> ## 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.

# Anthropic

> Capture Anthropic SDK calls — Messages and streaming — as Carbon events.

`wrapAnthropicSdk` instruments an existing Anthropic client. Your call sites stay the same; each request is captured as an LLM event with model, prompts, output, token usage, duration, and status.

## Quick setup

```typescript theme={null}
import Anthropic from "@anthropic-ai/sdk";
import { Carbon } from "@carbon-js/sdk";
import { wrapAnthropicSdk } from "@carbon-js/sdk/ai";

const carbon = new Carbon();
const anthropic = wrapAnthropicSdk(new Anthropic(), carbon);

const message = await anthropic.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "What is the capital of France?" }],
});
```

<Note>
  `wrapAnthropicSdk` mutates the client you pass in and returns the same instance, typed to accept the optional `carbon`
  field on requests. Wrap the client once at startup and share the wrapped instance.
</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

| Method                                | Captured as                                        |
| ------------------------------------- | -------------------------------------------------- |
| `messages.create`                     | One LLM event                                      |
| `messages.create` with `stream: true` | One LLM event, recorded after the stream completes |
| `messages.stream`                     | One LLM event, recorded after the stream completes |

## Attach metadata

Add a `carbon` field to any request to set a trace ID, context identifiers, or custom properties. The SDK strips the field before the request reaches Anthropic.

```typescript theme={null}
const traceId = carbon.createTraceId();

const message = await anthropic.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Summarize this ticket." }],
  carbon: {
    traceId,
    context: { agentId: "support-agent", userId: "user-481" },
    additionalProperties: { release: "2026-06" },
  },
});
```

See [Context](/documentation/sdk/context) for what each field powers in the dashboard.

## Streaming

Streamed responses are captured after the stream finishes, so the stream must be fully consumed:

```typescript theme={null}
const stream = await anthropic.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Write a haiku about ledgers." }],
  stream: true,
});

for await (const event of stream) {
  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
    process.stdout.write(event.delta.text);
  }
}
```

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

## Tool calls

The Anthropic Messages API does not execute tools. `messages.create` and `messages.stream` capture the LLM turn, including the `tool_use` blocks the model requests, but running those tools is your code's job — so tool executions are always instrumented manually.

Wrap each tool with `wrapTool` so its execution is captured. These methods don't open a trace of their own, so create a trace ID with `carbon.createTraceId()` and pass it to both the model call and every tool call — that shared ID links the LLM event and its tool events into one trace:

```typescript theme={null}
const getWeather = carbon.wrapTool({
  name: "get_weather",
  run: async ({ city }: { city: string }) => fetchWeather(city),
});

const traceId = carbon.createTraceId();

const message = await anthropic.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 1024,
  messages,
  tools: [/* get_weather definition */],
  carbon: { traceId },
});

// Run each tool the model requested — each wrapped call is captured on the same trace.
for (const block of message.content) {
  if (block.type === "tool_use" && block.name === "get_weather") {
    await getWeather(block.input as { city: string }, { traceId });
  }
}
```

See [Tool calls](/documentation/sdk/tool-calls) for the full `wrapTool` API.
