From 27a6ea94cb2ac7cfa4d1052c07500da26b710806 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 29 Jul 2026 15:30:34 +0200 Subject: [PATCH] docs(cloudflare): Add features from 10.69.0 --- .../guides/cloudflare/features/agents-sdk.mdx | 76 +++++++++++++------ .../cloudflare/features/durableobject.mdx | 20 +---- .../cloudflare/features/vite-plugin.mdx | 34 +++++++-- 3 files changed, 85 insertions(+), 45 deletions(-) diff --git a/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx b/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx index 0081899975799..df3090650158f 100644 --- a/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx +++ b/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx @@ -1,22 +1,44 @@ --- title: Cloudflare Agents SDK -description: "Link Cloudflare Agents SDK chats to Sentry Conversations with a chat session ID." +description: "Instrument Cloudflare Agents SDK classes with Sentry and link chats to Conversations." --- -When you build agents with the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/), set a conversation ID so multi-turn AI activity groups correctly in Conversations. + -Use **your chat session ID** (for example a UUID or `conv_...` value your app creates when the user starts a chat). Do not use a user ID, room name, or the Durable Object instance name unless that name is already one chat session. +When you build agents with the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/), 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: -Workers AI does **not** set this for you. Set the ID on the isolation scope that runs your AI work — for chat agents, that is typically at the start of `onChatMessage`, before any model or tool calls. +- **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. -## Prerequisites +```typescript +import * as Sentry from "@sentry/cloudflare"; +import { Agent, callable } from "agents"; + +class MyAgentBase extends Agent { + @callable() + async greet(name: string): Promise { + 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 +); +``` -- Tracing enabled -- Durable Objects instrumented with `instrumentDurableObjectWithSentry` (see Durable Objects) +`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. -## Link conversations +## Conversation IDs -Set the conversation ID before any AI calls in the chat handler: +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](https://developers.cloudflare.com/agents/runtime/operations/observability/#channels)), 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: ```typescript import * as Sentry from "@sentry/cloudflare"; @@ -30,6 +52,25 @@ class MyChatAgentBase extends AIChatAgent { // … 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)`. + +## SDK Versions Before 10.69.0 + +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: + +```typescript +import * as Sentry from "@sentry/cloudflare"; +import { AIChatAgent } from "@cloudflare/ai-chat"; + +class MyChatAgentBase extends AIChatAgent { + async onChatMessage() { + Sentry.setConversationId("conv_abc123"); + + // … run your model and tools … + } +} export const MyChatAgent = Sentry.instrumentDurableObjectWithSentry( (env: Env) => ({ @@ -40,18 +81,6 @@ export const MyChatAgent = Sentry.instrumentDurableObjectWithSentry( ); ``` -Define the conversation ID however your app tracks chats (client param, storage, etc.). Re-set it at the start of each handler that performs AI work so it applies on that isolation scope. - -If you already name each agent instance as one chat session (for example `useAgent({ name: chatSessionId })`), you can pass that value: - -```typescript -Sentry.setConversationId(this.name); -``` - -Only do this when the instance name is **one conversation**, not per-user or a shared singleton like `"default"`. - -To clear the ID: `Sentry.setConversationId(null)`. - ## Users Populate the Conversations **User** column with `Sentry.setUser` on every request or handler that performs AI calls, before those calls run. See Tracking Conversations. @@ -60,5 +89,8 @@ Populate the Conversations **User** column with `Sentry.setUser` on every reques - Workers AI - Durable Objects -- Tracking Conversations +- Vite Plugin +- + Tracking Conversations + - Conversations product docs diff --git a/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx b/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx index 229d6cf0d3d32..eb43577074881 100644 --- a/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx +++ b/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx @@ -28,25 +28,13 @@ export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry( `instrumentDurableObjectWithSentry` works with any class that extends `DurableObject`, not only those that extend it directly. This includes classes built on top of Durable Objects by other libraries. -For example, the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/) builds its `Agent` and `AIChatAgent` classes on top of Durable Objects, so you can instrument them the same way: +For classes built on the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/) (`Agent`, `AIChatAgent`, `McpAgent`), use the dedicated `instrumentAgentWithSentry` wrapper instead (SDK version 10.69.0 or higher). It applies the same Durable Object instrumentation and adds spans for `@callable()` RPC methods as well as automatic conversation IDs. See Cloudflare Agents SDK. -```typescript -import * as Sentry from "@sentry/cloudflare"; -import { Agent } from "agents"; +## Durable Object Storage Spans -class MyAgentBase extends Agent { - // impl -} +`instrumentDurableObjectWithSentry` automatically instruments Durable Object storage operations (`get`, `put`, `delete`, `list`). Each storage operation creates a span. -// Export your named class as defined in your wrangler config -export const MyAgent = Sentry.instrumentDurableObjectWithSentry( - (env: Env) => ({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, - }), - MyAgentBase -); -``` +The SDK also filters out framework-internal storage operations (version 10.69.0 or higher): keys prefixed with `cf_`, `cf:`, `__ps_`, or `/` (used internally by the Agents SDK and PartyServer) don't create spans, so your traces show only your own storage access. ## RPC Trace Propagation diff --git a/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx b/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx index d2b225f8f6124..b2db9d3069720 100644 --- a/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx +++ b/docs/platforms/javascript/guides/cloudflare/features/vite-plugin.mdx @@ -6,14 +6,14 @@ description: "Learn how to use the Sentry Cloudflare Vite plugin to instrument b - The Sentry Cloudflare Vite plugin has **experimental** stability. Configuration - options and behavior may change or be removed in any release. + The Sentry Cloudflare Vite plugin has **experimental** stability. + Configuration options and behavior may change or be removed in any release. The Sentry Cloudflare Vite plugin (`sentryCloudflareVitePlugin`) instruments your Worker at build time. It can: -1. **Instrument bundled dependencies** — automatically instruments supported packages in your bundle (such as database clients like `mysql`) at build time, giving you more traces out of the box. -2. **Auto-instrument your Worker entry** — optionally wraps your default export with `Sentry.withSentry()` and Durable Objects with `instrumentDurableObjectWithSentry()` at build time, so you don't need to modify your code. +1. **Instrument bundled dependencies**: automatically instruments supported packages in your bundle (such as database clients like `mysql`) at build time, giving you more traces out of the box. +2. **Auto-instrument your Worker entry**: optionally wraps your default export with `Sentry.withSentry()`, and Durable Object, Workflow, and Agents SDK classes with the matching `instrument*WithSentry` helper at build time, so you don't need to modify your code. **We recommend building your Cloudflare Worker with Vite and the `sentryCloudflareVitePlugin` plugin.** It's the most complete way to get tracing for bundled dependencies in the Workers runtime. If you already deploy with `wrangler` directly, see [Migrating From Wrangler](#migrating-from-wrangler). @@ -65,7 +65,7 @@ export default Sentry.withSentry( ### Auto-instrumentation (Experimental) -Alternatively, the plugin can wrap your Worker for you at build time, so you don't need `withSentry` in your code. Enable `autoInstrumentation` and the plugin reads your `wrangler.(jsonc|toml)` to find the entry point, Durable Objects, and workflows: +Alternatively, the plugin can wrap your Worker for you at build time, so you don't need `withSentry` in your code. Enable `autoInstrumentation` and the plugin reads your wrangler config (probing `wrangler.json`, `wrangler.jsonc`, and `wrangler.toml` at the Vite root, or the file set with [`wranglerConfigPath`](#options)) to find the entry point, Durable Objects, workflows, and Agents SDK classes. The plugin wraps Agents SDK classes (`Agent`, `AIChatAgent`, `McpAgent`) with `instrumentAgentWithSentry` (SDK version 10.69.0 or higher), which also gives them automatic conversation IDs (see Cloudflare Agents SDK). ```typescript {filename:vite.config.ts} import { cloudflare } from "@cloudflare/vite-plugin"; @@ -100,6 +100,26 @@ If no `instrument.server.*` file exists, the SDK reads all configuration (DSN, r ## Options + + +Path to your wrangler config file. By default the plugin probes `wrangler.json`, `wrangler.jsonc`, and `wrangler.toml` at the Vite root. Set this when your config lives at a custom path, for example to mirror the `configPath` option of the Cloudflare Vite plugin: + +```typescript {filename:vite.config.ts} +export default defineConfig({ + plugins: [ + cloudflare({ configPath: "./wrangler.agent.jsonc" }), + sentryCloudflareVitePlugin({ + wranglerConfigPath: "./wrangler.agent.jsonc", + _experimental: { + autoInstrumentation: true, + }, + }), + ], +}); +``` + + + Experimental options that may change or be removed without notice. @@ -108,7 +128,7 @@ Experimental options that may change or be removed without notice. -Automatically wraps your Worker at build time so you don't have to edit your entry. The plugin reads your wrangler config, wraps the default export with `Sentry.withSentry()` (sourcing options from a co-located `instrument.server.*` file, falling back to `env`), and wraps any configured Durable Object and Workflow classes with the matching `instrument*WithSentry` helper. Both `vite build` and `vite dev` are instrumented. +Automatically wraps your Worker at build time so you don't have to edit your entry. The plugin reads your wrangler config, wraps the default export with `Sentry.withSentry()` (sourcing options from a co-located `instrument.server.*` file, falling back to `env`), and wraps configured classes with the matching helper: Durable Objects with `instrumentDurableObjectWithSentry`, Workflows with `instrumentWorkflowWithSentry`, and Agents SDK classes with `instrumentAgentWithSentry` (SDK version 10.69.0 or higher). Both `vite build` and `vite dev` are instrumented. @@ -125,4 +145,4 @@ If you deploy with `wrangler` directly, moving to Vite is straightforward: 1. Set up the [Cloudflare Vite plugin](https://developers.cloudflare.com/workers/vite-plugin/get-started/) and add a `vite.config.ts` with the `cloudflare()` and `sentryCloudflareVitePlugin()` plugins as shown above. 2. Run `vite build` before `wrangler deploy`, and use `vite dev` in place of `wrangler dev` for local development. -Your existing `wrangler.jsonc` becomes the input config — the plugin generates the deployed output during the build. For the full list of fields that change or become redundant, see Cloudflare's [Migrating from Wrangler](https://developers.cloudflare.com/workers/vite-plugin/reference/migrating-from-wrangler-dev/) guide. +Your existing `wrangler.jsonc` becomes the input config, and the plugin generates the deployed output during the build. For the full list of fields that change or become redundant, see Cloudflare's [Migrating from Wrangler](https://developers.cloudflare.com/workers/vite-plugin/reference/migrating-from-wrangler-dev/) guide.