Cloudflare Agents SDK
Instrument Cloudflare Agents SDK classes with Sentry and link chats to the Conversations tab.
Available since: v10.69.0
When you build agents with the Cloudflare Agents SDK, the Sentry Cloudflare Vite plugin instruments your agent classes automatically. It reads the classes from your wrangler config and wraps each Agent from agents, AIChatAgent from @cloudflare/ai-chat, and McpAgent from agents/mcp at build time with the options from your instrument.server.* file. You don't have to change your code.
If you deploy with wrangler directly, wrap each class yourself with instrumentAgentWithSentry, as shown in the Wrangler setup.
Agents are Durable Objects under the hood, so the agent instrumentation applies everything Durable Object instrumentation does (request transactions, alarms, WebSocket handlers, RPC trace propagation), plus agent-specific telemetry:
- Callable RPC spans: a span for each
@callable()method invoked over WebSocket, carrying the agent class and instance name as attributes. - Automatic conversation IDs: the SDK sets the conversation ID on every chat turn (
onChatMessage) and every callable RPC call, sogen_aispans group in Conversations without anysetConversationIdcall.
import { Agent, callable } from "agents";
// Each call to `greet` creates a span
export class MyAgent extends Agent<Env> {
@callable()
async greet(name: string): Promise<string> {
return `Hello, ${name}!`;
}
}
import { Agent, callable } from "agents";
// Each call to `greet` creates a span
export class MyAgent extends Agent<Env> {
@callable()
async greet(name: string): Promise<string> {
return `Hello, ${name}!`;
}
}
To continue a trace that a Worker sends to the agent over RPC, see RPC Trace Propagation. With the Vite plugin, bindings to agents in the same Worker are propagated automatically.
The automatic conversation ID defaults to the agent instance name, which is correct when one agent instance is one chat session (for example useAgent({ name: chatSessionId })). When the chat is cleared (clearHistory() from useAgentChat, or anything that emits the message:clear observability event), the SDK rotates to a fresh conversation ID, so a reset chat groups as a new conversation.
If your instances are per-user or a shared singleton like "default", the default would group unrelated chats into one conversation. Override it with your own chat session ID at the start of onChatMessage, before any model or tool calls:
import * as Sentry from "@sentry/cloudflare";
import { AIChatAgent } from "@cloudflare/ai-chat";
export class MyChatAgent extends AIChatAgent<Env> {
async onChatMessage() {
// Your chat session ID (not user id / "default")
Sentry.setConversationId("conv_abc123");
// … run your model and tools …
}
}
import * as Sentry from "@sentry/cloudflare";
import { AIChatAgent } from "@cloudflare/ai-chat";
export class MyChatAgent extends AIChatAgent<Env> {
async onChatMessage() {
// Your chat session ID (not user id / "default")
Sentry.setConversationId("conv_abc123");
// … run your model and tools …
}
}
Use a real chat session ID, such as a UUID or conv_... value your app creates when the user starts a chat. Do not use a user ID or room name: those group unrelated chats into one conversation. To clear the ID, call Sentry.setConversationId(null).
Populate the User column in the Conversations tab with Sentry.setUser on every request or handler that performs AI calls, before those calls run. See Tracking Conversations.
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").