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
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?" }],
});
// Flush : Only needed in serverless and other short-lived environments
await carbon.flushPendingEvents();
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.
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 |
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.
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 Traces and 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:
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);
}
}
A stream that is abandoned before it completes produces no event.
Flushing
In serverless and other short-lived environments, flush buffered events before exiting:
await carbon.flushPendingEvents();
Buffering and flush behavior are configurable — see Configuration.