npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thinkyou0714/fugu

v0.2.1

Published

Zero-dependency TypeScript client + CLI for the Sakana Fugu OpenAI-compatible API (Responses + Chat Completions).

Readme

@thinkyou0714/fugu

npm CI license: MIT

Zero-dependency TypeScript client + CLI for the Sakana Fugu OpenAI-compatible API.

Fugu is Sakana AI's multi-agent orchestration system exposed as a single model behind one OpenAI-compatible endpoint: you send one request and Fugu decides internally whether to answer directly or to delegate to and synthesize a team of expert frontier models.

Status: unit-tested offline (mocked fetch) + e2e against a local socket stub. A live call against api.sakana.ai needs a real SAKANA_API_KEY — supply one and run npm run smoke to confirm end-to-end.

Highlights

  • Zero runtime dependencies. Built-in fetch; ESM-only; Node >= 22.9.
  • Typed error hierarchy (FuguAuthError, FuguRateLimitError, FuguTimeoutError, …) with code / status / requestId / retryAfterMs / isRetryable.
  • Secret-safe: the raw response body is never stored on errors or logged; messages and --json output are redacted (Bearer … / sk-… / deny-listed keys).
  • Typed usage + cost, including Fugu's hidden, billed orchestration tokens.
  • Effort-scaled timeouts (reasoning.efforthigh | xhigh | max) and status / incomplete / finishReason surfaced (no silent empty strings).
  • Resilient transport: retries with exponential backoff + jitter honoring Retry-After, a stable Idempotency-Key across retries, timeout/abort/network classification.
  • Streaming (respondStream / chatStream) over SSE — zero-dep.
  • Cost controls: a BudgetGuard spend circuit-breaker, output-token + input-size caps, chooseModel() routing (fugufugu-ultra), and an opt-in request cache (MemoryCache, LRU+TTL) — identical calls skip the network and the budget charge.
  • Strategy patterns: a confidence-gated Cascade (cheap model → judge → escalate), an eval harness (runEval + neutral llmGrader) to measure quality/cost/latency, and concurrency primitives (WorkPool with priority lanes, SingleFlight de-dup) for bulk runs.
  • Tool calling (tools + runTools agentic loop, built-in web_search), structured output (respondJson with validate-and-repair), stateful Conversation chaining, and observability hooks (onRequest / onResponse / logger — wire pino/OpenTelemetry; the core stays dependency-free).
  • Ecosystem: a multi-provider FuguRouter (failover) and an OpenAI-compatible proxy (createProxyServer / fugu-proxy bin) so Cursor / n8n / any OpenAI-SDK tool can target Fugu — with failover — at a localhost endpoint; a Fugu MCP server (integrations/mcp/, fugu_respond / fugu_chat) for Claude Code / Cursor / Codex; a zero-dep fugu-obsidian CLI (integrations/obsidian/) that answers questions about your Obsidian notes via the Local REST API; an n8n community node (integrations/n8n/) — a declarative Fugu node + Fugu API credential; and a Claude Code /fugu skill + fugu subagent (.claude/, mirrored as a Cursor command) that routes "second opinion" / adversarial-review asks to the MCP server.

Install

npm install @thinkyou0714/fugu        # core (zero deps)
npm install @thinkyou0714/fugu openai # optional: the ./openai adapter

CLI

export SAKANA_API_KEY=...    # from https://console.sakana.ai/get-started
npx fugu "Explain Sakana Fugu in one sentence." --usage
npx fugu "Refactor this..." --model fugu-ultra --effort high
echo "summarize this" | npx fugu --chat
npx fugu --help

--usage prints token usage (incl. orchestration) + estimated cost to stderr; --json prints the (redacted) raw response.

Verify your setup (live)

Once you have a key, confirm a real round-trip works:

export SAKANA_API_KEY=...    # or: cp .env.example .env && edit
npm run smoke                # one minimal call to api.sakana.ai

It prints a PASS/FAIL banner with latency + token usage. On failure it maps the error to a concrete fix (401 → re-copy the key, 403 → plan/model access, 429 → wait, connection/parse → check SAKANA_BASE_URL, timeout → raise/retry). Exit codes: 0 pass, 1 reached the API but failed, 2 not configured (no key) — so CI can skip cleanly.

