Trace the Vercel AI SDK
Trace Vercel AI SDK calls, steps and tool executions in TypeScript, on AI SDK 6 or 7.
The AI SDK already emits OpenTelemetry spans. You hand it Judgment’s tracer with Tracer.getOTELTracer(), and Judgment maps model, tokens, input and output from both the AI SDK 6 and 7 span formats. How you hand over the tracer depends on the major version of ai.
AI SDK 7: register once
AI SDK 7 registers telemetry globally with registerTelemetry and the OpenTelemetry integration from @ai-sdk/otel. Do it once at startup, after Tracer.init.
npm install judgeval ai@^7 @ai-sdk/openai@^4 @ai-sdk/otel zod
import { OpenTelemetry } from "@ai-sdk/otel";
import { registerTelemetry } from "ai";
import { Tracer } from "judgeval";
await Tracer.init({ projectName: "lunch-order-agent" });
registerTelemetry(new OpenTelemetry({ tracer: Tracer.getOTELTracer() }));
import "./instrumentation";
import { openai } from "@ai-sdk/openai";
import { generateText, stepCountIs, tool } from "ai";
import { Tracer } from "judgeval";
import { z } from "zod";
const result = await generateText({
model: openai("gpt-5.2"),
tools: {
check_delivery_eta: tool({
description: "Get the delivery ETA for a restaurant",
inputSchema: z.object({ restaurant: z.string() }),
execute: async ({ restaurant }) => ({ restaurant, eta: "12:15 PM" }),
}),
},
stopWhen: stepCountIs(5),
prompt: "When would Olive & Thyme deliver lunch for 30 people?",
});
console.log(result.text);
await Tracer.shutdown();
AI SDK 6: pass the tracer on each call
AI SDK 6 has no global registration. Turn on experimental_telemetry on every call you want traced.
npm install judgeval ai@^6 @ai-sdk/openai@^3
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";
import { Tracer } from "judgeval";
await Tracer.init({ projectName: "lunch-order-agent" });
const { text } = await generateText({
model: openai("gpt-5.2"),
prompt: "order me mediterranean food to feed 30 hungry engineers",
experimental_telemetry: { isEnabled: true, tracer: Tracer.getOTELTracer() },
});
console.log(text);
await Tracer.shutdown();
Group calls into one trace
Each generateText call is its own root span unless something wraps it. To get one trace per user request, wrap the handler in Tracer.observe:
import { Tracer } from "judgeval";
const handleRequest = Tracer.observe(
async function handleRequest(message: string) {
// call generateText / streamText here
return message;
},
{ spanType: "agent" },
);
Short-lived scripts and servers
await Tracer.shutdown() flushes pending spans and then shuts the tracer down, so call it once at the end of a script or in your server’s shutdown hook. A long-running server exports in the background and doesn’t need it per request. To flush without shutting down (for example at the end of a serverless handler), use await Tracer.forceFlush().
For OpenRouter as the model provider, turn on OpenRouter’s usage accounting so cost shows up on the spans.