Vercel AI SDK

generateText, streamText, generateObject, and tool calls capture automatically on v7, or with experimental_telemetry on v5/v6.

Every ai call inside wrap your agent becomes a span, model calls as llm, tool executions as tool.

How the AI SDK reports telemetry changed in v7, so which setup you need depends on your version:

AI SDKWhat you do
v7+Nothing, on trodo-node 2.23.4 or later. registerOTel() registers Trodo's telemetry integration for you, including under ESM and Next.js.
v5 / v6Pass experimental_telemetry: { isEnabled: true } per call.

What's captured

CallSpan kindAuto-extracted
generateTextllmmodel, provider, tokens, prompt, completion
streamTextllmsame, accumulated
generateObject / streamObjectllmmodel, tokens, schema, parsed object
tool() and the tool-call looptooltool name, input, output
embed / embedManyllmmodel, tokens

The provider field is whichever adapter you use (openai, anthropic, google).

Install

npm install ai @ai-sdk/openai

No OpenTelemetry package is needed on any version.

Minimal example

import trodo from 'trodo-node';
import { generateText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';

trodo.init({ siteId: process.env.TRODO_SITE_ID });

await trodo.wrapAgent('ai-sdk-bot', async (run) => {
  const { text } = await generateText({
    model: openai('gpt-4o-mini'),
    prompt: 'What is the weather in SF?',
    tools: {
      get_weather: tool({
        description: 'Current weather in a city',
        inputSchema: z.object({ city: z.string() }), // AI SDK v5+: inputSchema (was `parameters` in v4)
        execute: async ({ city }) => `Sunny in ${city}, 72F`,
      }),
    },
    experimental_telemetry: { isEnabled: true }, // required
  });
  run.setOutput(text);
});

On v5 / v6 the experimental_telemetry: { isEnabled: true } flag is required, without it the AI SDK emits no spans. On v7 it is harmless to leave in, and harmless to remove.

The provider on each span is the vendor alone (openai, anthropic, google), so cost and provider filters line up with every other span. The AI SDK's fuller id (openai.responses, anthropic.messages) is kept on the span as ai.provider_id, alongside ai.finish_reason.

On this page