diff --git a/docs/platforms/javascript/common/agent-tracing/index.mdx b/docs/platforms/javascript/common/agent-tracing/index.mdx index e3101effad8641..0fe0a7fa04502e 100644 --- a/docs/platforms/javascript/common/agent-tracing/index.mdx +++ b/docs/platforms/javascript/common/agent-tracing/index.mdx @@ -30,7 +30,7 @@ supported: - javascript.nitro --- -With Sentry Agent Tracing, you can monitor and debug your AI systems with full-stack context. You'll be able to track key insights like token usage, latency, tool usage, and error rates. Agent Tracing data will be fully connected to your other Sentry data like logs, errors, and traces. +With Sentry Agent Tracing, you can monitor and debug your AI systems with full-stack context. Track token usage, latency, tool usage, and error rates — and group multi-turn chats in Conversations. Agent Tracing data is fully connected to your other Sentry data like logs, errors, and traces. @@ -46,6 +46,10 @@ Before setting up Agent Tracing, ensure you have tr The JavaScript SDK supports automatic instrumentation for AI libraries. Add the integration for your AI library to your Sentry configuration: + +- Cloudflare Workers AI — automatic instrumentation for `env.AI` (no integration to add) + + - Vercel AI SDK - OpenAI @@ -79,61 +83,101 @@ Sentry.init({ -## Options +## Tracking Conversations + + + Tracking Conversations has **beta** stability. Configuration options and behavior may change. + -### Privacy Controls +[Conversations](/product/agents/conversations/) groups multi-turn AI activity into a single replay of messages and tool calls. Use `setConversationId()` so every AI span in a chat session shares the same `gen_ai.conversation.id`. -All AI integrations support `recordInputs` and `recordOutputs` options to control whether prompts and responses are captured. Both default to `true`. +Some integrations infer a conversation ID automatically. For everything else (including Workers AI), set it yourself at the start of the session. The ID is applied to all AI-related spans in the current scope. Pass `null` to unset it. -Set these to `false` if your prompts or responses contain sensitive data you don't want sent to Sentry. + + +Building with the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/)? Link chats with your session ID. See Cloudflare Agents SDK. + + ```javascript import * as Sentry from "___SDK_PACKAGE___"; -import { openAIIntegration } from "___SDK_PACKAGE___"; -Sentry.init({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, - integrations: [ - openAIIntegration({ - recordInputs: false, // Don't capture prompts - recordOutputs: false, // Don't capture responses - }), +// Set conversation ID at the start of a conversation +Sentry.setConversationId('conv_abc123'); + +// All subsequent AI calls will be linked to this conversation +await openai.chat.completions.create({ + model: "gpt-4", + messages: [{ role: "user", content: "Hello" }], +}); + +// Later in the conversation +await openai.chat.completions.create({ + model: "gpt-4", + messages: [ + { role: "user", content: "Hello" }, + { role: "assistant", content: "Hi there!" }, + { role: "user", content: "What's the weather?" }, ], }); + +// Both calls will have gen_ai.conversation.id: "conv_abc123" + +// To unset it +Sentry.setConversationId(null); ``` +### Identifying Users in Conversations + +The [Conversations](/product/agents/conversations/) view includes a **User** column. To populate it, call `setUser` once per request or session, before any AI calls: + +```javascript +import * as Sentry from "___SDK_PACKAGE___"; + +Sentry.setUser({ id: "user_123", email: "jane@example.com", username: "jane" }); +``` + +Any of `id`, `email`, or `username` is sufficient — Conversations displays whichever fields are present. See the setUser API reference for the full list of supported fields. + +## Options + -### Streaming Gen AI Spans +### Privacy Controls -`gen_ai` spans are sent as standalone envelope items instead of being bundled in the transaction by default (since SDK version `10.61.0`). This prevents AI spans with large inputs and outputs from hitting transaction payload size limits and being dropped, and is required for Conversations to work. +All AI integrations support `recordInputs` and `recordOutputs` options to control whether prompts and responses are captured. Both default to `true`. -To send `gen_ai` spans as part of the transaction instead, set `streamGenAiSpans` to `false`. Self-hosted Sentry users should set this to `false`, as standalone `gen_ai` spans may not be ingested by their Sentry instance. +Set these to `false` if your prompts or responses contain sensitive data you don't want sent to Sentry. ```javascript import * as Sentry from "___SDK_PACKAGE___"; +import { openAIIntegration } from "___SDK_PACKAGE___"; Sentry.init({ dsn: "___PUBLIC_DSN___", tracesSampleRate: 1.0, - streamGenAiSpans: false, // opt out of streaming gen_ai spans + integrations: [ + openAIIntegration({ + recordInputs: false, // Don't capture prompts + recordOutputs: false, // Don't capture responses + }), + ], }); ``` @@ -141,19 +185,15 @@ Sentry.init({ -## Tracking Conversations - - - Tracking Conversations has **beta** stability. Configuration options and behavior may change. - - -When building AI applications with multi-turn conversations, you can use `setConversationId()` to link all AI spans from the same conversation together. This allows you to analyze entire conversation flows in Sentry. +### Streaming Gen AI Spans + +`gen_ai` spans are sent as standalone envelope items instead of being bundled in the transaction by default (since SDK version `10.61.0`). This prevents AI spans with large inputs and outputs from hitting transaction payload size limits and being dropped, and is required for Conversations to work. -The conversation ID is automatically applied as the `gen_ai.conversation.id` attribute to all AI-related spans within the current scope. To unset the conversation ID, pass `null`. +To send `gen_ai` spans as part of the transaction instead, set `streamGenAiSpans` to `false`. Self-hosted Sentry users should set this to `false`, as standalone `gen_ai` spans may not be ingested by their Sentry instance. @@ -161,57 +201,31 @@ The conversation ID is automatically applied as the `gen_ai.conversation.id` att ```javascript import * as Sentry from "___SDK_PACKAGE___"; -// Set conversation ID at the start of a conversation -Sentry.setConversationId('conv_abc123'); - -// All subsequent AI calls will be linked to this conversation -await openai.chat.completions.create({ - model: "gpt-4", - messages: [{ role: "user", content: "Hello" }], -}); - -// Later in the conversation -await openai.chat.completions.create({ - model: "gpt-4", - messages: [ - { role: "user", content: "Hello" }, - { role: "assistant", content: "Hi there!" }, - { role: "user", content: "What's the weather?" }, - ], +Sentry.init({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, + streamGenAiSpans: false, // opt out of streaming gen_ai spans }); - -// Both calls will have gen_ai.conversation.id: "conv_abc123" - -// To unset it -Sentry.setConversationId(null); ``` -## Identifying Users in Conversations - -The [Conversations](/product/agents/conversations/) view includes a **User** column. To populate it, call `setUser` once per request or session, before any AI calls: - -```javascript -import * as Sentry from "___SDK_PACKAGE___"; - -Sentry.setUser({ id: "user_123", email: "jane@example.com", username: "jane" }); -``` - -Any of `id`, `email`, or `username` is sufficient — Conversations displays whichever fields are present. See the [setUser API reference](/platforms/javascript/configuration/apis/#setUser) for the full list of supported fields. - ## Manual Instrumentation You can also instrument agent spans yourself. See manual instrumentation. ## Framework Exporters + + If you're using an AI framework with a Sentry exporter, you can send traces to Sentry: - Mastra Sentry Exporter + + ## MCP Server Monitoring If you're building MCP (Model Context Protocol) servers, Sentry can also track tool executions, prompt retrievals, and resource access. See Instrument MCP Servers for setup instructions. diff --git a/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx b/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx new file mode 100644 index 00000000000000..6abf26da69cf8c --- /dev/null +++ b/docs/platforms/javascript/guides/cloudflare/features/agents-sdk.mdx @@ -0,0 +1,69 @@ +--- +title: Cloudflare Agents SDK +description: "Link Cloudflare Agents SDK chats to Sentry Conversations with a chat session ID." +--- + +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. + +Workers AI and other AI integrations do **not** set this for you. + +## Prerequisites + +- Tracing enabled +- Durable Objects instrumented with `instrumentDurableObjectWithSentry` (see Durable Objects) + +## Link conversations + +Set the conversation ID before any AI calls in the request handler: + +```typescript +import * as Sentry from "@sentry/cloudflare"; +import { Agent } from "agents"; + +class MyAgentBase extends Agent { + async onRequest(request: Request): Promise { + // Your chat session ID for this conversation (not user id / "default") + const chatSessionId = new URL(request.url).searchParams.get("chatId"); + if (chatSessionId) { + Sentry.setConversationId(chatSessionId); + } + + const result = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", { + messages: [{ role: "user", content: await request.text() }], + }); + + return new Response(JSON.stringify(result)); + } +} + +export const MyAgent = Sentry.instrumentDurableObjectWithSentry( + (env: Env) => ({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, + }), + MyAgentBase +); +``` + +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` once per session, before AI calls. See Identifying Users in Conversations. + +## Related + +- Workers AI +- Durable Objects +- Tracking Conversations +- Conversations product docs diff --git a/docs/platforms/javascript/guides/cloudflare/features/workers-ai.mdx b/docs/platforms/javascript/guides/cloudflare/features/workers-ai.mdx index 9d5e5c5545cb3a..70a1070e2a19a7 100644 --- a/docs/platforms/javascript/guides/cloudflare/features/workers-ai.mdx +++ b/docs/platforms/javascript/guides/cloudflare/features/workers-ai.mdx @@ -5,7 +5,7 @@ description: "Learn how Sentry instruments Cloudflare Workers AI to capture gen_ -Sentry automatically instruments the [Cloudflare Workers AI binding](https://developers.cloudflare.com/workers-ai/get-started/workers-wrangler/) (`env.AI`). Calls to `env.AI.run(...)` create `gen_ai` spans that follow Sentry's AI Agent Monitoring conventions, capturing the model, request parameters, and token usage. +Sentry automatically instruments the [Cloudflare Workers AI binding](https://developers.cloudflare.com/workers-ai/get-started/workers-wrangler/) (`env.AI`). Calls to `env.AI.run(...)` create `gen_ai` spans that follow Sentry's Agent Tracing conventions, capturing the model, request parameters, and token usage. No extra setup is required beyond initializing the SDK with `withSentry`. As long as your handler receives the instrumented `env`, the `AI` binding is wrapped for you: @@ -32,86 +32,7 @@ export default Sentry.withSentry( You can browse the full list of available models in the [Cloudflare Workers AI models directory](https://developers.cloudflare.com/ai/models/). -## Tracking Conversations +## Next Steps - - Tracking Conversations has **beta** stability. Configuration options and - behavior may change. - - -The Workers AI instrumentation does **not** infer the conversation ID automatically. To group multi-turn AI calls into a single Conversation, set it manually with `Sentry.setConversationId()`. The ID is applied as the `gen_ai.conversation.id` attribute to all AI spans within the current scope. See Tracking Conversations for details. - -When you use the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/), each agent instance already has a stable identifier, its Durable Object instance name (`this.name`), which is a natural conversation ID. - -### Agent - -Set the conversation ID at the start of the request handler, before any `env.AI.run(...)` calls: - -```typescript -import * as Sentry from "@sentry/cloudflare"; -import { Agent } from "agents"; - -class MyAgentBase extends Agent { - async onRequest(request: Request): Promise { - // Use the Agent's Durable Object instance name as the conversation ID - Sentry.setConversationId(this.name); - - const result = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", { - messages: [{ role: "user", content: await request.text() }], - }); - - return new Response(JSON.stringify(result)); - } -} - -export const MyAgent = Sentry.instrumentDurableObjectWithSentry( - (env: Env) => ({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, - }), - MyAgentBase -); -``` - -### ChatAgent - -For chat agents, set the conversation ID at the top of `onChatMessage` so every AI call triggered while handling the message shares it: - -```typescript -import * as Sentry from "@sentry/cloudflare"; -import { AIChatAgent } from "@cloudflare/ai-chat"; -import type { StreamTextOnFinishCallback } from "ai"; - -class MyChatAgentBase extends AIChatAgent { - async onChatMessage( - _onFinish: StreamTextOnFinishCallback - ): Promise { - // Every message in this chat session shares the same conversation ID - Sentry.setConversationId(this.name); - - const result = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", { - messages: this.messages.map((m) => ({ - role: m.role, - content: m.parts - .filter((p) => p.type === "text") - .map((p) => p.text) - .join(""), - })), - }); - - return new Response(JSON.stringify(result)); - } -} - -export const MyChatAgent = Sentry.instrumentDurableObjectWithSentry( - (env: Env) => ({ - dsn: "___PUBLIC_DSN___", - tracesSampleRate: 1.0, - }), - MyChatAgentBase -); -``` - -To unset the conversation ID, pass `null` to `Sentry.setConversationId()`. - -Grouped AI calls show up in the Conversations view, where you can inspect token usage, latency, and errors across an entire conversation. +- Group multi-turn chats in Conversations with `setConversationId()` +- Using the [Cloudflare Agents SDK](https://developers.cloudflare.com/agents/)? See Cloudflare Agents SDK for conversation linking