Skip to main content
@bryel/vercel maps the Vercel AI SDK’s OpenTelemetry spans into OpenInference and ships them to bryel — models, tokens, cost, tool calls, and the full multi-step trajectory. No wrapping your model calls.
npm i @bryel/vercel @vercel/otel

1. Register the processor once

instrumentation.ts (Next.js calls this on startup):
import { registerOTel } from "@vercel/otel";
import { bryelVercelProcessor } from "@bryel/vercel";

export function register() {
  registerOTel({
    serviceName: "my-app",
    spanProcessors: [bryelVercelProcessor({ apiKey: process.env.BRYEL_KEY! })],
  });
}

2. Enable telemetry per call

const result = streamText({
  model: openai("gpt-5"),
  prompt,
  stopWhen: stepCountIs(10),
  tools: { /* … */ },
  experimental_telemetry: {
    isEnabled: true,
    metadata: { sessionId, userId },
  },
});

Grouping & feedback

The metadata you pass becomes how bryel groups and joins data:
sessionId
string
Groups multiple turns into one conversation.
userId
string
The end-user behind the run.
messageId
string
A per-turn id you mint (crypto.randomUUID()). bryel stamps it onto the spans as bryel.interaction.id so feedback joins back to the right turn. Return it to your client to attach 👍/👎.
const messageId = crypto.randomUUID();
const result = streamText({
  model: openai("gpt-5"),
  experimental_telemetry: { isEnabled: true, metadata: { sessionId, userId, messageId } },
});
return result.toTextStreamResponse({ headers: { "x-bryel-message-id": messageId } });
A streamed span finalizes only once the stream is fully consumed — always drain it.