@mv37/rollout
v0.1.0
Published
Rollout TypeScript observability SDK
Readme
@mv37/rollout
TypeScript SDK for Rollout.
Install
pnpm add @mv37/rolloutRequires Node 20+. The base install stays lightweight and pulls in no provider SDKs.
Provider SDKs are optional peers. Install them in the app or example environment that needs them:
pnpm add @mv37/rollout openaiBasic Usage
import { Rollout } from "@mv37/rollout";
const rollout = new Rollout({
apiKey: process.env.ROLLOUT_API_KEY,
agentName: "support_agent",
environment: "production",
});
await rollout.trace("support_agent", async (trace) => {
trace.message({ role: "user", content: "Where is my order?" });
await trace.span("llm", async (span) => {
span.recordInput({ messages: [{ role: "user", content: "Where is my order?" }] });
span.recordOutput({ content: "Your order has shipped." });
span.setUsage({ input_tokens: 120, output_tokens: 24 });
}, {
name: "model.call",
model: "gpt-4.1-mini",
provider: "openai",
});
trace.feedback("thumbs_up", true);
});
await rollout.shutdown();Module-Level Convenience
import * as rollout from "@mv37/rollout";
rollout.init({
apiKey: process.env.ROLLOUT_API_KEY,
agentName: "support_agent",
});
const runAgent = rollout.agent("support_agent", async (message: string) => {
return `Echo: ${message}`;
});
await runAgent("hello");
await rollout.shutdown();The client object is the primary API. Module-level helpers route through the client created by
rollout.init().
Vercel AI SDK
Install the optional peer in server-side apps that use the AI SDK:
pnpm add @mv37/rollout aiWrap the AI SDK module explicitly. This does not monkeypatch globals and only affects calls made through the returned object.
import * as ai from "ai";
import { Rollout } from "@mv37/rollout";
import { wrapAISDK, eventMetadata } from "@mv37/rollout/ai-sdk";
const rollout = new Rollout({ apiKey: process.env.ROLLOUT_API_KEY });
const wrappedAI = wrapAISDK(ai, {
client: rollout,
context: {
agentName: "support_agent",
userId: "user_123",
conversationId: "chat_123",
},
});
const result = await wrappedAI.generateText({
model,
prompt: "Help the user",
experimental_telemetry: {
metadata: eventMetadata({
userId: "user_123",
conversationId: "chat_123",
externalTraceId: "message_123",
agentName: "support_agent",
}),
},
});wrapAISDK currently instruments generateText, streamText, generateObject, and
streamObject. It creates an implicit trace when there is no active Rollout trace, or attaches
the LLM span to the active trace when one exists. Stream calls preserve the AI SDK result object and
record stream start/end, bounded previews, usage, finish reason, and tool callbacks exposed by the
AI SDK.
For useChat route handlers, derive stable metadata from the request body:
import * as ai from "ai";
import { convertToModelMessages } from "ai";
import { eventMetadataFromChatRequest, wrapAISDK } from "@mv37/rollout/ai-sdk";
export async function POST(req: Request) {
const body = await req.json();
const wrappedAI = wrapAISDK(ai, { client: rollout });
const result = wrappedAI.streamText({
model,
messages: convertToModelMessages(body.messages),
experimental_telemetry: {
metadata: eventMetadataFromChatRequest({
request: body,
userId: "user_123",
agentName: "support_agent",
}),
},
});
return result.toUIMessageStreamResponse();
}Use this integration only on the server. Do not expose Rollout workspace API keys in browser bundles.
Configuration
Constructor values override environment variables:
ROLLOUT_API_KEYROLLOUT_BASE_URLROLLOUT_ENVIRONMENTROLLOUT_RELEASEROLLOUT_SERVICE_NAMEROLLOUT_AGENT_NAMEROLLOUT_AGENT_IDROLLOUT_AGENT_VERSIONROLLOUT_DEPLOYMENTROLLOUT_SAMPLE_RATEROLLOUT_DEBUGROLLOUT_DISABLED
Useful local options:
const rollout = new Rollout({
apiKey: "rl_...",
syncMode: true,
debug: true,
beforeSend(event) {
return event.event_type === "debug.noise" ? null : event;
},
scrubber(event) {
return event;
},
});Scrubbers run before beforeSend.
Edge and Browser
Use @mv37/rollout/edge for request-scoped runtimes:
import { Rollout } from "@mv37/rollout/edge";
const rollout = new Rollout({ apiKey: process.env.ROLLOUT_API_KEY });
await rollout.trace("request", async () => {
// work
});
await rollout.flush();Edge uses a fallback stack context manager and does not promise arbitrary async context propagation.
@mv37/rollout/browser is disabled by default. Rollout workspace API keys must not be exposed in
browser bundles.
Diagnostics
const result = await rollout.check();
console.log(result.ok, result.message);check() sends a short completed diagnostic trace through POST /v1/events:batch.
Example
An OpenRouter example using the OpenAI JavaScript SDK lives at:
examples/openrouter-agent.tsRun it from the package directory:
cd packages/sdk-ts
ROLLOUT_BASE_URL=http://127.0.0.1:8080 \
ROLLOUT_API_KEY=... \
OPENROUTER_API_KEY=... \
OPENAI_MODEL=openai/gpt-4o-mini \
pnpm example:openrouterThe example records a user message, two manual llm spans around OpenRouter chat completions,
wrapped weather tool calls, assistant output, identity, and feedback.
A Vercel AI SDK example using @ai-sdk/openai-compatible with OpenRouter lives at:
examples/vercel-ai-sdk-agent.tsRun it from the package directory:
cd packages/sdk-ts
ROLLOUT_BASE_URL=http://127.0.0.1:8080 \
ROLLOUT_API_KEY=... \
OPENROUTER_API_KEY=... \
OPENAI_MODEL=openai/gpt-4o-mini \
pnpm example:ai-sdkDevelopment
From the repo root:
pnpm install
pnpm --dir packages/sdk-ts lint
pnpm --dir packages/sdk-ts typecheck
pnpm --dir packages/sdk-ts test
pnpm --dir packages/sdk-ts buildOr run the package check:
pnpm --dir packages/sdk-ts check