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

@spaturzu/sdk

v0.1.7

Published

Per-agent LLM cost attribution + budget enforcement + cross-provider fallback for Node.js. Wraps your provider client (OpenAI, Anthropic, Bedrock, Gemini, Mistral) and emits a metering row to the spaturzu gateway on every call, with frame-based agent attr

Readme

@spaturzu/sdk

Per-agent LLM cost attribution + budget enforcement + cross-provider fallback for Node.js. Wraps your provider client (OpenAI, Anthropic, Bedrock, Gemini, Mistral) and emits a metering row to the spaturzu gateway on every call, with frame-based agent attribution and free-form tags.

Part of spaturzu — full docs at https://spaturzu.superchiu.org/docs.

# Published on npm as @spaturzu/sdk (ESM-only).
npm install @spaturzu/sdk

# Plus whichever provider clients you use (normal npm packages):
npm install openai @anthropic-ai/sdk @aws-sdk/client-bedrock-runtime @google/genai @mistralai/mistralai

The provider clients are optional peer dependencies — install only what you use. pnpm / yarn work the same (pnpm add @spaturzu/sdk); the imports below are unchanged.

Quickstart

import { Spaturzu } from "@spaturzu/sdk";
import OpenAI from "openai";

const spaturzu = new Spaturzu({
  baseURL: process.env.SPATURZU_BASE_URL,
  apiKey: process.env.SPATURZU_API_KEY,
  tags: { env: "prod", region: "us-east-1" }, // applied to every call
});

const openai = spaturzu.wrapOpenAI(new OpenAI());

await spaturzu.run("researcher", async () => {
  const r = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [{ role: "user", content: "Hello" }],
  });
});

// Short-lived processes (CLIs, lambdas) — flush before exit:
await spaturzu.flush();

Drop-in (one-line) instrumentation

Change only the import specifier — construction and call sites stay the same:

- import OpenAI from "openai";
+ import OpenAI from "@spaturzu/sdk/openai";
  const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
  await openai.chat.completions.create({ model: "gpt-4o-mini", messages: [...] });

Spaturzu reads its own config from SPATURZU_API_KEY / SPATURZU_BASE_URL. Call configure({...}) once at startup (before constructing any client) for process-wide tags or an onError handler.

| Swap from | …to | Imported as | |---|---|---| | openai | @spaturzu/sdk/openai | import OpenAI from … | | @anthropic-ai/sdk | @spaturzu/sdk/anthropic | import Anthropic from … | | @aws-sdk/client-bedrock-runtime | @spaturzu/sdk/bedrock | import { BedrockRuntime } from … | | @google/genai | @spaturzu/sdk/google | import { GoogleGenAI } from … | | @mistralai/mistralai | @spaturzu/sdk/mistral | import { Mistral } from … |

Bedrock: the drop-in is BedrockRuntime (the aggregated client with converse / converseStream), not the low-level BedrockRuntimeClient. The Command form (client.send(new ConverseCommand(...))) is not instrumented.

Agent attribution without a closure

await openai.withAgent("writer").chat.completions.create({ ... });

.withAgent(name) tags that call (and nests under any enclosing run() as a sub-agent). For multi-call workflows, use the closure form:

import { run, flush } from "@spaturzu/sdk";
await run("workflow", async () => { await openai.chat.completions.create({ ... }); });
await flush();

Budget / fallback on the drop-in path

Pass an optional second constructor argument (ignored by the real SDK):

const openai = new OpenAI({ apiKey }, { budget: { hardCap: true }, fallback: [...] });

