diff --git a/docs/platforms/javascript/common/agent-tracing/index.mdx b/docs/platforms/javascript/common/agent-tracing/index.mdx index 4d49c088f020e..f9f079215ebb8 100644 --- a/docs/platforms/javascript/common/agent-tracing/index.mdx +++ b/docs/platforms/javascript/common/agent-tracing/index.mdx @@ -81,6 +81,11 @@ As of SDK version `11.0.0`, Sentry auto-instruments the most popular AI SDKs and title: "TypeSafe", icon: "typesafe-ai", }, + { + to: "/configuration/integrations/pi-durable/", + title: "pi-durable", + icon: "default", + }, { to: "/agent-tracing/mastra/", href: "/platforms/javascript/guides/mastra/", diff --git a/docs/platforms/javascript/common/configuration/integrations/pi-durable.mdx b/docs/platforms/javascript/common/configuration/integrations/pi-durable.mdx new file mode 100644 index 0000000000000..96afeedc4e9d5 --- /dev/null +++ b/docs/platforms/javascript/common/configuration/integrations/pi-durable.mdx @@ -0,0 +1,156 @@ +--- +title: pi-durable +description: "Adds instrumentation for pi-durable. (default)" +supportedCategories: + - server + - serverless +notSupported: + - javascript.mastra +--- + + + +_Import name: `Sentry.piDurableIntegration`_ + +The `piDurableIntegration` adds instrumentation for [`@earendil-works/pi-durable`](https://www.npmjs.com/package/@earendil-works/pi-durable), Earendil's durable agent harness, to capture agent tracing `gen_ai` spans for agent runs, model requests, and tool calls. + + + +This integration is enabled by default when tracing is enabled. To customize it, see [Modifying Default Integrations](./../#modifying-default-integrations). + +```javascript +Sentry.init({ + dsn: "___PUBLIC_DSN___", + // Tracing must be enabled for agent tracing to work + tracesSampleRate: 1.0, + integrations: [Sentry.piDurableIntegration()], +}); +``` + + + + + +On Deno, preload Sentry's import hook so pi-durable can be instrumented: + +```bash +deno run --allow-net --allow-env --allow-read --allow-sys --allow-write --preload=npm:@sentry/deno/import app.ts +``` + + + + + + + +With the Node.js adapter, no build step is needed. The integration is enabled by default when tracing is enabled. + +On Bun, add `sentryBunPlugin()` to your build so the plugin can instrument the bundled pi-durable package: + + + + + +On Bun, add `sentryBunPlugin()` to your build so the plugin can instrument the bundled pi-durable package: + + + +```typescript {filename:build.ts} +import { sentryBunPlugin } from "@sentry/bun/plugin"; + +await Bun.build({ + entrypoints: ["./src/index.ts"], + outdir: "./dist", + target: "bun", + plugins: [sentryBunPlugin()], +}); +``` + +pi-durable must be part of the bundle. The plugin only runs during a build, so an application started with `bun run` without a build gets no pi-durable spans. + + + + + +On Cloudflare, the Sentry Cloudflare Vite plugin adds this integration when your Worker bundles pi-durable. This includes pi-durable in a Durable Object hosted by the Agents SDK `PiHarness`. You don't have to add the integration yourself. + +```typescript {filename:vite.config.mts} +import { cloudflare } from "@cloudflare/vite-plugin"; +import { sentryCloudflareVitePlugin } from "@sentry/cloudflare/vite"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [cloudflare(), sentryCloudflareVitePlugin()], +}); +``` + +Without the plugin, or with `buildTimeInstrumentation: false`, the SDK doesn't instrument pi-durable. To choose whether the SDK records prompts and responses, use the `dataCollection` option. + +pi-durable in the Agents SDK keeps its state in SQLite tables with the `pi_` prefix. Their statements don't create spans. See Durable Object SQL Spans. + + + +## Supported Operations + +- **Agent Runs** (`gen_ai.invoke_agent`): One span for each run. A run lasts until pi-durable settles the input of the conversation, so it covers every model request and tool round in between. +- **Model Requests** (`gen_ai.chat`): One span for each request that pi-ai sends, with the model, token usage, and finish reason. +- **Tool Calls** (`gen_ai.execute_tool`): One span for each tool call. The span records the result that the model receives, after `afterTool` hooks and output limits. + +Each run starts a new trace. pi-durable runs the work in background tasks, which can continue after a restart, so a run isn't part of the trace of the request that submitted the input. When a tool call creates a conversation for a subagent, the first run of that conversation is a child of the tool call span. + +All spans of a run get a `gen_ai.conversation.id` in the form `:`, so the runs of one conversation group in [Conversations](/product/agents/conversations/). The SDK creates a new harness ID each time `Harness.open()` runs. After a restart, a pi-durable conversation therefore continues with a new ID. + +## Captured Errors + +The integration captures: + +- Errors that a tool throws. pi-durable turns them into an error result for the model, so your code can't catch them. +- Errors that pi-durable passes to `onReport`, such as a hook that throws. If you pass your own `onReport`, the SDK still captures them and marks them as handled. +- Errors that a task phase throws. + +The SDK doesn't capture errors of the built-in coding tools (`bash`, `read`, `edit`, and `write`), because these tools throw for expected failures, such as a command that exits with a non-zero code. Their spans still get an error status. + +## Model Requests of Provider SDKs + +pi-ai sends its model requests through the `openai`, `@anthropic-ai/sdk`, and `@google/genai` clients, or on Cloudflare through the Workers AI binding. To report each request only once, the OpenAI, Anthropic, Google Gen AI, and Workers AI integrations stop creating spans from the first pi-durable model request on. This applies to the whole process, so model calls that your code makes with these clients outside of pi-durable also get no spans. + +The AWS integration still creates spans for Amazon Bedrock requests, so Sentry reports pi-durable model requests to Bedrock twice. + +## Supported Versions + +- `@earendil-works/pi-durable`: `>=1.0.0 <2.0.0` + + + +## Options + +### `recordInputs` + +_Type: `boolean` (optional)_ + +Records the system instructions, input messages, and tool definitions of model requests, and the arguments of tool calls. + +Defaults to `true` if `dataCollection.genAI.inputs` is `true`, which is the default. + +### `recordOutputs` + +_Type: `boolean` (optional)_ + +Records the output messages of model requests and the results of tool calls. + +Defaults to `true` if `dataCollection.genAI.outputs` is `true`, which is the default. + +```javascript +Sentry.init({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, + integrations: [ + Sentry.piDurableIntegration({ + recordInputs: false, + recordOutputs: false, + }), + ], +}); +``` + + diff --git a/docs/platforms/javascript/common/configuration/options.mdx b/docs/platforms/javascript/common/configuration/options.mdx index b9e04ff0d347e..4bfe0d401330d 100644 --- a/docs/platforms/javascript/common/configuration/options.mdx +++ b/docs/platforms/javascript/common/configuration/options.mdx @@ -576,6 +576,14 @@ Propagates trace context over every RPC call on `env`, including bindings whose + + +Names of Durable Object SQL tables whose statements create `db.query` spans, even though the name starts with a prefix for internal tables. By default, statements on tables with the `cf_` prefix (Agents SDK, PartyServer) or the `pi_` prefix (pi-durable in the Agents SDK `PiHarness`) create no spans. + +String entries must match a table name exactly. Use a regular expression for pattern matching, such as `/^pi_/` to see the statements of pi-durable. See Durable Object SQL Spans. + + + diff --git a/docs/platforms/javascript/guides/cloudflare/agent-tracing/agents-sdk.mdx b/docs/platforms/javascript/guides/cloudflare/agent-tracing/agents-sdk.mdx index 80d2712033b27..29532281ae3a6 100644 --- a/docs/platforms/javascript/guides/cloudflare/agent-tracing/agents-sdk.mdx +++ b/docs/platforms/javascript/guides/cloudflare/agent-tracing/agents-sdk.mdx @@ -30,6 +30,10 @@ export class MyAgent extends Agent { 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. +## pi-durable Runs + +If your agent hosts pi-durable with `PiHarness` from `agents/harness/pi`, the pi-durable integration traces its runs, model requests, and tool calls (SDK version 11.6.0 or higher). Each run is a separate trace with the conversation ID of pi-durable, so `Sentry.setConversationId()` in your agent doesn't apply to these spans. + ## Conversation IDs 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. diff --git a/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx b/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx index bb53123f46bc6..c6432da36414c 100644 --- a/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx +++ b/docs/platforms/javascript/guides/cloudflare/features/durableobject.mdx @@ -21,6 +21,27 @@ The SDK automatically instruments Durable Object storage operations (`get`, `put 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. +## Durable Object SQL Spans + +The SDK creates a `db.query` span for each statement that a SQLite-backed Durable Object runs with `ctx.storage.sql.exec()` (version 10.61.0 or higher). The span name is the query summary, such as `SELECT orders`. + +Frameworks built on Durable Objects keep their own state in SQLite tables, and a single request can run hundreds of statements against them. Statements on these tables don't create spans: + +- Tables with the `cf_` prefix, used by the Agents SDK and PartyServer (version 10.67.0 or higher) +- Tables with the `pi_` prefix, used by pi-durable in the Agents SDK `PiHarness` (version 11.6.0 or higher) + +A table of your own with one of these prefixes also gets no spans. To keep its spans, add it to `durableObjectSqlSpanAllowlist`. A string keeps the table with exactly that name, and a regular expression keeps every table whose name it matches. To see the statements of pi-durable, add `/^pi_/`: + +```typescript {filename:src/instrument.server.ts} +import * as Sentry from "@sentry/cloudflare"; + +export default Sentry.defineCloudflareOptions((env) => ({ + dsn: "___PUBLIC_DSN___", + tracesSampleRate: 1.0, + durableObjectSqlSpanAllowlist: ["cf_my_table", /^pi_/], +})); +``` + ## RPC Trace Propagation To enable distributed tracing across RPC calls to your Durable Objects, see Distributed Tracing. diff --git a/platform-includes/configuration/integrations/javascript.astro.mdx b/platform-includes/configuration/integrations/javascript.astro.mdx index 9d14eb2142664..e79d42460b0cf 100644 --- a/platform-includes/configuration/integrations/javascript.astro.mdx +++ b/platform-includes/configuration/integrations/javascript.astro.mdx @@ -94,6 +94,7 @@ Depending on whether an integration enhances the functionality of a particular r | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`firebaseIntegration`](./firebase/) | ✓ | | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.aws-lambda.mdx b/platform-includes/configuration/integrations/javascript.aws-lambda.mdx index ac3543690d0d9..294ee8e2a2548 100644 --- a/platform-includes/configuration/integrations/javascript.aws-lambda.mdx +++ b/platform-includes/configuration/integrations/javascript.aws-lambda.mdx @@ -27,6 +27,7 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`amqplibIntegration`](./amqplib/) | | | ✓ | | | [`anrIntegration`](./anr/) | | ✓ | | | | [`captureConsoleIntegration`](./captureconsole/) | | | | ✓ | diff --git a/platform-includes/configuration/integrations/javascript.bun.mdx b/platform-includes/configuration/integrations/javascript.bun.mdx index 8496fc44d2774..61ef60716cb06 100644 --- a/platform-includes/configuration/integrations/javascript.bun.mdx +++ b/platform-includes/configuration/integrations/javascript.bun.mdx @@ -39,6 +39,7 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`firebaseIntegration`](./firebase/) | ✓ | | ✓ | | | [`bunRuntimeMetricsIntegration`](./bunruntimemetrics/) | | | | ✓ | | [`captureConsoleIntegration`](./captureconsole/) | | | | ✓ | diff --git a/platform-includes/configuration/integrations/javascript.cloudflare.mdx b/platform-includes/configuration/integrations/javascript.cloudflare.mdx index 99a2952b3905b..966f154c62aa8 100644 --- a/platform-includes/configuration/integrations/javascript.cloudflare.mdx +++ b/platform-includes/configuration/integrations/javascript.cloudflare.mdx @@ -17,4 +17,6 @@ [Mistral AI](./mistral/) is automatically instrumented when built with the Sentry Cloudflare Vite plugin. Without the plugin, use `instrumentMistralAiClient`. +[pi-durable](./pi-durable/) is automatically instrumented when built with the Sentry Cloudflare Vite plugin. + The [`prismaIntegration`](./prisma/) needs the `nodejs_compat` compatibility flag on your Worker. diff --git a/platform-includes/configuration/integrations/javascript.deno.mdx b/platform-includes/configuration/integrations/javascript.deno.mdx index 187f4353e9937..9bc3aebf129c0 100644 --- a/platform-includes/configuration/integrations/javascript.deno.mdx +++ b/platform-includes/configuration/integrations/javascript.deno.mdx @@ -22,3 +22,4 @@ | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`mistralAIIntegration`](./mistral/) | ✓ | | ✓ | | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.fastify.mdx b/platform-includes/configuration/integrations/javascript.fastify.mdx index eeaf38e2bb06b..251d6b40232c1 100644 --- a/platform-includes/configuration/integrations/javascript.fastify.mdx +++ b/platform-includes/configuration/integrations/javascript.fastify.mdx @@ -39,6 +39,7 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`anrIntegration`](./anr/) | | ✓ | | | | [`captureConsoleIntegration`](./captureconsole/) | | | | ✓ | | [`eventLoopBlockIntegration`](./event-loop-block/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.gcp-functions.mdx b/platform-includes/configuration/integrations/javascript.gcp-functions.mdx index 461d95cdd4ff5..638d34852625e 100644 --- a/platform-includes/configuration/integrations/javascript.gcp-functions.mdx +++ b/platform-includes/configuration/integrations/javascript.gcp-functions.mdx @@ -27,6 +27,7 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`firebaseIntegration`](./firebase/) | ✓ | | ✓ | | | [`amqplibIntegration`](./amqplib/) | | | ✓ | | | [`anrIntegration`](./anr/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.hapi.mdx b/platform-includes/configuration/integrations/javascript.hapi.mdx index 7c15ac2ecb127..cd53bc49b036a 100644 --- a/platform-includes/configuration/integrations/javascript.hapi.mdx +++ b/platform-includes/configuration/integrations/javascript.hapi.mdx @@ -40,6 +40,7 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`anrIntegration`](./anr/) | | ✓ | | | | [`captureConsoleIntegration`](./captureconsole/) | | | | ✓ | | [`eventLoopBlockIntegration`](./event-loop-block/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.nestjs.mdx b/platform-includes/configuration/integrations/javascript.nestjs.mdx index b831a6cb44efd..d3941e2ba810f 100644 --- a/platform-includes/configuration/integrations/javascript.nestjs.mdx +++ b/platform-includes/configuration/integrations/javascript.nestjs.mdx @@ -53,5 +53,6 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.nextjs.mdx b/platform-includes/configuration/integrations/javascript.nextjs.mdx index ad2d5f4b61f67..d86588bbe1ce3 100644 --- a/platform-includes/configuration/integrations/javascript.nextjs.mdx +++ b/platform-includes/configuration/integrations/javascript.nextjs.mdx @@ -101,6 +101,7 @@ Depending on whether an integration enhances the functionality of a particular r | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.node.mdx b/platform-includes/configuration/integrations/javascript.node.mdx index e3ee76402e28b..737d10ba10e86 100644 --- a/platform-includes/configuration/integrations/javascript.node.mdx +++ b/platform-includes/configuration/integrations/javascript.node.mdx @@ -52,6 +52,7 @@ | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`firebaseIntegration`](./firebase/) | ✓ | | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.nuxt.mdx b/platform-includes/configuration/integrations/javascript.nuxt.mdx index dee5ac6b1717e..36fa2b7913d8e 100644 --- a/platform-includes/configuration/integrations/javascript.nuxt.mdx +++ b/platform-includes/configuration/integrations/javascript.nuxt.mdx @@ -94,5 +94,6 @@ Depending on whether an integration enhances the functionality of a particular r | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.remix.mdx b/platform-includes/configuration/integrations/javascript.remix.mdx index 80d9715cfff34..f3e7c678a2011 100644 --- a/platform-includes/configuration/integrations/javascript.remix.mdx +++ b/platform-includes/configuration/integrations/javascript.remix.mdx @@ -94,5 +94,6 @@ Depending on whether an integration enhances the functionality of a particular r | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.solidstart.mdx b/platform-includes/configuration/integrations/javascript.solidstart.mdx index 7d83ce9f33f21..6ec5aa7cbbe0c 100644 --- a/platform-includes/configuration/integrations/javascript.solidstart.mdx +++ b/platform-includes/configuration/integrations/javascript.solidstart.mdx @@ -94,5 +94,6 @@ Depending on whether an integration enhances the functionality of a particular r | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | | diff --git a/platform-includes/configuration/integrations/javascript.sveltekit.mdx b/platform-includes/configuration/integrations/javascript.sveltekit.mdx index c832017405940..aadd81355ff9c 100644 --- a/platform-includes/configuration/integrations/javascript.sveltekit.mdx +++ b/platform-includes/configuration/integrations/javascript.sveltekit.mdx @@ -94,5 +94,6 @@ Depending on whether an integration enhances the functionality of a particular r | [`groqIntegration`](./groq/) | ✓ | | ✓ | | | [`togetherAIIntegration`](./together-ai/) | ✓ | | ✓ | | | [`typesafeIntegration`](./typesafe/) | ✓ | | ✓ | | +| [`piDurableIntegration`](./pi-durable/) | ✓ | ✓ | ✓ | | | [`zodErrorsIntegration`](./zodErrors/) | | | | ✓ | | [`pinoIntegration`](./pino/) | | ✓ | | |