Skip to content
Judgment Labs
Esc
↑↓navigate↵open⌘Jpreview
On this page

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.

Was this page helpful?