ESM-only, same as the main entry. The drop-in subpaths require the corresponding provider package to be installed (it's an optional peer dep).

Supported providers

| Wrap method | Client | Methods intercepted | |---|---|---| | wrapOpenAI(client) | openai | chat.completions.create | | wrapAnthropic(client) | @anthropic-ai/sdk | messages.create | | wrapBedrock(client) | @aws-sdk/client-bedrock-runtime | converse, converseStream | | wrapGemini(client) | @google/genai | models.generateContent, models.generateContentStream | | wrapMistral(client) | @mistralai/mistralai | chat.complete, chat.stream |

All wraps capture non-streaming + streaming usage, support the budget pre-call gate, and work as cross-provider fallback sources and targets.

Bedrock

// Use the aggregated `BedrockRuntime` client (it has the `converse` /
// `converseStream` methods). The low-level `BedrockRuntimeClient` uses the
// Command form (`client.send(...)`) and is not instrumented.
import { BedrockRuntime } from "@aws-sdk/client-bedrock-runtime";
const client = new BedrockRuntime({ region: "us-east-1" });
const wrapped = spaturzu.wrapBedrock(client);

await wrapped.converse({
  modelId: "anthropic.claude-3-5-sonnet-20241022-v2:0",
  messages: [{ role: "user", content: [{ text: "hello" }] }],
});

Targets the named-method form only. If you use the Command pattern (client.send(new ConverseCommand(...))), migrate to the named methods — the Command form is not instrumented in v1.

Gemini

import { GoogleGenAI } from "@google/genai";
const client = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
const wrapped = spaturzu.wrapGemini(client);

await wrapped.models.generateContent({
  model: "gemini-2.5-pro",
  contents: [{ role: "user", parts: [{ text: "hello" }] }],
});

Mistral

import { Mistral } from "@mistralai/mistralai";
const client = new Mistral({ apiKey: process.env.MISTRAL_API_KEY });
const wrapped = spaturzu.wrapMistral(client);

await wrapped.chat.complete({
  model: "mistral-large-latest",
  messages: [{ role: "user", content: "hello" }],
});

Note: Mistral exposes chat.complete and chat.stream as separate methods, not a stream: true flag.

Agent frames + tags

spaturzu.run(name, fn) opens an agent frame; nested calls share runId and extend agentPath. Tags merge with the parent frame's; the inner scope wins on key conflict.

await spaturzu.run("research", async () => {
  await openai.chat.completions.create({ ... });   // agentPath=["research"]

  await spaturzu.run("synthesize", { tags: { phase: "draft" } }, async () => {
    await anthropic.messages.create({ ... });      // agentPath=["research","synthesize"], tags.phase="draft"
  });
});

Budget enforcement (hard cap)

const openai = spaturzu.wrapOpenAI(new OpenAI(), {
  budget: { hardCap: true, onBreach: "throw" },   // 'warn' to log + proceed
});

When a configured hard-cap budget is breached, the wrap throws BudgetExceededError before hitting the upstream provider. No token cost is incurred for refused calls.

Cross-provider fallback

Declare a fallback chain to handle provider outages:

import Anthropic from "@anthropic-ai/sdk";
import { BedrockRuntime } from "@aws-sdk/client-bedrock-runtime";

const openai = spaturzu.wrapOpenAI(new OpenAI(), {
  fallback: [
    {
      provider: "anthropic",
      client: new Anthropic(),
      model: "claude-3-5-haiku-20241022",
    },
    {
      provider: "bedrock",
      client: new BedrockRuntime({ region: "us-east-1" }),
      model: "anthropic.claude-3-5-haiku-20241022-v1:0",
    },
  ],
});

On a retryable upstream error (429, 5xx, connection-class) the wrap walks the chain. Request/response shapes are translated automatically — your code keeps receiving OpenAI-shaped responses even when an Anthropic or Bedrock fallback served the call. All 20 directional pairs (5 providers × 4 other-providers) are supported.

v1 fallback limits: non-streaming, text content only, no tools, no response_format. Calls that use any of those quietly skip fallback and surface the original error.

API reference

new Spaturzu(opts)

| Option | Type | Default | |---|---|---| | baseURL | string | process.env.SPATURZU_BASE_URL ?? https://spaturzu-api.superchiu.org | | apiKey | string | process.env.SPATURZU_API_KEY | | timeoutMs | number | 10000 | | backoffMs | number[] | [1000, 2000, 4000, 8000, 16000] | | maxConcurrent | number | 50 | | onError | (err) => void | silent | | tags | Record<string, string \| number \| boolean> | — |

spaturzu.run(name, [opts,] fn)

Open an agent frame. opts.tags adds frame-scoped tags. Returns fn's result.

spaturzu.flush() / spaturzu.shutdown()

Block until queued log POSTs settle. shutdown also stops the BudgetGuard's SSE + polling threads.

Notes

  • The wraps don't import provider SDKs — they duck-type against runtime shapes, so any compatible client (OpenAI-compat proxies, vLLM, Together, Groq) works for wrapOpenAI.
  • Tokens come from the provider's usage field when present; otherwise the SDK estimates via tiktoken locally (rough for non-OpenAI tokenizers — rows are flagged usageSource: 'tiktoken').
  • Streaming captures usage from the final chunk for each provider (OpenAI's include_usage, Anthropic's message_delta, Bedrock's metadata, Gemini's last usageMetadata, Mistral's last data.usage).
  • After a fallback target serves a call, the response is in the primary provider's shape (translated). Use the property/key access matching the primary, not the fallback target.