> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oncarbon.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel AI SDK

> Capture generateText, streamText, and ToolLoopAgent calls — including tool executions — as Carbon events.

`wrapVercelSdk` instruments the Vercel AI SDK module. Wrapped functions behave exactly like the originals; each call is captured as an LLM event, and tools executed during the call are captured as tool events on the same trace.

## Quick setup

```typescript theme={null}
import * as ai from "ai";
import { Carbon } from "@carbon-js/sdk";
import { wrapVercelSdk } from "@carbon-js/sdk/ai";

const carbon = new Carbon();
const { generateText } = wrapVercelSdk(ai, carbon);

const result = await generateText({
  model: "google/gemini-3-flash",
  prompt: "What is the capital of France?",
});
```

<Note>
  Unlike the OpenAI and Anthropic wrappers, `wrapVercelSdk` does not mutate the module you pass in — it returns a new
  wrapped object. Import functions from the wrapped object, not from `ai` directly.
</Note>

Deploying to a serverless platform — Next.js, Vercel, AWS Lambda? Flush buffered events before the function exits so none are lost. See [Serverless](/documentation/sdk/serverless).

## What gets captured

| Function                                  | Captured as                                                    |
| ----------------------------------------- | -------------------------------------------------------------- |
| `generateText`                            | One LLM event per step, plus one tool event per tool execution |
| `streamText`                              | The same, recorded after the stream completes                  |
| `ToolLoopAgent` (`generate` and `stream`) | LLM and tool events for every step of the loop                 |

The wrapper forces AI SDK telemetry on for wrapped calls and uses its lifecycle callbacks to build events. Existing telemetry configuration is preserved.

## Capturing cost

Calls through the **Vercel AI Gateway** — a bare id like `"openai/gpt-5"` — are priced automatically: Carbon records the gateway as the provider and ingest computes the cost from it, with no setup. Everything below is only needed when you **construct a provider yourself**.

When you build a provider (`createOpenAI`, `createAnthropic`, …), the Vercel AI SDK hides the request URL — so Carbon can't see which platform served the call, and without the provider it can't price it. Pass **`carbon.fetch`** so Carbon captures the endpoint and resolves the provider and cost from it:

```typescript theme={null}
import { createOpenAI } from "@ai-sdk/openai";

const openai = createOpenAI({ fetch: carbon.fetch });

const { text } = await generateText({
  model: openai("gpt-5"),
  prompt: "What is the capital of France?",
});
```

`carbon.fetch` is a drop-in `fetch`: it records the request URL and otherwise behaves normally. It works with every AI SDK provider — `createAnthropic`, `createAmazonBedrock`, `createOpenAICompatible`, a custom `baseURL`, and so on. If you already pass your own `fetch`, compose it instead:

```typescript theme={null}
const openai = createOpenAI({ fetch: carbon.wrapFetch(myFetch) });
```

## Attach metadata

Add a `carbon` field to the call arguments to set context identifiers or custom properties:

```typescript theme={null}
import { tool } from "ai";
import { z } from "zod";

const result = await generateText({
  model: "google/gemini-3-flash",
  prompt: "What is the weather in Tokyo?",
  tools: {
    get_weather: tool({
      description: "Get the current weather for a city",
      inputSchema: z.object({ city: z.string() }),
      execute: async ({ city }) => ({ city, tempC: 22 }),
    }),
  },
  carbon: {
    context: { agentId: "travel-agent", threadId: "thread-92", userId: "user-481" },
  },
});
```

Tool executions inside the call are recorded automatically — more on that under [Tool calls](#tool-calls). Each call gets its own [trace](/documentation/sdk/traces) automatically; pass a `traceId` only when one trace should span several calls. See [Context](/documentation/sdk/context) for what each field powers in the dashboard.

## Streaming

`streamText` events are recorded after the stream finishes, so consume the stream to completion:

```typescript theme={null}
const { streamText } = wrapVercelSdk(ai, carbon);

const result = streamText({
  model: "google/gemini-3-flash",
  prompt: "Write a haiku about ledgers.",
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}
```

<Warning>A stream that is abandoned before it completes produces no event.</Warning>

## Tool calls

Every tool the AI SDK runs is instrumented automatically. `generateText`, `streamText`, and `ToolLoopAgent` (both `generate` and `stream`) capture each tool execution as a tool event on the same trace as the call — no `wrapTool`, no extra setup. Carbon reads them straight from the SDK's tool telemetry, so single calls and multi-step tool loops are covered alike. The `get_weather` tool in [Attach metadata](#attach-metadata) above is captured this way.

<Note>
  Only tools the SDK runs are captured here. A tool defined without an `execute`
  function is handed back to your code to run rather than executed by the SDK —
  if you run a tool yourself, wrap it with
  [`wrapTool`](/documentation/sdk/tool-calls) to capture it.
</Note>
