Cloudflare Agents SDK

Instrument Cloudflare Agents SDK classes with Sentry and link chats to the Conversations view.

Available since: v10.69.0

When you build agents with the Cloudflare Agents SDK, wrap your agent classes with instrumentAgentWithSentry. Agents are Durable Objects under the hood, so the wrapper 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, so gen_ai spans group in Conversations without any setConversationId call.
Copied
import * as Sentry from "@sentry/cloudflare";
import { Agent, callable } from "agents";

class MyAgentBase extends Agent<Env> {
  @callable()
  async greet(name: string): Promise<string> {
    return `Hello, ${name}!`;
  }
}

// Export your named class as defined in your wrangler config
export const MyAgent = Sentry.instrumentAgentWithSentry(
  (env: Env) => ({
    dsn: "___PUBLIC_DSN___",
    tracesSampleRate: 1.0,
    enableRpcTracePropagation: true,
  }),
  MyAgentBase,
);

instrumentAgentWithSentry works with Agent from agents, AIChatAgent from @cloudflare/ai-chat, and McpAgent from agents/mcp. When you build with the Sentry Cloudflare Vite plugin's autoInstrumentation, the plugin detects and wraps Agent classes 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:

Copied
import * as Sentry from "@sentry/cloudflare";
import { AIChatAgent } from "@cloudflare/ai-chat";

class MyChatAgentBase 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).

On older SDK versions, wrap agent classes with instrumentDurableObjectWithSentry instead and set the conversation ID manually at the start of the handler (onRequest for Agent, onChatMessage for AIChatAgent), before any AI calls:

Copied
import * as Sentry from "@sentry/cloudflare";
import { AIChatAgent } from "@cloudflare/ai-chat";

class MyChatAgentBase extends AIChatAgent<Env> {
  async onChatMessage() {
    Sentry.setConversationId("conv_abc123");

    // … run your model and tools …
  }
}

export const MyChatAgent = Sentry.instrumentDurableObjectWithSentry(
  (env: Env) => ({
    dsn: "___PUBLIC_DSN___",
    tracesSampleRate: 1.0,
  }),
  MyChatAgentBase,
);

Populate the Conversations User column with Sentry.setUser on every request or handler that performs AI calls, before those calls run. See Tracking Conversations.

Was this helpful?
Help improve this content
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").