TypeScript SDK
The @ultrarouter/sdk client — OpenAI-shaped, with the ur.* extensions.
@ultrarouter/sdk mirrors the openai v5 surface and adds the ultrarouter
extensions. It is fetch-based (Node ≥ 20 / Bun / Deno / edge), ESM + CJS, with a
core entry under 15 kB min+gz.
@ultrarouter/sdk is not on the npm registry. Clone the public feat/learning-loop branch for the learning
preview (0.1.0), build its tarball, and install that file. The default main branch does not carry
this preview. Exact current artifact names are in /setup-recipes.json;
<version> below is the version of the package you build.
git clone --branch feat/learning-loop --single-branch https://github.com/lucastonon/ultrarouter-sdk-typescript ../ultrarouter-sdk-typescript
(cd ../ultrarouter-sdk-typescript && npm ci && npm run build && npm pack)
npm install ../ultrarouter-sdk-typescript/ultrarouter-sdk-<version>.tgzQuickstart
import UltraRouter from "@ultrarouter/sdk";
const ur = new UltraRouter({
apiKey: process.env.UR_API_KEY, // or ULTRAROUTER_API_KEY
defaultModel: "anthropic/claude-sonnet-4-6",
defaults: {
router: "off",
compression: "semantic_safe",
provider: { sort: "price" },
},
});
const res = await ur.chat.completions.create({
model: "openai/gpt-5-mini", // per-call override of defaultModel
messages: [{ role: "user", content: "hi" }],
call_type: "support-reply-draft",
router: "auto",
compression: { mode: "auto", no_compress_fields: ["messages.1.content"] },
models: ["openai/gpt-5"], // fallbacks
});
console.log(res.choices[0].message.content, res.ur.cost_usd);Init defaults are overridable per call. Every ur extension is typed.
Streaming
const stream = await ur.chat.completions.create({
messages: [{ role: "user", content: "stream please" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
if (chunk.ur) console.log("\n", chunk.ur.request_id, chunk.ur.cost_usd);
}The ur.* extensions
const emb = await ur.embeddings.create({ model: "openai/text-embedding-3-small", input: ["a", "b"] });
const models = await ur.models.list({ capability: "vision" });
const cts = await ur.ur.callTypes.list();
await ur.ur.requests.feedback(res.ur.request_id, { rating: 1, tags: ["great"] });
const stats = await ur.ur.generation.get(res.ur.request_id);Drop-in for openai
asOpenAI() returns an OpenAI-client preset (base URL + key). openai is not a
dependency of the SDK — pass the constructor to get a live instance:
import OpenAI from "openai";
const client = ur.asOpenAI(OpenAI); // new OpenAI({ baseURL: "<gw>/v1", apiKey })Retries, timeouts, idempotency
Retries 429 / 5xx / transport errors with jittered backoff honoring
Retry-After (maxRetries, default 2). A total timeout and per-call
AbortSignal are honored. Non-streaming POSTs carry a stable auto
Idempotency-Key so a retried mutation replays instead of double-executing. Errors
are UltraRouterError (.code, .status, .requestId, .retryable,
.providerCode).
The SDK's source is the public repository lucastonon/ultrarouter-sdk-typescript. Until the package is published to npm, install the tarball built from that repository, as shown at the top of this page.
CI quality gate — the ur bench CLI
The @ultrarouter/sdk package ships an ur bin that gates a CI build on a Bench
baseline compare: it captures bench-tagged traffic, freezes the suite, re-runs your
current prompt/pin/config as the candidate, and compares it against a pinned baseline
under the interval-based decision contract — quality non-inferiority and cost-savings
intervals must both clear their bars for a pass; a regression, a hard-scorer break, or an
absolute per-task cost-ceiling breach is a fail; missing paired evidence is inconclusive
(never silently green).
ur bench run checkout-agent --capture "pnpm test:agent" \
--budget 3 --gate --baseline bench:main --json
# exit 0 = pass · exit 2 = fail / inconclusive · fails closed on any API errorA published GitHub Action wraps the CLI (inputs: suite, api-key, baseline,
budget, capture, cost-ceiling, allow-inconclusive, pin-baseline) — see
action.yml and docs/github-action.md in
lucastonon/ultrarouter-sdk-typescript
(uses: lucastonon/ultrarouter-sdk-typescript@v0.0.1). The routes it drives (POST /v1/bench/runs/:id/baseline, GET /v1/bench/runs/:id/gate) are in the API reference.
Model price comparison — what each model costs on your own traffic
For the models your workspace may use, see the net-effective price per 1M tokens, a projected monthly cost from your own recent volume, and what we actually know about each model's quality — with honest unknowns.
Python SDK
The ultrarouter Python client — sync + async, pydantic-typed.