orbitrage
v0.6.1
Published
One-line observability + intelligent LLM routing for Node.js / TypeScript agents.
Downloads
338
Maintainers
Readme
orbitrage
One LLM gateway. Router + observability. One line.
Orbitrage is the proxy between your code and the model providers. Every
request flows through it — so it sees the model you asked for, the model it
routed to, the input messages, the output, tokens, cost, and latency.
Pointing your OpenAI / Anthropic SDK at https://api.orbitrage.ai/v1 is
the entire integration; this package is a 5-line convenience wrapper that
does it for you and tags every call with a trace + user id so the dashboard
groups them properly.
import { orbitrage } from "orbitrage";
import OpenAI from "openai";
await orbitrage.init({ apiKey: "orb_xxx_yyy" }); // 1 line of setup
//
const client = new OpenAI(); // 2 lines of usage —
// the OpenAI client auto-
// points at the Orbitrage
// gateway and adds trace
// headers to every request.
await client.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: "hi" }],
});Open https://app.orbitrage.ai/workflows — every call shows up with model,
tokens, cost, latency, and the full input/output.
Install
npm install orbitrageZero runtime dependencies. openai and @anthropic-ai/sdk are optional
peers — install whichever clients you actually use.
What init() does
- Generates a stable trace id for this process. Every request carries
it as
x-orbitrage-run-id, so the dashboard groups all your agent's LLM calls into a single run. - Patches the
OpenAIandAnthropicclass constructors to defaultbaseURLtohttps://api.orbitrage.ai/v1and add the trace headers viadefaultHeaders. If you already passbaseURLorapiKeyexplicitly, your value wins. - Sets
OPENAI_BASE_URLas a safety net for code that constructs the client without any args.
That's all. No background timers, no span processors, no OTLP exports. The gateway sees every byte of the request and writes the routing decision, upstream response, tokens, cost, and latency directly to your project's data store. The proxy is the single source of truth.
Per-end-user graphs
If you're a B2B service handling traffic for many end-users (your
customers' users), pass userId so the dashboard can partition every
call inside one workflow:
await orbitrage.init({
apiKey: process.env.ORBITRAGE_API_KEY,
userId: currentUser.id, // optional — your customer's user
});Every subsequent LLM call is tagged with x-orbitrage-end-user-id. The
dashboard uses it to build per-user flow graphs, cost breakdowns, and
churn signals.
For long-running servers that switch end-users between requests, call
orbitrage.setUser(userId) at the start of each request. The next
OpenAI or Anthropic instance you construct picks up the new id.
Bring your own provider key (BYOK)
Save your OpenAI / Anthropic / Google / Groq key on the
Models page. For models that match
that provider, Orbitrage forwards the request to the provider with
your key — your account is billed, our pooled credits are untouched.
Routing decisions still appear in your dashboard with byok=true so you
can see the split.
Forcing a specific model
Pass the model id verbatim — Orbitrage routes by explicit pin when the caller names a model:
await client.chat.completions.create({
model: "claude-sonnet-4-6", // explicit pin, no scoring
messages: [...],
});To let the router pick the cheapest model that meets the prompt's
difficulty, pass the alias "auto" (or any of "router", "default",
"orbitrage").
Backward compatibility
Decorators + lifecycle from v0.4 are kept as no-op shims so existing code compiles without changes:
import { workflow, task, flush, shutdown } from "orbitrage";
const planner = workflow("planner")(originalPlannerFn);
const run = task("run")(originalRunFn);
await flush(); // no-op — the gateway persists synchronously
await shutdown(); // no-opThe router captures the same data regardless of decorator markup; the decorators exist so v0.4 user code keeps importing.
How the workflow is determined
Every API key is minted for one workflow from the dashboard. The workflow
your calls land under is whichever workflow your key belongs to — no
appName argument required.
License
Apache-2.0
