Prototype Notice: This integration targets AI SDK v7+ (beta) which exposes a first-class
TelemetryIntegrationlifecycle. It currently coversgenerateTextandstreamText.generateObjectandstreamObjectwill be added in a future release.
Braintrust has historically provided tracing for the Vercel AI SDK through the wrapAISDK(...) proxy approach. Starting with AI SDK v7, the SDK exposes a new TelemetryIntegration interface that lets integrations receive lifecycle events directly — no proxy needed.
The BraintrustTelemetryIntegration is Braintrust's first-party implementation of this interface.
npm install braintrust ai@7.0.0-beta.42import { registerTelemetryIntegration } from "ai";
import { BraintrustTelemetryIntegration } from "braintrust";
// Register once at startup — all generateText/streamText calls get traced
registerTelemetryIntegration(new BraintrustTelemetryIntegration());import { generateText } from "ai";
import { BraintrustTelemetryIntegration } from "braintrust";
const integration = new BraintrustTelemetryIntegration();
const result = await generateText({
model: openai("gpt-4"),
prompt: "Hello world",
experimental_telemetry: {
integrations: [integration],
},
});Custom span names, metadata, and span attributes are passed through experimental_telemetry.metadata.braintrust:
import { generateText } from "ai";
const result = await generateText({
model: openai("gpt-4"),
prompt: "Summarize this document",
experimental_telemetry: {
metadata: {
braintrust: {
name: "document-summarizer",
metadata: { documentId: "doc-123", user: "alice" },
spanAttributes: { type: "function" },
},
},
},
});| Field | Type | Description |
|---|---|---|
name |
string |
Custom name for the root Braintrust span (default: generateText or streamText) |
metadata |
Record<string, unknown> |
Additional metadata attached to the Braintrust span |
spanAttributes |
Record<string, unknown> |
Custom span attributes (e.g., { type: "function" }) |
wrapAISDK (old) |
TelemetryIntegration (new) |
|---|---|
wrapAISDK(ai) |
registerTelemetryIntegration(new BraintrustTelemetryIntegration()) |
span_info.name |
experimental_telemetry.metadata.braintrust.name |
span_info.metadata |
experimental_telemetry.metadata.braintrust.metadata |
span_info.spanAttributes |
experimental_telemetry.metadata.braintrust.spanAttributes |
| Wrapper owns tracing | Integration owns tracing |
import { wrapAISDK } from "braintrust";
import * as ai from "ai";
const { generateText } = wrapAISDK(ai);
const result = await generateText({
model: openai("gpt-4"),
prompt: "Reply with PARIS",
span_info: {
name: "city-lookup",
metadata: { region: "europe" },
},
});import { registerTelemetryIntegration, generateText } from "ai";
import { BraintrustTelemetryIntegration } from "braintrust";
registerTelemetryIntegration(new BraintrustTelemetryIntegration());
const result = await generateText({
model: openai("gpt-4"),
prompt: "Reply with PARIS",
experimental_telemetry: {
metadata: {
braintrust: {
name: "city-lookup",
metadata: { region: "europe" },
},
},
},
});import { wrapAISDK } from "braintrust";
import * as ai from "ai";
const { streamText } = wrapAISDK(ai);
const result = streamText({
model: openai("gpt-4"),
prompt: "Count to 3",
span_info: {
name: "counting-stream",
},
});
for await (const chunk of result.textStream) {
console.log(chunk);
}import { registerTelemetryIntegration, streamText } from "ai";
import { BraintrustTelemetryIntegration } from "braintrust";
registerTelemetryIntegration(new BraintrustTelemetryIntegration());
const result = streamText({
model: openai("gpt-4"),
prompt: "Count to 3",
experimental_telemetry: {
metadata: {
braintrust: {
name: "counting-stream",
},
},
},
});
for await (const chunk of result.textStream) {
console.log(chunk);
}// Old (wrapper)
generateText({ ...params, span_info: { name: "my-span" } });
// New (integration)
generateText({
...params,
experimental_telemetry: {
metadata: { braintrust: { name: "my-span" } },
},
});// Old (wrapper)
generateText({
...params,
span_info: { metadata: { env: "production", version: "1.2" } },
});
// New (integration)
generateText({
...params,
experimental_telemetry: {
metadata: {
braintrust: { metadata: { env: "production", version: "1.2" } },
},
},
});The integration produces the following trace structure:
root span (generateText / custom-name)
└── step-0 (LLM call)
root span (generateText / custom-name)
├── step-0 (LLM call → tool call)
│ └── get_weather (tool execution)
└── step-1 (LLM call → final response)
root span (streamText / custom-name)
└── step-0 (LLM call, includes time_to_first_token metric)
| Data | Location |
|---|---|
| System/prompt/messages | Root span input |
| Model ID | Root span metadata.model |
| Provider | Root span metadata.provider |
| Step messages | Step span input |
| Step output (text, tool calls, finish reason, usage) | Step span output |
| Token usage metrics | Step span and root span metrics |
| Tool call input | Tool span input |
| Tool call output | Tool span output |
| Tool execution duration | Tool span metrics.duration |
| Time to first token (streaming) | Step span metrics.time_to_first_token |
| Errors | Span error field |
This is a prototype focused on validating the approach. The following are not yet supported:
generateObject/streamObject— planned for a future release- AI SDK versions prior to v7 — use
wrapAISDKfor v3–v6 - Mixed wrapper/integration coexistence — do not use both
wrapAISDKandBraintrustTelemetryIntegrationon the same call - Agent class wrapping — the integration covers
generateTextandstreamText; agent classes still use the wrapper
import { BraintrustTelemetryIntegration } from "braintrust";
const integration = new BraintrustTelemetryIntegration();Implements the AI SDK TelemetryIntegration interface with the following lifecycle hooks:
onStart— Creates root Braintrust spanonStepStart— Creates child step spanonToolCallStart— Creates child tool spanonToolCallFinish— Logs tool output/error and ends tool spanonChunk— Trackstime_to_first_tokenfor streamingonStepFinish— Logs step output/metrics and ends step spanonFinish— Logs final output/metrics and ends root spanonError— Logs error on all open spans and ends themexecuteTool— Runs tool execution within Braintrust span context (enables nested traces)
import type { BraintrustTelemetryMetadata } from "braintrust";
const meta: BraintrustTelemetryMetadata = {
name: "my-span",
metadata: { key: "value" },
spanAttributes: { type: "function" },
};