Open-source client SDKs for spaturzu β per-agent LLM cost attribution, budget enforcement, and cross-provider fallback. Wrap your existing provider client (OpenAI, Anthropic, Bedrock, Gemini, Mistral) and every call is metered, attributed to the agent that made it, and optionally budget-capped β without changing how you call the model.
Already calling OpenAI, Anthropic, Bedrock, Gemini, or Mistral? Change a single
import β from import OpenAI from "openai"
to
import OpenAI from "@spaturzu/sdk/openai"
. Construction and call sites stay exactly the same, and you can attribute each call to the agent that made it:
import OpenAI from "@spaturzu/sdk/openai";
// Swap one import β reads SPATURZU_API_KEY + OPENAI_API_KEY from env.
const openai = new OpenAI();
// Tag any call with the agent that made it β one line, no closure.
await openai.withAgent("support-triage").chat.completions.create({ /* β¦ */ });
That's the whole migration β no new objects, no wrappers around your call
sites. Python is identical: from spaturzu.openai import OpenAI
, then
client.with_agent("support-triage").chat.completions.create(...)
. The same
one-import swap works for every provider β @spaturzu/sdk/anthropic
,
/bedrock
, /google
, /mistral
(Python: spaturzu.anthropic
, and so on).
Running multi-step workflows? Group several calls under one agent with
run()
instead β see[What you can do]below.
| SDK | Package | Docs |
|---|---|---|
| TypeScript / Node | ||
@spaturzu/sdk |
READMEPythonspaturzu
READMEOpenClaw plugin* experimental*@spaturzu/openclaw
β οΈ and not yet ready for production use. APIs may change without notice.@spaturzu/openclaw
is a work in progress
Both the TypeScript and Python SDKs treat the underlying provider clients as optional dependencies β install only the ones you actually call.
Python β published on PyPI as spaturzu (Python 3.10+):
pip install spaturzu # core
pip install "spaturzu[openai]" # with the OpenAI integration
pip install "spaturzu[all]" # every provider integration
TypeScript / Node β published on npm as @spaturzu/sdk (ESM-only):
npm install @spaturzu/sdk
npm install openai @anthropic-ai/sdk @aws-sdk/client-bedrock-runtime @google/genai @mistralai/mistralai
Once installed, every import in this README works as written. pnpm
/ yarn
accept the same package name (pnpm add @spaturzu/sdk
).
Full docs & guides:https://spaturzu.superchiu.org/docs** TypeScript / Node API:**typescript/README.md
Python API:python/README.md
OpenClaw plugin(experimental):openclaw/README.md
For AI tools / LLMs:https://spaturzu.superchiu.org/llms.txt
The examples below all build on this one-time setup. Every later snippet
reuses spaturzu
/sp
, openai
, and messages
from here.
// TypeScript
import { Spaturzu } from "@spaturzu/sdk";
import OpenAI from "openai";
const spaturzu = new Spaturzu({ apiKey: process.env.SPATURZU_API_KEY });
const openai = spaturzu.wrapOpenAI(new OpenAI());
const messages = [{ role: "user", content: "Summarize the latest sales report." }];
python
import os
from spaturzu import spaturzu
from openai import OpenAI
sp = spaturzu(api_key=os.environ["SPATURZU_API_KEY"])
openai = sp.wrap_openai(OpenAI())
messages = [{"role": "user", "content": "Summarize the latest sales report."}]
Wrapping is transparent: the wrapped client has the
same methods and return typesas the original. You keep calling the provider exactly as before β spaturzu just meters each call in the background.
Wrap a block of work in run("name", β¦)
and every model call inside it is billed to that agent β so the dashboard shows cost per agent, not one undifferentiated total.
// TypeScript
await spaturzu.run("researcher", async () => {
await openai.chat.completions.create({ model: "gpt-4o", messages });
});
with sp.run("researcher"):
openai.chat.completions.create(model="gpt-4o", messages=messages)
Nested run()
calls share one run id and extend the agent path, so a
multi-step workflow shows up as a tree (research βΊ synthesize
).
// TypeScript
await spaturzu.run("research", async () => {
await openai.chat.completions.create({ model: "gpt-4o", messages }); // path: research
await spaturzu.run("synthesize", async () => {
await openai.chat.completions.create({ model: "gpt-4o", messages }); // path: research βΊ synthesize
});
});
with sp.run("research"):
openai.chat.completions.create(model="gpt-4o", messages=messages) # path: research
with sp.run("synthesize"):
openai.chat.completions.create(model="gpt-4o", messages=messages) # path: research βΊ synthesize
Set tags globally on the client, or per-frame on a run()
. Frame tags merge with the global ones (inner wins on conflict), so you can break spend down by any dimension you like.
// TypeScript
const spaturzu = new Spaturzu({
apiKey: process.env.SPATURZU_API_KEY,
tags: { env: "prod", team: "growth" }, // on every call
});
await spaturzu.run("billing-agent", { tags: { customer: "acme" } }, async () => {
await openai.chat.completions.create({ model: "gpt-4o", messages });
});
sp = spaturzu(
api_key=os.environ["SPATURZU_API_KEY"],
tags={"env": "prod", "team": "growth"}, # on every call
)
with sp.run("billing-agent", tags={"customer": "acme"}):
openai.chat.completions.create(model="gpt-4o", messages=messages)
When an agent's budget is exhausted, the wrapped call raises
BudgetExceededError
before it reaches the provider β so a refused call
costs nothing. (Use onBreach: "warn"
/ "on_breach": "warn"
to log and proceed instead of throwing.)
// TypeScript
import { BudgetExceededError } from "@spaturzu/sdk";
const capped = spaturzu.wrapOpenAI(new OpenAI(), {
budget: { hardCap: true, onBreach: "throw" },
});
try {
await capped.chat.completions.create({ model: "gpt-4o", messages });
} catch (err) {
if (err instanceof BudgetExceededError) {
// budget hit β the request never left your process, so no tokens were spent
}
}
python
from spaturzu import BudgetExceededError
capped = sp.wrap_openai(OpenAI(), budget={"hard_cap": True, "on_breach": "throw"})
try:
capped.chat.completions.create(model="gpt-4o", messages=messages)
except BudgetExceededError:
pass # call never reached OpenAI β no spend
Give a wrap a fallback chain. On a retryable error (429 / 5xx / connection), spaturzu transparently retries the next provider β and translates the response back to your primary provider's shape, so your code is unchanged.
// TypeScript
import Anthropic from "@anthropic-ai/sdk";
const resilient = spaturzu.wrapOpenAI(new OpenAI(), {
fallback: [
{ provider: "anthropic", client: new Anthropic(), model: "claude-3-5-haiku-20241022" },
],
});
// If OpenAI is down, this is served by Anthropic β still returns an OpenAI-shaped response.
const r = await resilient.chat.completions.create({ model: "gpt-4o", messages });
python
from anthropic import Anthropic
resilient = sp.wrap_openai(OpenAI(), fallback=[
{"provider": "anthropic", "client": Anthropic(), "model": "claude-3-5-haiku-20241022"},
])
r = resilient.chat.completions.create(model="gpt-4o", messages=messages)
All 20 directional provider pairs are supported. v1 fallback is non-streaming, text-only (no tools /
response_format
).
The same five providers, the same shape, in both languages. Streaming and sync/async calls are metered automatically β no extra configuration.
| Provider | TypeScript | Python |
|---|---|---|
| OpenAI (+ OpenAI-compatible) | wrapOpenAI |
|
wrap_openai |
||
| Anthropic | wrapAnthropic |
|
wrap_anthropic |
||
| Amazon Bedrock | wrapBedrock |
|
wrap_bedrock |
||
| Google Gemini | wrapGemini |
|
wrap_gemini |
||
| Mistral | wrapMistral |
|
wrap_mistral |
Short-lived processes(CLIs, serverless): callspaturzu.flush()
/sp.flush()
before exit so queued metering rows are sent.
For the complete API β every option, streaming details, and per-provider notes β see the TypeScript and Python READMEs, or the full docs at ** https://spaturzu.superchiu.org/docs**.
sdks/
βββ typescript/ @spaturzu/sdk β Node/TS SDK (5 providers, 20 fallback pairs)
βββ python/ spaturzu β Python SDK (parity with the TS surface)
βββ openclaw/ @spaturzu/openclaw β OpenClaw metering/budget plugin (WIP)
TypeScript packages (managed as a pnpm workspace):
pnpm install
pnpm build # build all packages
pnpm test # run all test suites
pnpm typecheck
Python SDK:
cd python
python3 -m venv .venv
.venv/bin/pip install -e ".[dev,all]"
.venv/bin/pytest
MIT Β© Superchiu Ltd
spaturzu is a product of Superchiu Ltd.