Troubleshooting

npm run smoke and the CLI map every typed error to a concrete fix. The same diagnosis applies in code — branch on err.code, or use the exported type guards (isAuthError, isRetryable, …):

| Error (code / status) | Likely cause | Fix | |---|---|---| | auth (401) | key missing / invalid / expired | re-copy SAKANA_API_KEY from the console | | permission (403) | plan or model not allowed | check tier + model access (fugu-ultra may need a higher plan) | | rate_limit (429) | too many requests | wait retryAfterMs, lower concurrency | | connection / parse | wrong base URL / non-Fugu endpoint | verify SAKANA_BASE_URL (default https://api.sakana.ai/v1) | | timeout | slow run or wrong host | raise the timeout / retry; instant timeouts ⇒ check the host | | bad_request (400/404/422) | bad model id or params | check the model (fugu / fugu-ultra) and request body |

Programmatic

import { createClient, loadConfig, FuguRateLimitError } from "@thinkyou0714/fugu";

const client = createClient(loadConfig());
try {
  const r = await client.respond("Give me a haiku about pufferfish.", { reasoningEffort: "high" });
  console.log(r.text);
  console.log(r.usage, r.costUsd); // typed usage + estimated cost
} catch (e) {
  if (e instanceof FuguRateLimitError) await sleep(e.retryAfterMs ?? 1000);
}

Streaming + budget + routing

import { createClient, loadConfig, BudgetGuard, chooseModel } from "@thinkyou0714/fugu";

const client = createClient(loadConfig(), { budget: new BudgetGuard({ limitUsd: 5 }) });
const model = chooseModel({ chars: prompt.length, task: "code" }); // fugu ↔ fugu-ultra

for await (const ev of client.respondStream(prompt, { model })) {
  if (ev.type === "delta") process.stdout.write(ev.textDelta ?? "");
  else console.log("\n", ev.result?.costUsd, ev.result?.usage);
}

Tools, structured output, observability

import { createClient, loadConfig, functionTool, webSearchTool } from "@thinkyou0714/fugu";

const client = createClient(loadConfig(), { onResponse: (e) => metrics.record(e) });

// agentic tool loop
const res = await client.runTools([{ role: "user", content: "weather in Tokyo?" }], {
  tools: [functionTool("getWeather", { parameters: { type: "object", properties: { city: { type: "string" } } } }), webSearchTool()],
  handlers: { getWeather: async (args) => fetchWeather((args as { city: string }).city) },
});

// structured output with validate-and-repair
const { data } = await client.respondJson<{ score: number }>("Rate this 1-10", {
  schema: { type: "object", properties: { score: { type: "number" } }, required: ["score"] },
  validate: (v) => {
    const o = v as { score?: unknown };
    if (typeof o.score !== "number") throw new Error("score must be a number");
    return o as { score: number };
  },
});

Cache, confidence cascade & evals

import { createClient, loadConfig, MemoryCache, Cascade, llmJudge, runEval, llmGrader } from "@thinkyou0714/fugu";

// opt-in cache: identical requests are free (no network, no budget charge)
const cache = new MemoryCache({ maxEntries: 1000, ttlMs: 60 * 60_000 });
const client = createClient(loadConfig(), { cache });

// confidence cascade: try fugu, escalate to fugu-ultra only when the judge isn't sure
const cascade = new Cascade(client, {
  stages: [{ model: "fugu" }, { model: "fugu-ultra", effort: "high" }],
  judge: llmJudge(client, { threshold: 0.7 }), // or the zero-cost default `statusJudge`
});
const { result, stageIndex, escalations } = await cascade.run("A hard question…");

// evals: measure quality/cost/latency over a golden set (neutral judge ≠ system under test)
const report = await runEval(client, goldenSet, { grader: llmGrader(judgeClient), concurrency: 4 });
console.log(report.passRate, report.totalCostUsd, report.avgLatencyMs);

Router + proxy (use Fugu from any OpenAI-SDK tool, with failover)

import { FuguClient, FuguRouter, createProxyServer, loadConfig } from "@thinkyou0714/fugu";

const router = new FuguRouter({
  providers: [
    { name: "fugu", client: new FuguClient(loadConfig()), model: "fugu-ultra" },
    { name: "backup", client: new FuguClient({ ...loadConfig(), baseUrl: "https://backup/v1" }) },
  ],
});

// one localhost OpenAI endpoint any tool (Cursor, n8n, scripts) can target:
createProxyServer({ backend: router, token: "local-secret" }).listen(4141);
// or just run the bin:  npx fugu-proxy   ->   http://localhost:4141/v1

Optional OpenAI-SDK adapter

import { createFuguOpenAI } from "@thinkyou0714/fugu/openai"; // requires `openai` installed
const openai = await createFuguOpenAI();
const res = await openai.responses.create({ model: "fugu-ultra", input: "hi" });

Develop

Source runs directly via node --experimental-strip-types — no build needed for dev/tests.

npm test            # offline (mocked fetch) + real timeout wiring
npm run smoke       # live: one real round-trip to api.sakana.ai (needs SAKANA_API_KEY)
npm run coverage    # tests + coverage thresholds
npm run typecheck   # tsc --noEmit (erasableSyntaxOnly)
npm run lint        # biome
npm run build       # tsdown -> dist (ESM + .d.ts)
npm run check:exports  # build + publint + are-the-types-wrong (esm-only)

Layout

fugu/
├── src/
│   ├── index.ts        # public API barrel (the supported entry point)
│   ├── config.ts       # env loading, defaults, effort-scaled timeout
│   ├── errors.ts       # typed FuguError hierarchy + HTTP→error mapping
│   ├── redact.ts       # secret redaction
│   ├── types.ts        # FuguResult / FuguUsage + tolerant parsers
│   ├── pricing.ts      # price table + cost estimation
│   ├── fugu-client.ts  # FuguClient: respond() / chat() / *Stream()
│   ├── retry.ts        # backoff + jitter + Retry-After
│   ├── budget.ts       # BudgetGuard spend circuit-breaker
│   ├── routing.ts      # chooseModel() policy
│   ├── stream.ts       # SSE parsing
│   ├── tools.ts        # tool-calling types + parsing
│   ├── json.ts         # loose JSON extraction (structured output)
│   ├── observe.ts      # logging / metrics hooks
│   ├── conversation.ts # stateful Responses chaining
│   ├── cache.ts        # request cache (MemoryCache LRU+TTL; RequestCache)
│   ├── pool.ts         # WorkPool (bounded concurrency) + SingleFlight
│   ├── cascade.ts      # confidence-gated model cascade + judges
│   ├── evals.ts        # golden-set eval harness + graders
│   ├── router.ts       # multi-provider failover (FuguRouter)
│   ├── proxy.ts        # OpenAI-compatible proxy (bin: fugu-proxy)
│   ├── cli.ts          # CLI (bin: fugu)
│   └── openai.ts       # optional ./openai adapter
├── test/               # client / timeout / p2-p5 / mcp / obsidian / strategy tests
├── integrations/
│   ├── mcp/            # Fugu MCP server (own package; @modelcontextprotocol/sdk + zod)
│   ├── obsidian/       # fugu-obsidian CLI (own package; zero-dep, Local REST API)
│   └── n8n/            # n8n-nodes-fugu (own package; declarative node + credential)
├── .claude/           # /fugu skill + fugu subagent (delegate to the MCP server)
├── .cursor/           # mirrored Cursor command
├── .github/workflows/  # ci / release (changesets + npm OIDC) / codeql (templates)
└── tsdown.config.ts · biome.json · .changeset · tsconfig.json

Publishing

Releases use Changesets + npm Trusted Publishing (OIDC, no long-lived token, automatic provenance). Add a changeset per user-facing change with npm run changeset. See .github/workflows/release.yml.

API reference (as of 2026-06)

Compiled from Sakana's site/console and public guides (see Sources); not verified against a live call in this repo — confirm against your console dashboard.

| Item | Value | |-----------|-------------------------------------------------------------------| | Base URL | https://api.sakana.ai/v1 (copy the exact value from your console) | | Models | fugu (fast), fugu-ultra (max quality) | | Auth | Authorization: Bearer $SAKANA_API_KEY | | Endpoints | /responses (recommended), /chat/completions, /models | | Effort | reasoning.efforthigh / xhigh / max |

Sources: Sakana Fugu · console · Apidog guide