TypeScript SDK

Vercel AI SDK

wrapAISDK instruments the Vercel AI SDK explicitly: it wraps the module you pass in and touches nothing else. Calls create an implicit trace when there is no active one, or attach the LLM span to the active trace.

Install the peer

shell
pnpm add @mv37/rollout ai

Wrap the AI SDK

Wrap the AI SDK module explicitly. This does not monkeypatch globals — only calls made through the returned object are instrumented. Pass stable identity through experimental_telemetry.metadata with eventMetadata:

ai-sdk.ts
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",    }),  },});

What it instruments

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 any tool callbacks the AI SDK exposes.

useChat route handlers

For useChat route handlers, derive stable metadata from the request body with eventMetadataFromChatRequest:

app/api/chat/route.ts
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();}

Server only

Heads up

Use this integration only on the server. Do not expose Rollout workspace API keys in browser bundles.