zidane 6.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/{acp-Irby04Us.js → acp-cfR8T19u.js} +8 -8
- package/dist/{acp-Irby04Us.js.map → acp-cfR8T19u.js.map} +1 -1
- package/dist/acp-cli.js +7 -7
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-DkSmGkDM.js → agent-DZRA7wip.js} +377 -61
- package/dist/agent-DZRA7wip.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{anthropic-CTHsdFG9.js → anthropic-DNJbRMUK.js} +7 -7
- package/dist/anthropic-DNJbRMUK.js.map +1 -0
- package/dist/atomic-write-B7zr1ddF.js.map +1 -1
- package/dist/{auth-BDSu_0t3.js → auth-B3cB5K6d.js} +7 -7
- package/dist/auth-B3cB5K6d.js.map +1 -0
- package/dist/cache-telemetry-BKAwsNxm.js.map +1 -1
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +3 -3
- package/dist/chat.d.ts +44 -21
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +7 -7
- package/dist/chat.js.map +1 -1
- package/dist/completion-core-CXYSVhZo.js.map +1 -1
- package/dist/context-breakdown-Dzo25N45.js.map +1 -1
- package/dist/contexts/daytona.d.ts +3 -1
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +2 -2
- package/dist/contexts/daytona.js.map +1 -1
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js +2 -2
- package/dist/contexts/docker.js.map +1 -1
- package/dist/contexts/e2b.d.ts +3 -1
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +1 -1
- package/dist/contexts/e2b.js.map +1 -1
- package/dist/{contexts-Vone3qQQ.js → contexts-BIbcfBFH.js} +2 -2
- package/dist/contexts-BIbcfBFH.js.map +1 -0
- package/dist/contexts.js +1 -1
- package/dist/edit-utils-EGosADZq.js.map +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +4 -3
- package/dist/eval.js.map +1 -1
- package/dist/exec-file-size-PXkr-MGA.js.map +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{fetch-url-CWE8X5OD.js → fetch-url-_5WKWpbQ.js} +2 -2
- package/dist/{fetch-url-CWE8X5OD.js.map → fetch-url-_5WKWpbQ.js.map} +1 -1
- package/dist/{format-BNOXpl-1.js → format-BF745pLL.js} +9 -2
- package/dist/format-BF745pLL.js.map +1 -0
- package/dist/generate-data-WL_yGVL6.js.map +1 -1
- package/dist/hash-DJRzmcPI.js.map +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +4 -4
- package/dist/headless.js.map +1 -1
- package/dist/{index-B8UtiZy7.d.ts → index-BGpM2YaU.d.ts} +378 -5
- package/dist/index-BGpM2YaU.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/logger-DBX9uYOw.js.map +1 -1
- package/dist/{login-DOF8pMVM.js → login-DZLG__2f.js} +4 -3
- package/dist/{login-DOF8pMVM.js.map → login-DZLG__2f.js.map} +1 -1
- package/dist/mcp-CcvuVXB9.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/media-sniff-Bn76JxAu.js.map +1 -1
- package/dist/{messages-CwujiS74.js → messages-C5BDOjUG.js} +2 -2
- package/dist/{messages-CwujiS74.js.map → messages-C5BDOjUG.js.map} +1 -1
- package/dist/oauth-8LqbeI_Q.js.map +1 -1
- package/dist/{openai-compat-BvgYGSR1.js → openai-compat-B0kqvZqN.js} +2 -2
- package/dist/openai-compat-B0kqvZqN.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/output/terminal.js +1 -1
- package/dist/output/terminal.js.map +1 -1
- package/dist/output-cap-kBUHBlnq.js.map +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.js +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +2 -2
- package/dist/providers/baseten.js.map +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +8 -8
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +1 -1
- package/dist/{providers-z6LDMAr3.js → providers-BMlrTr6a.js} +3 -3
- package/dist/{providers-z6LDMAr3.js.map → providers-BMlrTr6a.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +4 -4
- package/dist/read-state-Dq_TXUX1.js.map +1 -1
- package/dist/{resolve-Cr8JSL_O.js → resolve-CC8Lmwcj.js} +3 -3
- package/dist/{resolve-Cr8JSL_O.js.map → resolve-CC8Lmwcj.js.map} +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js.map +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +75 -20
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-CsdDIPY8.js → session-CsKzK8-P.js} +3 -3
- package/dist/session-CsKzK8-P.js.map +1 -0
- package/dist/session.d.ts +2 -2
- package/dist/session.js +2 -2
- package/dist/{skills-Bsb0rvWI.js → skills-BjeXSRlQ.js} +2 -2
- package/dist/{skills-Bsb0rvWI.js.map → skills-BjeXSRlQ.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -2
- package/dist/stdio-loader-Ce68wUmM.js.map +1 -1
- package/dist/{tool-formatters-DY0TDb1r.d.ts → tool-formatters-CMwjDvkp.d.ts} +2 -2
- package/dist/tool-formatters-CMwjDvkp.d.ts.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools/web-search.js +1 -1
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +2 -2
- package/dist/{transcript-anchors-DSRPWjiH.js → transcript-anchors-BTNe1OJi.js} +346 -89
- package/dist/transcript-anchors-BTNe1OJi.js.map +1 -0
- package/dist/{transcript-anchors-Cb-bDbNH.d.ts → transcript-anchors-D5wvdKQQ.d.ts} +37 -3
- package/dist/transcript-anchors-D5wvdKQQ.d.ts.map +1 -0
- package/dist/tui.d.ts +21 -6
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +497 -83
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-Dq9Kx7m2.js → turn-operations-CEt_l3fy.js} +23 -8
- package/dist/turn-operations-CEt_l3fy.js.map +1 -0
- package/dist/{turn-operations-CgMROLsr.d.ts → turn-operations-JO5MYM9_.d.ts} +27 -9
- package/dist/turn-operations-JO5MYM9_.d.ts.map +1 -0
- package/dist/types-BIarq1qE.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/{xai-B_e6TOA8.js → xai-C_aq671K.js} +3 -3
- package/dist/{xai-B_e6TOA8.js.map → xai-C_aq671K.js.map} +1 -1
- package/docs/ARCHITECTURE.md +4 -0
- package/docs/CHAT.md +12 -10
- package/docs/SKILL.md +1 -1
- package/docs/TUI.md +3 -3
- package/package.json +2 -2
- package/dist/agent-DkSmGkDM.js.map +0 -1
- package/dist/anthropic-CTHsdFG9.js.map +0 -1
- package/dist/auth-BDSu_0t3.js.map +0 -1
- package/dist/contexts-Vone3qQQ.js.map +0 -1
- package/dist/format-BNOXpl-1.js.map +0 -1
- package/dist/index-B8UtiZy7.d.ts.map +0 -1
- package/dist/openai-compat-BvgYGSR1.js.map +0 -1
- package/dist/session-CsdDIPY8.js.map +0 -1
- package/dist/tool-formatters-DY0TDb1r.d.ts.map +0 -1
- package/dist/transcript-anchors-Cb-bDbNH.d.ts.map +0 -1
- package/dist/transcript-anchors-DSRPWjiH.js.map +0 -1
- package/dist/turn-operations-CgMROLsr.d.ts.map +0 -1
- package/dist/turn-operations-Dq9Kx7m2.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["prefixed"],"sources":["../src/behaviors/local-reliability.ts","../src/metrics.ts","../src/mutation-validation.ts","../src/tracing.ts"],"sourcesContent":["import type { AgentBehavior } from '../types'\n\nconst DEFAULT_LOCAL_RELIABILITY: AgentBehavior = {\n maxConcurrentTools: 3,\n readFileDefaults: {\n limit: 400,\n maxBytes: 64 * 1024,\n },\n toolOutputBudget: 32 * 1024,\n textToolCallRescue: { mode: 'steer' },\n thinkingOverrunPolicy: {\n mode: 'steer-next-turn',\n thresholdTokens: 2048,\n },\n}\n\n/**\n * Opt-in behavior overlay for brittle/local OpenAI-compatible endpoints.\n * Returns plain `AgentBehavior` so hosts can spread it before or after their\n * own overrides; no built-in profile uses this helper by default.\n */\nexport function localReliabilityBehavior(overrides: AgentBehavior = {}): AgentBehavior {\n return {\n ...DEFAULT_LOCAL_RELIABILITY,\n ...overrides,\n readFileDefaults: {\n ...DEFAULT_LOCAL_RELIABILITY.readFileDefaults,\n ...(overrides.readFileDefaults ?? {}),\n },\n textToolCallRescue: overrides.textToolCallRescue ?? DEFAULT_LOCAL_RELIABILITY.textToolCallRescue,\n thinkingOverrunPolicy: overrides.thinkingOverrunPolicy ?? DEFAULT_LOCAL_RELIABILITY.thinkingOverrunPolicy,\n }\n}\n","/**\n * Metrics helper — wraps agent lifecycle hooks in caller-provided meters.\n *\n * Symmetric with {@link createTracingHooks} from `./tracing`. Where the\n * tracer answers \"what happened in this run?\" by producing spans, the\n * metrics helper answers \"how is the fleet behaving?\" by emitting\n * counters / histograms / up-down counters. Both are tracer-agnostic —\n * the caller supplies a `Meter` (OTel-API-shaped) and the helper plugs\n * the right hook on each metric.\n *\n * Instrument families:\n *\n * ### Histograms (distribution metrics)\n * - `gen_ai.client.operation.duration` (ms) — wall-clock per turn (`turn:before` → `turn:after`).\n * - `gen_ai.client.token.usage` — `input` / `output` token counts per turn (tagged by `gen_ai.token.type`).\n * - `gen_ai.client.time_to_first_token` (ms) — per-turn TTFT from `TurnUsage.timeToFirstTokenMs`.\n * - `gen_ai.tool.duration` (ms) — native tool execution time (`tool:before` → `tool:after`).\n * - `gen_ai.tool.output_bytes` — `tool:after.outputBytes`.\n * - `gen_ai.mcp.tool.duration` (ms) — MCP tool execution time.\n * - `gen_ai.mcp.bootstrap.duration` (ms) — MCP server bootstrap (already measured by harness).\n *\n * ### Counters (monotonic)\n * - `gen_ai.agent.runs` — `agent:start`.\n * - `gen_ai.agent.runs.completed` — `agent:done`.\n * - `gen_ai.agent.aborts` — `agent:abort`.\n * - `gen_ai.tool.calls` — `tool:dispatched` (tagged by `outcome`).\n * - `gen_ai.tool.errors` — `tool:error`.\n * - `gen_ai.mcp.tool.errors` — `mcp:tool:error`.\n * - `gen_ai.stream.errors` — `stream:error` (tagged by `status_code`).\n * - `gen_ai.validation.rejects` — `validation:reject`.\n * - `gen_ai.validation.coercions` — `validation:coerce`.\n * - `gen_ai.gate.blocks` — `tool:dispatched` outcome `gate-block`.\n * - `gen_ai.budget.exceeded` — `budget:exceeded`.\n * - `gen_ai.tool_budget.exceeded` — `tool-budget:exceeded` (tagged by `mode`).\n * - `gen_ai.pairing.repairs` — `pairing:repair` (tagged by `mode`).\n * - `gen_ai.oauth.refreshes` — `oauth:refresh`.\n * - `gen_ai.mcp.errors` — `mcp:error`.\n * - `gen_ai.mcp.auth.required` — `mcp:auth:required`.\n * - `gen_ai.cost_usd` — accumulated cost (added on `turn:after`).\n *\n * ### Up-down counter (gauge-shaped)\n * - `gen_ai.agent.runs.active` — incremented on `agent:start`, decremented on `agent:done`.\n *\n * The `Meter` shape mirrors `@opentelemetry/api`'s `Meter` exactly — passing\n * `metrics.getMeter('zidane')` works directly. Hosts using a different\n * metrics backend (StatsD, Prometheus client, custom in-memory aggregator)\n * implement the same three factory methods and the helper plugs in\n * unchanged.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\n\n// ---------------------------------------------------------------------------\n// OTel-shaped Meter interface\n// ---------------------------------------------------------------------------\n\nexport type MetricAttributes = Record<string, string | number | boolean | undefined>\n\nexport interface Counter {\n add: (value: number, attributes?: MetricAttributes) => void\n}\n\nexport interface Histogram {\n record: (value: number, attributes?: MetricAttributes) => void\n}\n\nexport interface UpDownCounter {\n add: (value: number, attributes?: MetricAttributes) => void\n}\n\nexport interface InstrumentOptions {\n description?: string\n unit?: string\n}\n\n/**\n * Minimal Meter interface — structurally identical to OTel's `Meter`.\n * Hosts passing `metrics.getMeter(name)` (from `@opentelemetry/api`)\n * satisfy this without adaptation.\n */\nexport interface Meter {\n createCounter: (name: string, options?: InstrumentOptions) => Counter\n createHistogram: (name: string, options?: InstrumentOptions) => Histogram\n createUpDownCounter: (name: string, options?: InstrumentOptions) => UpDownCounter\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface MetricsHooksOptions {\n meter: Meter\n /**\n * Optional prefix prepended to every instrument name. Default: no prefix\n * (instrument names follow OTel Gen AI semantic conventions verbatim,\n * which is the most-portable shape). Set to e.g. `'zidane.'` to\n * namespace inside a shared meter registry.\n */\n namespace?: string\n /**\n * Optional baseline attributes applied to every measurement. Typical\n * use: `{ service: 'tui', env: 'prod' }`. Per-event attributes win on\n * key collision.\n */\n baseAttributes?: MetricAttributes\n /**\n * Error sink for meter failures. The helper still swallows the throw\n * so a broken backend can't crash a run; this callback surfaces the\n * failure for ops dashboards.\n */\n onError?: (kind: string, err: unknown) => void\n}\n\nexport interface MetricsHookSet {\n install: (hooks: Hookable<AgentHooks>) => () => void\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction prefixed(prefix: string | undefined, name: string): string {\n return prefix ? `${prefix}${name}` : name\n}\n\n/**\n * Drop `undefined` entries before handing attributes to a metrics\n * backend. OTel's `@opentelemetry/api` rejects `undefined` attribute\n * values (and Prometheus / StatsD adapters silently mis-label them); the\n * helper's own API surface allows `undefined` for ergonomic call sites\n * (`{...(cond ? { foo } : {})}`-style spreads), so we strip here at the\n * boundary.\n */\nfunction mergeAttrs(\n base: MetricAttributes | undefined,\n extra: MetricAttributes,\n): Record<string, string | number | boolean> {\n const out: Record<string, string | number | boolean> = {}\n if (base) {\n for (const [k, v] of Object.entries(base)) {\n if (v !== undefined)\n out[k] = v\n }\n }\n for (const [k, v] of Object.entries(extra)) {\n if (v !== undefined)\n out[k] = v\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// createMetricsHooks\n// ---------------------------------------------------------------------------\n\n/**\n * Build a set of metrics hook handlers that can be installed on an agent.\n *\n * @example OpenTelemetry\n * ```ts\n * import { metrics } from '@opentelemetry/api'\n * const meter = metrics.getMeter('zidane')\n * const m = createMetricsHooks({ meter, baseAttributes: { service: 'tui' } })\n * const uninstall = m.install(agent.hooks)\n * try { await agent.run({ prompt }) }\n * finally { uninstall() }\n * ```\n */\nexport function createMetricsHooks(options: MetricsHooksOptions): MetricsHookSet {\n const ns = options.namespace\n const base = options.baseAttributes\n const onError = options.onError ?? (() => {})\n\n const make = {\n counter: (name: string, opts?: InstrumentOptions) =>\n safeFactory(() => options.meter.createCounter(prefixed(ns, name), opts), name, onError),\n histogram: (name: string, opts?: InstrumentOptions) =>\n safeFactory(() => options.meter.createHistogram(prefixed(ns, name), opts), name, onError),\n upDown: (name: string, opts?: InstrumentOptions) =>\n safeFactory(() => options.meter.createUpDownCounter(prefixed(ns, name), opts), name, onError),\n }\n\n // Instruments — created once at install time.\n const turnDuration = make.histogram('gen_ai.client.operation.duration', { unit: 'ms', description: 'Per-turn LLM operation duration.' })\n const tokenUsage = make.histogram('gen_ai.client.token.usage', { unit: 'tokens', description: 'Per-turn token usage (tagged by gen_ai.token.type).' })\n const ttft = make.histogram('gen_ai.client.time_to_first_token', { unit: 'ms', description: 'Per-turn time to first token.' })\n const toolDuration = make.histogram('gen_ai.tool.duration', { unit: 'ms', description: 'Native tool execution wall clock.' })\n const toolOutput = make.histogram('gen_ai.tool.output_bytes', { unit: 'By', description: 'Native tool output bytes.' })\n const mcpToolDuration = make.histogram('gen_ai.mcp.tool.duration', { unit: 'ms', description: 'MCP tool execution wall clock.' })\n const mcpBootstrapDuration = make.histogram('gen_ai.mcp.bootstrap.duration', { unit: 'ms', description: 'MCP server bootstrap duration.' })\n\n const runsStarted = make.counter('gen_ai.agent.runs', { description: 'Runs started.' })\n const runsCompleted = make.counter('gen_ai.agent.runs.completed', { description: 'Runs completed.' })\n const aborts = make.counter('gen_ai.agent.aborts', { description: 'Run abort events.' })\n const toolCalls = make.counter('gen_ai.tool.calls', { description: 'Tool dispatches (tagged by outcome).' })\n const toolErrors = make.counter('gen_ai.tool.errors', { description: 'Native tool errors.' })\n const mcpToolErrors = make.counter('gen_ai.mcp.tool.errors', { description: 'MCP tool errors.' })\n const streamErrors = make.counter('gen_ai.stream.errors', { description: 'Provider stream errors.' })\n const validationRejects = make.counter('gen_ai.validation.rejects', { description: 'Tool input validation rejects.' })\n const validationCoercions = make.counter('gen_ai.validation.coercions', { description: 'Tool input auto-coercions.' })\n const gateBlocks = make.counter('gen_ai.gate.blocks', { description: 'Tool-gate refusals.' })\n const budgetExceeded = make.counter('gen_ai.budget.exceeded', { description: 'Per-turn byte budget exceedances.' })\n const toolBudgetExceeded = make.counter('gen_ai.tool_budget.exceeded', { description: 'Per-tool dispatch budget exceedances.' })\n const pairingRepairs = make.counter('gen_ai.pairing.repairs', { description: 'Tool-pairing repair counts.' })\n const oauthRefreshes = make.counter('gen_ai.oauth.refreshes', { description: 'Provider OAuth credential refreshes.' })\n const mcpErrors = make.counter('gen_ai.mcp.errors', { description: 'MCP server errors.' })\n const mcpAuthRequired = make.counter('gen_ai.mcp.auth.required', { description: 'MCP bootstrap blocked on missing auth.' })\n const costMeter = make.counter('gen_ai.cost_usd', { unit: 'USD', description: 'Cumulative cost across turns.' })\n\n const runsActive = make.upDown('gen_ai.agent.runs.active', { description: 'In-flight agent runs.' })\n\n return {\n install(hooks: Hookable<AgentHooks>): () => void {\n // Per-instrument book-keeping. Each map tracks instrument start times\n // keyed by the identifier that distinguishes concurrent in-flight\n // instances of that kind.\n const turnStart = new Map<string, number>() // turnId -> startedAt\n const toolStart = new Map<string, number>() // callId -> startedAt\n const mcpStart = new Map<string, number>() // callId -> startedAt\n\n const unregisters: Array<() => void> = []\n\n const record = <T extends { record: (v: number, a?: MetricAttributes) => void }>(\n instrument: T | undefined,\n value: number,\n attrs: MetricAttributes,\n kind: string,\n ): void => {\n if (!instrument)\n return\n try {\n instrument.record(value, mergeAttrs(base, attrs))\n }\n catch (err) {\n try {\n onError(kind, err)\n }\n catch { /* ignore */ }\n }\n }\n\n const add = <T extends { add: (v: number, a?: MetricAttributes) => void }>(\n instrument: T | undefined,\n value: number,\n attrs: MetricAttributes,\n kind: string,\n ): void => {\n if (!instrument)\n return\n try {\n instrument.add(value, mergeAttrs(base, attrs))\n }\n catch (err) {\n try {\n onError(kind, err)\n }\n catch { /* ignore */ }\n }\n }\n\n // ---- Agent lifecycle --------------------------------------------\n\n unregisters.push(hooks.hook('agent:start', (ctx) => {\n const attrs: MetricAttributes = {\n 'gen_ai.agent.depth': ctx.depth,\n ...(ctx.agentName ? { 'gen_ai.agent.name': ctx.agentName } : {}),\n }\n add(runsStarted, 1, attrs, 'runs')\n add(runsActive, 1, attrs, 'runs.active')\n }))\n\n unregisters.push(hooks.hook('agent:done', () => {\n add(runsCompleted, 1, {}, 'runs.completed')\n add(runsActive, -1, {}, 'runs.active')\n }))\n\n unregisters.push(hooks.hook('agent:abort', () => {\n add(aborts, 1, {}, 'aborts')\n }))\n\n // ---- Turn / stream metrics -------------------------------------\n\n unregisters.push(hooks.hook('turn:before', (ctx) => {\n turnStart.set(ctx.turnId, Date.now())\n }))\n\n unregisters.push(hooks.hook('turn:after', (ctx) => {\n const started = turnStart.get(ctx.turnId)\n turnStart.delete(ctx.turnId)\n const tagsBase: MetricAttributes = {\n 'gen_ai.operation.name': 'chat',\n ...(ctx.usage.modelId ? { 'gen_ai.response.model': ctx.usage.modelId } : {}),\n ...(ctx.usage.finishReason ? { 'gen_ai.response.finish_reason': ctx.usage.finishReason } : {}),\n }\n if (typeof started === 'number')\n record(turnDuration, Date.now() - started, tagsBase, 'turn.duration')\n if (typeof ctx.usage.timeToFirstTokenMs === 'number')\n record(ttft, ctx.usage.timeToFirstTokenMs, tagsBase, 'ttft')\n\n record(tokenUsage, ctx.usage.input, { ...tagsBase, 'gen_ai.token.type': 'input' }, 'token.input')\n record(tokenUsage, ctx.usage.output, { ...tagsBase, 'gen_ai.token.type': 'output' }, 'token.output')\n if (typeof ctx.usage.cacheRead === 'number' && ctx.usage.cacheRead > 0)\n record(tokenUsage, ctx.usage.cacheRead, { ...tagsBase, 'gen_ai.token.type': 'cache_read' }, 'token.cache_read')\n if (typeof ctx.usage.cacheCreation === 'number' && ctx.usage.cacheCreation > 0)\n record(tokenUsage, ctx.usage.cacheCreation, { ...tagsBase, 'gen_ai.token.type': 'cache_creation' }, 'token.cache_creation')\n\n if (typeof ctx.usage.cost === 'number' && ctx.usage.cost > 0)\n add(costMeter, ctx.usage.cost, tagsBase, 'cost')\n }))\n\n unregisters.push(hooks.hook('stream:error', (ctx) => {\n add(streamErrors, 1, {\n 'http.response.status_code': ctx.statusCode,\n 'error.type': ctx.err instanceof Error ? ctx.err.name : 'unknown',\n }, 'stream.error')\n }))\n\n // ---- Native tool metrics ---------------------------------------\n\n unregisters.push(hooks.hook('tool:before', (ctx) => {\n toolStart.set(ctx.callId, Date.now())\n }))\n\n unregisters.push(hooks.hook('tool:after', (ctx) => {\n const started = toolStart.get(ctx.callId)\n toolStart.delete(ctx.callId)\n const tags: MetricAttributes = { 'gen_ai.tool.name': ctx.name }\n if (typeof started === 'number')\n record(toolDuration, Date.now() - started, tags, 'tool.duration')\n record(toolOutput, ctx.outputBytes, tags, 'tool.output_bytes')\n }))\n\n // NOTE: `tool:error` must NOT delete `toolStart[callId]` — on the\n // execute-error path the loop still fires `tool:after` afterwards\n // (with the `Tool error: …` payload), and that's where the errored\n // call's duration gets recorded + the entry cleaned up.\n unregisters.push(hooks.hook('tool:error', (ctx) => {\n add(toolErrors, 1, {\n 'gen_ai.tool.name': ctx.name,\n 'error.type': ctx.error.name,\n }, 'tool.errors')\n }))\n\n // Mid-flight per-call cancels close with `tool:cancelled` instead of\n // `tool:after` — clean up the start entry here or it leaks.\n unregisters.push(hooks.hook('tool:cancelled', (ctx) => {\n toolStart.delete(ctx.callId)\n }))\n\n unregisters.push(hooks.hook('tool:dispatched', (ctx) => {\n add(toolCalls, 1, {\n 'gen_ai.tool.name': ctx.name,\n 'outcome': ctx.outcome,\n }, 'tool.calls')\n if (ctx.outcome === 'gate-block') {\n add(gateBlocks, 1, {\n 'gen_ai.tool.name': ctx.name,\n ...(ctx.reason ? { reason: ctx.reason } : {}),\n }, 'gate.blocks')\n }\n // Unknown-tool dispatches fire `tool:before` (with `unknown: true`)\n // but never `tool:after` — drop the start entry so hallucinated\n // tool names can't grow the map unboundedly. `tool:dispatched` for\n // real executions fires BEFORE `tool:before`, so this only affects\n // the unknown path.\n if (ctx.outcome === 'unknown')\n toolStart.delete(ctx.callId)\n }))\n\n unregisters.push(hooks.hook('validation:reject', (ctx) => {\n add(validationRejects, 1, { 'gen_ai.tool.name': ctx.name }, 'validation.rejects')\n }))\n\n unregisters.push(hooks.hook('validation:coerce', (ctx) => {\n add(validationCoercions, 1, {\n 'gen_ai.tool.name': ctx.name,\n 'coercions': ctx.coercions.length,\n }, 'validation.coercions')\n }))\n\n unregisters.push(hooks.hook('budget:exceeded', (ctx) => {\n add(budgetExceeded, 1, {\n bytes: ctx.bytes,\n budget: ctx.budget,\n }, 'budget.exceeded')\n }))\n\n unregisters.push(hooks.hook('tool-budget:exceeded', (ctx) => {\n add(toolBudgetExceeded, 1, {\n 'gen_ai.tool.name': ctx.tool,\n 'mode': ctx.mode,\n 'count': ctx.count,\n 'max': ctx.max,\n }, 'tool_budget.exceeded')\n }))\n\n unregisters.push(hooks.hook('pairing:repair', (ctx) => {\n add(pairingRepairs, 1, { mode: ctx.mode }, 'pairing.repairs')\n }))\n\n unregisters.push(hooks.hook('oauth:refresh', (ctx) => {\n add(oauthRefreshes, 1, { provider: ctx.provider, source: ctx.source }, 'oauth.refreshes')\n }))\n\n // ---- MCP metrics -----------------------------------------------\n\n unregisters.push(hooks.hook('mcp:tool:before', (ctx) => {\n mcpStart.set(ctx.callId, Date.now())\n }))\n\n unregisters.push(hooks.hook('mcp:tool:after', (ctx) => {\n const started = mcpStart.get(ctx.callId)\n mcpStart.delete(ctx.callId)\n const tags: MetricAttributes = {\n 'gen_ai.mcp.server': ctx.server,\n 'gen_ai.tool.name': ctx.displayName,\n }\n if (typeof started === 'number')\n record(mcpToolDuration, Date.now() - started, tags, 'mcp.tool.duration')\n }))\n\n unregisters.push(hooks.hook('mcp:tool:error', (ctx) => {\n mcpStart.delete(ctx.callId)\n add(mcpToolErrors, 1, {\n 'gen_ai.mcp.server': ctx.server,\n 'gen_ai.tool.name': ctx.displayName,\n 'error.type': ctx.error.name,\n }, 'mcp.tool.errors')\n }))\n\n unregisters.push(hooks.hook('mcp:bootstrap:end', (ctx) => {\n record(mcpBootstrapDuration, ctx.durationMs, {\n 'gen_ai.mcp.server': ctx.name,\n 'ok': ctx.ok,\n }, 'mcp.bootstrap.duration')\n }))\n\n unregisters.push(hooks.hook('mcp:error', (ctx) => {\n add(mcpErrors, 1, {\n 'gen_ai.mcp.server': ctx.name,\n 'error.type': ctx.error.name,\n }, 'mcp.errors')\n }))\n\n unregisters.push(hooks.hook('mcp:auth:required', (ctx) => {\n add(mcpAuthRequired, 1, {\n 'gen_ai.mcp.server': ctx.name,\n 'transport': ctx.transport,\n 'reason': ctx.reason,\n }, 'mcp.auth.required')\n }))\n\n // -----------------------------------------------------------------\n // Disposal\n // -----------------------------------------------------------------\n\n let disposed = false\n return function uninstall() {\n if (disposed)\n return\n disposed = true\n for (const un of unregisters) {\n try {\n un()\n }\n catch { /* ignore */ }\n }\n turnStart.clear()\n toolStart.clear()\n mcpStart.clear()\n }\n },\n }\n}\n\n/**\n * Defensive factory wrapper — returns undefined when meter creation\n * throws. Lets a half-broken meter (one unsupported instrument) still\n * give partial metrics rather than collapsing the whole install.\n */\nfunction safeFactory<T>(\n factory: () => T,\n name: string,\n onError: (kind: string, err: unknown) => void,\n): T | undefined {\n try {\n return factory()\n }\n catch (err) {\n try {\n onError(`createInstrument:${name}`, err)\n }\n catch { /* ignore */ }\n return undefined\n }\n}\n","import type { AgentHookMap } from './agent'\nimport type { ToolOutcome, ToolResultContent } from './types'\n\ntype MaybePromise<T> = T | Promise<T>\n\nexport type SuccessfulMutationOutcome = Extract<ToolOutcome, 'created' | 'updated' | 'edited'>\n\nexport interface MutationValidationMutation {\n turnId: string\n callId: string\n tool: string\n displayName: string\n input: Record<string, unknown>\n outcome: SuccessfulMutationOutcome\n result: string | ToolResultContent[]\n}\n\nexport interface MutationValidationBatch {\n turnId: string\n mutations: readonly MutationValidationMutation[]\n}\n\nexport type MutationValidationResult\n = | { ok: true }\n | { ok: false, message?: string, errors?: readonly string[] }\n\nexport interface MutationValidationFailure {\n batch: MutationValidationBatch\n result: Extract<MutationValidationResult, { ok: false }>\n message: string\n failureCount: number\n}\n\nexport interface MutationValidationHooksOptions {\n validate: (batch: MutationValidationBatch) => MaybePromise<MutationValidationResult | void>\n /**\n * Called when validation fails and the run has not crossed\n * `maxFailuresPerRun`. Hosts typically call `agent.followUp(message)` here.\n */\n onFailure?: (failure: MutationValidationFailure) => MaybePromise<void>\n buildFailureMessage?: (failure: Omit<MutationValidationFailure, 'message'>) => string\n onError?: (error: unknown, batch: MutationValidationBatch) => MaybePromise<void>\n maxFailuresPerRun?: number\n}\n\nfunction defaultFailureMessage(failure: Omit<MutationValidationFailure, 'message'>): string {\n const changed = failure.batch.mutations\n .map(m => `${m.displayName} ${String(m.input.path ?? m.callId)}`)\n .join(', ')\n const details = failure.result.message\n ?? failure.result.errors?.join('\\n')\n ?? 'Validation failed after the last file mutation.'\n const seen = failure.failureCount > 1 ? ` (failure ${failure.failureCount})` : ''\n return `[Mutation validation failed${seen}] ${changed}\\n${details}\\nFix the validation errors with the smallest focused change.`\n}\n\nfunction isSuccessfulMutation(outcome: ToolOutcome | undefined): outcome is SuccessfulMutationOutcome {\n return outcome === 'created' || outcome === 'updated' || outcome === 'edited'\n}\n\n/**\n * Build host-side hooks for post-mutation validation without changing the\n * built-in edit/write tools. The helper only observes successful mutations\n * reported through `tool:after.outcome`; validation commands and recovery\n * prompts remain host policy.\n */\nexport function createMutationValidationHooks(options: MutationValidationHooksOptions): AgentHookMap {\n const pending: MutationValidationMutation[] = []\n let failureCount = 0\n const maxFailures = Math.max(1, Math.floor(options.maxFailuresPerRun ?? 2))\n\n return {\n 'tool:after': (ctx) => {\n if (!isSuccessfulMutation(ctx.outcome))\n return\n pending.push({\n turnId: ctx.turnId,\n callId: ctx.callId,\n tool: ctx.name,\n displayName: ctx.displayName,\n input: ctx.input,\n outcome: ctx.outcome,\n result: ctx.result,\n })\n },\n 'tool-results:after': async (ctx) => {\n if (pending.length === 0)\n return\n const mutations = pending.splice(0)\n const batch: MutationValidationBatch = {\n turnId: ctx.turnId,\n mutations,\n }\n let result: MutationValidationResult | void\n try {\n result = await options.validate(batch)\n }\n catch (err) {\n await options.onError?.(err, batch)\n return\n }\n if (!result || result.ok)\n return\n failureCount++\n if (failureCount > maxFailures)\n return\n const withoutMessage = { batch, result, failureCount }\n const message = options.buildFailureMessage?.(withoutMessage)\n ?? defaultFailureMessage(withoutMessage)\n await options.onFailure?.({ ...withoutMessage, message })\n },\n 'agent:done': () => {\n pending.length = 0\n // `agent:done` fires at the end of every run, so resetting here gives\n // `maxFailuresPerRun` true per-run semantics even when this hook map is\n // registered at agent level and reused across runs.\n failureCount = 0\n },\n }\n}\n","/**\n * Tracing helper — wraps agent lifecycle hooks in caller-provided spans.\n *\n * Zidane is hooks-native; rather than introducing a plugin abstraction just for\n * observability, we ship a small helper that turns an arbitrary `startSpan`\n * function into a bundle of hook handlers. Works with Sentry, OpenTelemetry,\n * Datadog — any tracer that can hand back an object with an `end()` method.\n *\n * Attribute conventions follow the Sentry AI Agents spec (which itself\n * tracks OpenTelemetry Gen AI semconv v1.36, with a few divergences). The\n * `conventions` option lets callers pick `'sentry'` (default — Sentry's\n * exact keys), `'otel'` (vendor-neutral OTel 1.36), or `'both'` (emit\n * every variant for maximum portability).\n *\n * Span coverage:\n *\n * - `invoke_agent <name?>` — root span, opens on `agent:start`, closes on `agent:done`. Sentry op `gen_ai.invoke_agent`.\n * - `chat <model?>` — per-turn LLM call, opens on `turn:before`, closes on `turn:after`. Sentry op `gen_ai.chat`.\n * - `execute_tool <name>` — native tool execution, opens on `tool:before`, closes on `tool:after` / `tool:error`. Sentry op `gen_ai.execute_tool`.\n * - `execute_tool <server>.<name>` — MCP tool variant, same op. Tagged with `gen_ai.tool.type: 'extension'`.\n * - `handoff to <task>` — subagent handoff (parent→child), opens on `spawn:before`, closes on `spawn:complete` / `spawn:error`. Sentry op `gen_ai.handoff`.\n * Also injects parent trace context into the spawn carrier when `propagator` is configured.\n * - `mcp.bootstrap <server>` — server bootstrap, opens on `mcp:bootstrap:start`, closes on `mcp:bootstrap:end`. Zidane-specific (no Sentry op equivalent).\n *\n * Span events (not spans — recorded on the active span via `addEvent`):\n *\n * - `gen_ai.gate.block` — a `tool:gate` listener refused a call.\n * - `gen_ai.validation.reject` — tool input failed schema validation.\n * - `gen_ai.validation.coerce` — tool input was auto-coerced to satisfy the schema.\n * - `gen_ai.budget.exceeded` — byte budget exceeded (`budget:exceeded`).\n * - `gen_ai.tool_budget.exceeded` — per-tool dispatch cap exceeded.\n * - `gen_ai.pairing.repair` — pre-send pairing repair fired.\n * - `gen_ai.stream.error` — provider stream errored (carries `statusCode` / `requestId`).\n * - `gen_ai.mcp.auth.required` — MCP server bootstrap blocked on missing OAuth tokens.\n * - `gen_ai.oauth.refresh` — provider OAuth credentials refreshed.\n *\n * Attribute naming follows the Sentry AI Agents conventions\n * (https://develop.sentry.dev/sdk/telemetry/traces/modules/ai-agents/) by\n * default — which closely track OTel Gen AI semconv v1.36 with a few\n * intentional differences (`usage.input_tokens.cached` instead of\n * `usage.cache_read_input_tokens`, `cost.total_tokens` instead of\n * `usage.cost_usd`, seconds instead of ms for `time_to_first_token`).\n * Set `conventions: 'otel'` to emit only the vendor-neutral OTel keys, or\n * `'both'` to emit everything for maximum portability. Legacy attribute\n * names (`inputTokens`, `toolName`, `displayName`, …) are also emitted by\n * default for back-compat; set `legacyAttributes: false` to drop them.\n *\n * On `agent:done` or `uninstall()` it closes any spans still open (defensive —\n * normally all tool/turn spans have matching end hooks, but an abort\n * mid-execution can leave dangling ones).\n *\n * Returns an `install(hooks)` helper that registers every handler at once and\n * yields an `uninstall()` function for cleanup. Safe across multiple runs.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { SessionMessage } from './types'\n\n/** Minimal span shape — any tracer that provides these methods is compatible. */\nexport interface Span {\n /** Close the span. Called exactly once per span. */\n end: () => void\n /** Optional: attach additional attributes after the span is started (ignored if unsupported). */\n setAttributes?: (attrs: Record<string, unknown>) => void\n /**\n * Optional: record a structured event on the span. Used for non-span\n * occurrences (gate blocks, validation rejects, budget hits, pairing\n * repairs). Maps to OTel's `Span.addEvent` and Sentry's `addBreadcrumb`.\n * Tracers without an event surface should treat this as a no-op (the\n * helper falls back to `setAttributes` with an `event.*` key prefix).\n */\n addEvent?: (name: string, attrs?: Record<string, unknown>) => void\n}\n\n/**\n * Function that opens a span. Caller-provided so we stay tracer-agnostic.\n *\n * `parentContext` carries opaque trace metadata propagated from another\n * agent (typically a W3C `{ traceparent, tracestate }` carrier received on\n * `agent:start.tracingContext` after a parent agent's tracer injected it on\n * `spawn:before`). Implementations that integrate with OTel should extract\n * the carrier into a `Context` and use it as the parent when opening the\n * span; implementations that don't care about cross-agent linkage can\n * ignore the third argument entirely.\n */\nexport type StartSpan = (\n name: string,\n attrs?: Record<string, unknown>,\n parentContext?: Readonly<Record<string, string>>,\n) => Span\n\nexport type TracingConventions = 'sentry' | 'otel' | 'both'\n\nexport interface TracingHooksOptions {\n /** Tracer seam. Receives a span name + attributes; must return a `Span`. */\n startSpan: StartSpan\n /**\n * Optional attribute namespace. Prepended to every span name with a `/`\n * separator (e.g. `\"agent\"` → `agent/chat <model>`, `agent/execute_tool Bash`).\n *\n * Empty / undefined = no prefix.\n */\n namespace?: string\n /**\n * Which Gen-AI attribute conventions to emit.\n *\n * - `'sentry'` (default) — Sentry AI Agents conventions. Most common\n * choice — Sentry, Datadog AI, Honeycomb derived dashboards and\n * Langfuse all consume these.\n * - `'otel'` — vendor-neutral OpenTelemetry Gen AI semconv v1.36.\n * Diverges from Sentry on cache-token keys, cost keys, and TTFT unit.\n * - `'both'` — emit every variant. Doubles the per-span attribute\n * payload; pick when shipping to multiple backends with different\n * ingestion conventions.\n */\n conventions?: TracingConventions\n /**\n * Capture the actual prompt / completion text on spans\n * (`gen_ai.input.messages`, `gen_ai.output.messages`,\n * `gen_ai.system_instructions`, `gen_ai.tool.definitions`,\n * `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result`).\n *\n * Defaults to `true` (required for the Sentry AI Agents conversation\n * viewer). Full prompts and tool arguments can carry secrets and PII;\n * captured content flows through `redact`, so pair the default with a\n * redactor when payloads may hold secrets, or set `false` to keep all\n * content-shaped data in-process.\n */\n captureMessageContent?: boolean\n /**\n * Emit legacy attribute keys (`inputTokens`, `outputTokens`, `toolName`,\n * `displayName`, `finishReason`, `modelId`) alongside the new\n * `gen_ai.*` semconv keys. Defaults to `true` so existing dashboards\n * keep working. Set `false` once you've migrated all consumers off the\n * legacy names.\n */\n legacyAttributes?: boolean\n /**\n * Error sink for tracer failures. Replaces the historic silent-swallow.\n * Called when `Span.end()`, `setAttributes()`, `addEvent()`, or\n * `startSpan()` throws — so degraded tracers stay visible. The helper\n * still does not let tracer errors propagate into the agent loop.\n *\n * `kind` identifies which step failed (`'startSpan'`, `'end'`,\n * `'setAttributes'`, `'addEvent'`, `'redact'`, `'getActiveTraceContext'`).\n * Default: no-op (silent).\n */\n onError?: (kind: string, err: unknown) => void\n /**\n * Optional callback the helper invokes on `spawn:before` (after opening\n * the spawn span) to read the active trace context. Whatever it returns\n * is written into `ctx.tracingContext` and forwarded to the child's\n * `agent.run({ tracingContext })`. Typical use:\n *\n * ```ts\n * getActiveTraceContext: () => {\n * const carrier: Record<string, string> = {}\n * propagation.inject(context.active(), carrier)\n * return carrier\n * }\n * ```\n *\n * Returning `undefined` or an empty object leaves the carrier empty\n * and the child runs with no parent context. The helper's own\n * `propagator` is preferred over this when both are set (the\n * propagator runs inside the helper; this callback is the escape\n * hatch for hosts wanting full control).\n */\n getActiveTraceContext?: () => Readonly<Record<string, string>> | undefined\n /**\n * Optional in-process span redactor. When set, every potentially\n * sensitive string (tool input, tool result, system prompt) flows\n * through this fn before landing on a span attribute / event. Returning\n * the input unchanged is a no-op.\n *\n * Composes with the harness-wide `tracing:redact` hook: if a host has\n * already registered a hook handler that mutates `ctx.redacted`, the\n * tracer reuses that pipeline; setting `redact` here registers an extra\n * step that runs only for the tracer's attributes. The hook is the\n * canonical path; `redact` is the convenience surface for tracer-only\n * setups.\n */\n redact?: (kind: string, value: string, meta?: Readonly<Record<string, unknown>>) => string\n}\n\n/** Value returned by {@link createTracingHooks} — install entrypoint. */\nexport interface TracingHookSet {\n /**\n * Attach every hook handler to the given agent hooks instance.\n *\n * @returns an `uninstall` function that detaches every handler and closes any\n * still-open spans. Safe to call multiple times.\n */\n install: (hooks: Hookable<AgentHooks>) => () => void\n}\n\n// ---------------------------------------------------------------------------\n// Gen AI semantic-convention attribute keys\n// ---------------------------------------------------------------------------\n\n/**\n * Stable keys we emit unconditionally — present in BOTH Sentry and OTel\n * conventions with identical semantics, so no `conventions` branching is\n * needed at the call site.\n */\nconst GEN_AI = {\n system: 'gen_ai.system',\n operationName: 'gen_ai.operation.name',\n requestModel: 'gen_ai.request.model',\n responseModel: 'gen_ai.response.model',\n responseFinishReasons: 'gen_ai.response.finish_reasons',\n responseId: 'gen_ai.response.id',\n responseStreaming: 'gen_ai.response.streaming',\n responseTokensPerSecond: 'gen_ai.response.tokens_per_second',\n // Sentry uses seconds; OTel uses ms. We emit one or both based on `conventions`.\n responseTimeToFirstTokenSeconds: 'gen_ai.response.time_to_first_token',\n responseTimeToFirstTokenMs: 'gen_ai.client.time_to_first_token',\n // Usage — Sentry expects input_tokens to INCLUDE cached, with subkeys for cache slices.\n usageInputTokens: 'gen_ai.usage.input_tokens',\n usageOutputTokens: 'gen_ai.usage.output_tokens',\n usageTotalTokens: 'gen_ai.usage.total_tokens',\n // Sentry-specific cache keys.\n usageInputTokensCached: 'gen_ai.usage.input_tokens.cached',\n usageInputTokensCacheWrite: 'gen_ai.usage.input_tokens.cache_write',\n usageOutputTokensReasoning: 'gen_ai.usage.output_tokens.reasoning',\n // OTel cache keys (older / vendor-neutral).\n usageCacheReadInputTokens: 'gen_ai.usage.cache_read_input_tokens',\n usageCacheCreationInputTokens: 'gen_ai.usage.cache_creation_input_tokens',\n usageReasoningTokens: 'gen_ai.usage.reasoning_tokens',\n // Cost — Sentry splits, OTel rolls up.\n costTotalTokens: 'gen_ai.cost.total_tokens',\n costInputTokens: 'gen_ai.cost.input_tokens',\n costOutputTokens: 'gen_ai.cost.output_tokens',\n usageCostUsd: 'gen_ai.usage.cost_usd',\n // Tool — Sentry uses `tool.call.arguments` / `tool.call.result`; OTel uses `tool.input` / `tool.output` (deprecated in Sentry).\n toolName: 'gen_ai.tool.name',\n toolDescription: 'gen_ai.tool.description',\n toolType: 'gen_ai.tool.type',\n toolCallId: 'gen_ai.tool.call.id',\n toolCallArguments: 'gen_ai.tool.call.arguments',\n toolCallResult: 'gen_ai.tool.call.result',\n toolMessage: 'gen_ai.tool.message',\n toolInputDeprecated: 'gen_ai.tool.input',\n toolOutputDeprecated: 'gen_ai.tool.output',\n // Request configuration.\n requestMaxTokens: 'gen_ai.request.max_tokens',\n requestTemperature: 'gen_ai.request.temperature',\n requestTopP: 'gen_ai.request.top_p',\n requestTopK: 'gen_ai.request.top_k',\n requestSeed: 'gen_ai.request.seed',\n requestFrequencyPenalty: 'gen_ai.request.frequency_penalty',\n requestPresencePenalty: 'gen_ai.request.presence_penalty',\n // Message content surfaces (Sentry conversation viewer).\n inputMessages: 'gen_ai.input.messages',\n outputMessages: 'gen_ai.output.messages',\n systemInstructions: 'gen_ai.system_instructions',\n toolDefinitions: 'gen_ai.tool.definitions',\n // Agent identity.\n agentName: 'gen_ai.agent.name',\n agentRunId: 'gen_ai.agent.run.id',\n agentParentRunId: 'gen_ai.agent.parent_run.id',\n agentDepth: 'gen_ai.agent.depth',\n pipelineName: 'gen_ai.pipeline.name',\n turn: 'gen_ai.agent.turn',\n // MCP-specific (zidane extension; no Sentry op equivalent).\n mcpServer: 'gen_ai.mcp.server',\n mcpToolCount: 'gen_ai.mcp.tool_count',\n} as const\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Compose namespace prefix once. */\nfunction prefixed(namespace: string | undefined, name: string): string {\n return namespace ? `${namespace}/${name}` : name\n}\n\n/** Drop undefined entries — tracers vary on how they render `undefined`. */\nfunction compact(attrs: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(attrs)) {\n if (v !== undefined)\n out[k] = v\n }\n return out\n}\n\n/**\n * Convert a zidane `SessionMessage` (or `StreamOptions.messages` entry)\n * into Sentry's `{role, parts: [{type, content}]}` shape, JSON-stringify\n * the result. Returns `undefined` on serialization failure so the caller\n * skips the attribute rather than poisoning the span.\n *\n * Per Sentry footnote [7], binary blobs in image content are replaced\n * with `\"[Blob substitute]\"`. Tool calls become `{type: 'tool_call'}`\n * parts; tool results become `{type: 'tool_result'}` parts.\n */\ninterface SentryMessagePart {\n type: 'text' | 'tool_call' | 'tool_result' | 'reasoning'\n content?: string\n name?: string\n arguments?: string\n result?: string\n call_id?: string\n}\ninterface SentryMessage {\n role: 'user' | 'assistant' | 'system' | 'tool'\n parts: SentryMessagePart[]\n}\n\n/**\n * Wide-shape block record. `SessionContentBlock` is a discriminated\n * union — accepting the wide record lets us peek at the discriminator\n * without re-importing the entire union at this layer.\n */\ninterface AnyBlock { type: string, [k: string]: unknown }\n\nfunction blockToParts(block: AnyBlock): SentryMessagePart[] {\n switch (block.type) {\n case 'text':\n return [{ type: 'text', content: typeof block.text === 'string' ? block.text : '' }]\n case 'image':\n case 'audio':\n case 'video':\n case 'document':\n return [{ type: 'text', content: '[Blob substitute]' }]\n case 'tool_call':\n return [{\n type: 'tool_call',\n ...(typeof block.name === 'string' ? { name: block.name } : {}),\n ...(typeof block.id === 'string' ? { call_id: block.id } : {}),\n arguments: safeJson(block.input),\n }]\n case 'tool_result': {\n const output = block.output\n const text = typeof output === 'string'\n ? output\n : Array.isArray(output)\n ? (output as Array<{ type: string, text?: string }>)\n .map(b => (b.type === 'image' || b.type === 'audio' || b.type === 'video' || b.type === 'document') ? '[Blob substitute]' : (b.text ?? ''))\n .join('\\n')\n : ''\n return [{\n type: 'tool_result',\n ...(typeof block.callId === 'string' ? { call_id: block.callId } : {}),\n content: text,\n }]\n }\n case 'thinking':\n return [{ type: 'reasoning', content: typeof block.text === 'string' ? block.text : '' }]\n default:\n return []\n }\n}\n\nfunction messageToSentry(msg: { role: 'user' | 'assistant', content: readonly AnyBlock[] }): SentryMessage {\n const parts: SentryMessagePart[] = []\n for (const block of msg.content)\n parts.push(...blockToParts(block))\n return { role: msg.role, parts }\n}\n\nfunction safeJson(value: unknown): string {\n try {\n return JSON.stringify(value ?? null)\n }\n catch {\n return '\"[unserializable]\"'\n }\n}\n\n/**\n * Stringify an array of `SessionMessage`s into Sentry's `gen_ai.input.messages`\n * format. Each entry's role + content is mapped via `messageToSentry`.\n * Returns `undefined` when the input is empty or unserializable.\n */\nfunction stringifyMessages(messages: readonly SessionMessage[]): string | undefined {\n if (messages.length === 0)\n return undefined\n try {\n const sentry = messages.map(m => messageToSentry({\n role: m.role,\n content: m.content as readonly AnyBlock[],\n }))\n return JSON.stringify(sentry)\n }\n catch {\n return undefined\n }\n}\n\n/**\n * Stringify a `StreamOptions.tools` array into Sentry's\n * `gen_ai.tool.definitions` format: `[{name, description?, parameters?}, …]`.\n *\n * The input is `unknown[]` because `StreamOptions.tools` carries the\n * provider-formatted shape (Anthropic / OpenAI / OpenAI-compat all\n * differ). We probe the three names that overlap (`name`, `description`,\n * `inputSchema` / `parameters`) and degrade gracefully otherwise.\n */\nfunction stringifyToolDefs(tools: readonly unknown[] | undefined): string | undefined {\n if (!tools || tools.length === 0)\n return undefined\n try {\n return JSON.stringify(tools.map((raw) => {\n if (!raw || typeof raw !== 'object')\n return { name: 'anonymous' }\n const t = raw as Record<string, unknown>\n const name = typeof t.name === 'string' ? t.name : 'anonymous'\n const description = typeof t.description === 'string' ? t.description : undefined\n // OpenAI's wire format calls it `parameters`; Anthropic / ToolSpec\n // call it `input_schema` / `inputSchema`. Probe all three.\n const parameters = t.parameters ?? t.input_schema ?? t.inputSchema\n return {\n name,\n ...(description ? { description } : {}),\n ...(parameters !== undefined ? { parameters } : {}),\n }\n }))\n }\n catch {\n return undefined\n }\n}\n\n/**\n * Build the usage attribute set per the configured conventions. Sentry\n * expects `input_tokens` to include cached, with `input_tokens.cached`\n * + `input_tokens.cache_write` subkeys; OTel splits cache into\n * separate top-level keys. `'both'` emits everything.\n */\nfunction buildUsageAttrs(\n usage: {\n input: number\n output: number\n cacheRead?: number\n cacheCreation?: number\n thinking?: number\n cost?: number\n modelId?: string\n finishReason?: string\n timeToFirstTokenMs?: number\n },\n conventions: TracingConventions,\n): Record<string, unknown> {\n const cacheRead = usage.cacheRead ?? 0\n const cacheWrite = usage.cacheCreation ?? 0\n // Per Sentry: `input_tokens` includes cached. zidane reports `input` as\n // the uncached new-input slice, so the headline number is the sum.\n const inputInclCache = usage.input + cacheRead + cacheWrite\n const totalTokens = inputInclCache + usage.output\n const wantSentry = conventions === 'sentry' || conventions === 'both'\n const wantOtel = conventions === 'otel' || conventions === 'both'\n\n const out: Record<string, unknown> = {\n [GEN_AI.responseModel]: usage.modelId,\n [GEN_AI.responseFinishReasons]: usage.finishReason ? [usage.finishReason] : undefined,\n [GEN_AI.usageOutputTokens]: usage.output,\n [GEN_AI.usageTotalTokens]: totalTokens,\n }\n\n if (wantSentry) {\n out[GEN_AI.usageInputTokens] = inputInclCache\n if (cacheRead > 0)\n out[GEN_AI.usageInputTokensCached] = cacheRead\n if (cacheWrite > 0)\n out[GEN_AI.usageInputTokensCacheWrite] = cacheWrite\n if (typeof usage.thinking === 'number' && usage.thinking > 0)\n out[GEN_AI.usageOutputTokensReasoning] = usage.thinking\n if (typeof usage.cost === 'number')\n out[GEN_AI.costTotalTokens] = usage.cost\n if (typeof usage.timeToFirstTokenMs === 'number')\n out[GEN_AI.responseTimeToFirstTokenSeconds] = usage.timeToFirstTokenMs / 1000\n }\n if (wantOtel) {\n // OTel: input_tokens is the uncached slice; cache is separate.\n if (!wantSentry)\n out[GEN_AI.usageInputTokens] = usage.input\n if (cacheRead > 0)\n out[GEN_AI.usageCacheReadInputTokens] = cacheRead\n if (cacheWrite > 0)\n out[GEN_AI.usageCacheCreationInputTokens] = cacheWrite\n if (typeof usage.thinking === 'number' && usage.thinking > 0)\n out[GEN_AI.usageReasoningTokens] = usage.thinking\n if (typeof usage.cost === 'number')\n out[GEN_AI.usageCostUsd] = usage.cost\n if (typeof usage.timeToFirstTokenMs === 'number')\n out[GEN_AI.responseTimeToFirstTokenMs] = usage.timeToFirstTokenMs\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a set of tracing hook handlers that can be installed on an agent.\n *\n * @example Sentry\n * ```ts\n * const tracing = createTracingHooks({\n * startSpan: (name, attrs) => Sentry.startInactiveSpan({ name, attributes: attrs }),\n * })\n * const uninstall = tracing.install(agent.hooks)\n * try { await agent.run({ prompt }) }\n * finally { uninstall() }\n * ```\n *\n * @example OpenTelemetry with parent-context propagation\n * ```ts\n * import { trace, context, propagation } from '@opentelemetry/api'\n *\n * const tracer = trace.getTracer('zidane')\n * const tracing = createTracingHooks({\n * startSpan: (name, attrs, parentCtx) => {\n * const ctx = parentCtx ? propagation.extract(context.active(), parentCtx) : context.active()\n * return tracer.startSpan(name, { attributes: attrs }, ctx)\n * },\n * getActiveTraceContext: () => {\n * const carrier: Record<string, string> = {}\n * propagation.inject(context.active(), carrier)\n * return carrier\n * },\n * })\n * ```\n */\nexport function createTracingHooks(options: TracingHooksOptions): TracingHookSet {\n const namespace = options.namespace\n const legacy = options.legacyAttributes ?? true\n const conventions = options.conventions ?? 'sentry'\n const wantSentry = conventions === 'sentry' || conventions === 'both'\n const captureContent = options.captureMessageContent !== false\n const onError = options.onError ?? (() => {})\n\n return {\n install(hooks: Hookable<AgentHooks>): () => void {\n // Span book-keeping. Each map keys by the identifier that's unique\n // across concurrent in-flight spans of that kind.\n const runSpans = new Map<string, Span>() // keyed by runId\n const turnSpans = new Map<string, Span>() // keyed by turnId\n const toolSpans = new Map<string, Span>() // keyed by callId\n const mcpSpans = new Map<string, Span>() // keyed by callId\n const spawnSpans = new Map<string, Span>() // keyed by spawn id\n const bootstrapSpans = new Map<string, Span>() // keyed by server name\n // Provider system identifier (`anthropic`, `openai`, …) captured at\n // `agent:start`. Stamped onto every chat / tool span belonging to\n // this run so Sentry's per-vendor breakdowns work. Reset on\n // `agent:done`.\n let activeSystem: string | undefined\n // Active turn book-keeping for tokens-per-second derivation.\n const turnTrack = new Map<string, { startedAt: number }>()\n // Active run span ref — used so non-span events (gate blocks,\n // budget hits, validation rejects, policy/pairing repairs) can\n // attach via `addEvent` on the in-flight run span. The run span is\n // the natural parent for cross-cutting policy events: it outlives\n // turn spans (which close before tool dispatch starts in the\n // current loop), and tool spans (which haven't opened on a\n // gate-block path).\n let activeRunSpan: Span | undefined\n\n function safeStartSpan(\n name: string,\n attrs: Record<string, unknown>,\n parentContext?: Readonly<Record<string, string>>,\n ): Span | undefined {\n try {\n return options.startSpan(prefixed(namespace, name), compact(attrs), parentContext)\n }\n catch (err) {\n try {\n onError('startSpan', err)\n }\n catch { /* ignore */ }\n return undefined\n }\n }\n\n function safeSetAttrs(span: Span | undefined, attrs: Record<string, unknown>): void {\n if (!span?.setAttributes)\n return\n try {\n span.setAttributes(compact(attrs))\n }\n catch (err) {\n try {\n onError('setAttributes', err)\n }\n catch { /* ignore */ }\n }\n }\n\n function safeEnd(map: Map<string, Span>, key: string): void {\n const span = map.get(key)\n if (!span)\n return\n try {\n span.end()\n }\n catch (err) {\n try {\n onError('end', err)\n }\n catch { /* ignore */ }\n }\n map.delete(key)\n }\n\n function endAll(map: Map<string, Span>): void {\n for (const [, span] of map) {\n try {\n span.end()\n }\n catch (err) {\n try {\n onError('end', err)\n }\n catch { /* ignore */ }\n }\n }\n map.clear()\n }\n\n function safeAddEvent(span: Span | undefined, name: string, attrs: Record<string, unknown>): void {\n if (!span)\n return\n if (typeof span.addEvent === 'function') {\n try {\n span.addEvent(name, compact(attrs))\n }\n catch (err) {\n try {\n onError('addEvent', err)\n }\n catch { /* ignore */ }\n }\n return\n }\n // Tracer doesn't support events — fall back to a single\n // `event.<name>.*` attribute so the data lands somewhere.\n safeSetAttrs(span, Object.fromEntries(\n Object.entries(compact(attrs)).map(([k, v]) => [`event.${name}.${k}`, v]),\n ))\n }\n\n function redact(kind: string, value: string, meta?: Readonly<Record<string, unknown>>): string {\n if (typeof options.redact !== 'function')\n return value\n try {\n return options.redact(kind, value, meta)\n }\n catch (err) {\n try {\n onError('redact', err)\n }\n catch { /* ignore */ }\n return value\n }\n }\n\n const unregisters: Array<() => void> = []\n\n // -----------------------------------------------------------------\n // agent.run (root)\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('agent:start', (ctx) => {\n activeSystem = ctx.providerName\n // Empty-string names produce `invoke_agent ` (trailing space).\n // Treat empty as \"no name\" so the span name reads cleanly.\n const displayName = ctx.agentName && ctx.agentName.length > 0\n ? ctx.agentName\n : 'agent'\n const span = safeStartSpan(\n `invoke_agent ${displayName}`,\n {\n [GEN_AI.operationName]: 'invoke_agent',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.agentName]: ctx.agentName,\n [GEN_AI.agentRunId]: ctx.runId,\n [GEN_AI.agentParentRunId]: ctx.parentRunId,\n [GEN_AI.agentDepth]: ctx.depth,\n // Sentry-specific span op hint — backends that key off\n // `op` (Sentry Python/JS) read this directly; OTel\n // backends ignore unknown keys, so it's harmless.\n 'sentry.op': 'gen_ai.invoke_agent',\n ...(legacy\n ? {\n runId: ctx.runId,\n parentRunId: ctx.parentRunId,\n agentName: ctx.agentName,\n depth: ctx.depth,\n }\n : {}),\n },\n ctx.tracingContext,\n )\n if (span) {\n runSpans.set(ctx.runId, span)\n activeRunSpan = span\n }\n }))\n\n unregisters.push(hooks.hook('agent:done', (stats) => {\n // `agent:done` doesn't carry a runId on its payload (it's `AgentStats`).\n // The 99% case is a single in-flight run — close every open run span\n // and stamp the totals on each. Multi-run-concurrent users plug a\n // runId into stats via their own integration; for now we close all.\n const usageAttrs = buildUsageAttrs({\n input: stats.totalIn,\n output: stats.totalOut,\n cacheRead: stats.totalCacheRead,\n cacheCreation: stats.totalCacheCreation,\n cost: stats.cost,\n timeToFirstTokenMs: stats.timeTillFirstTokenMs,\n }, conventions)\n for (const [, span] of runSpans) {\n safeSetAttrs(span, {\n ...usageAttrs,\n [GEN_AI.turn]: stats.turns,\n 'gen_ai.agent.elapsed_ms': stats.elapsed,\n ...(legacy\n ? {\n totalIn: stats.totalIn,\n totalOut: stats.totalOut,\n totalCacheRead: stats.totalCacheRead,\n totalCacheCreation: stats.totalCacheCreation,\n cost: stats.cost,\n turns: stats.turns,\n elapsed: stats.elapsed,\n }\n : {}),\n })\n }\n endAll(runSpans)\n // Defensive — close anything else still hanging open.\n endAll(turnSpans)\n endAll(toolSpans)\n endAll(mcpSpans)\n endAll(spawnSpans)\n endAll(bootstrapSpans)\n activeRunSpan = undefined\n activeSystem = undefined\n turnTrack.clear()\n }))\n\n unregisters.push(hooks.hook('agent:abort', () => {\n for (const [, span] of runSpans)\n safeSetAttrs(span, { 'gen_ai.agent.status': 'aborted' })\n }))\n\n // -----------------------------------------------------------------\n // Turn span — OTel Gen AI `chat` operation\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('turn:before', (ctx) => {\n const requestedModel = ctx.options.model\n // Built-in Sentry/OTel attrs that don't depend on content capture.\n const baseAttrs: Record<string, unknown> = {\n [GEN_AI.operationName]: 'chat',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.requestModel]: requestedModel,\n [GEN_AI.turn]: ctx.turn,\n [GEN_AI.responseStreaming]: true,\n [GEN_AI.requestMaxTokens]: ctx.options.maxTokens,\n 'sentry.op': 'gen_ai.chat',\n 'gen_ai.agent.turn_id': ctx.turnId,\n ...(legacy ? { turnId: ctx.turnId, turn: ctx.turn } : {}),\n }\n // Optionally surface conversation content — prompts, system\n // instructions, available tools. Each piece flows through the\n // redact seam so hosts can scrub secrets without losing the\n // structural attribute. Skipping content keeps the span cheap\n // and privacy-safe.\n if (captureContent) {\n const systemText = ctx.options.system\n if (systemText) {\n baseAttrs[GEN_AI.systemInstructions] = redact('system', systemText, {\n turnId: ctx.turnId,\n turn: ctx.turn,\n })\n }\n const inputMsgs = stringifyMessages(ctx.options.messages)\n if (inputMsgs) {\n baseAttrs[GEN_AI.inputMessages] = redact('prompt', inputMsgs, {\n turnId: ctx.turnId,\n turn: ctx.turn,\n })\n }\n const toolDefs = stringifyToolDefs(ctx.options.tools)\n if (toolDefs)\n baseAttrs[GEN_AI.toolDefinitions] = toolDefs\n }\n const span = safeStartSpan(\n `chat${requestedModel ? ` ${requestedModel}` : ''}`,\n baseAttrs,\n )\n if (span) {\n turnSpans.set(ctx.turnId, span)\n turnTrack.set(ctx.turnId, { startedAt: Date.now() })\n }\n }))\n\n unregisters.push(hooks.hook('stream:start', (ctx) => {\n safeAddEvent(turnSpans.get(ctx.turnId), 'gen_ai.stream.start', {\n startedAt: ctx.startedAt,\n })\n }))\n\n unregisters.push(hooks.hook('turn:after', (ctx) => {\n const span = turnSpans.get(ctx.turnId)\n const tracked = turnTrack.get(ctx.turnId)\n turnTrack.delete(ctx.turnId)\n // Tokens-per-second derivation. Use wall-clock duration since the\n // turn span opened, fall back to TTFT-adjusted slice when present.\n let tokensPerSecond: number | undefined\n if (tracked && ctx.usage.output > 0) {\n const elapsedMs = Date.now() - tracked.startedAt\n if (elapsedMs > 0)\n tokensPerSecond = (ctx.usage.output / elapsedMs) * 1000\n }\n const usageAttrs = buildUsageAttrs(ctx.usage, conventions)\n // Cumulative-through-this-turn totals. We compute `input_tokens`\n // here to mirror `gen_ai.usage.input_tokens`'s semantic on the\n // same span: it INCLUDES cached when Sentry conventions are in\n // play, matches the uncached slice when OTel-only. Without this\n // alignment the two keys (`usage.*` vs `cumulative.*`) would\n // silently differ in arithmetic.\n const cumInputTokens = wantSentry\n ? ctx.cumulativeUsage.input + ctx.cumulativeUsage.cacheRead + ctx.cumulativeUsage.cacheCreation\n : ctx.cumulativeUsage.input\n const attrs: Record<string, unknown> = {\n ...usageAttrs,\n [GEN_AI.responseTokensPerSecond]: tokensPerSecond,\n 'gen_ai.agent.cumulative.input_tokens': cumInputTokens,\n 'gen_ai.agent.cumulative.output_tokens': ctx.cumulativeUsage.output,\n 'gen_ai.agent.cumulative.total_tokens': cumInputTokens + ctx.cumulativeUsage.output,\n 'gen_ai.agent.cumulative.cache_read_input_tokens': ctx.cumulativeUsage.cacheRead,\n 'gen_ai.agent.cumulative.cache_creation_input_tokens': ctx.cumulativeUsage.cacheCreation,\n 'gen_ai.agent.cumulative.cost_usd': ctx.cumulativeUsage.cost,\n 'gen_ai.agent.cumulative.turns': ctx.cumulativeUsage.turns,\n ...(legacy\n ? {\n inputTokens: ctx.usage.input,\n outputTokens: ctx.usage.output,\n finishReason: ctx.usage.finishReason,\n modelId: ctx.usage.modelId,\n }\n : {}),\n }\n // Output messages — the assistant turn that just landed. Sentry's\n // conversation viewer keys off this; skipped when content capture\n // is off. `system` turns aren't serialized (Sentry's schema only\n // accepts user / assistant / system / tool — and we never emit\n // system role from the loop).\n if (captureContent && ctx.message && ctx.message.role !== 'system' && ctx.message.role !== 'command') {\n const outputMsgs = stringifyMessages([{\n role: ctx.message.role,\n content: ctx.message.content,\n }])\n if (outputMsgs)\n attrs[GEN_AI.outputMessages] = redact('stream-text', outputMsgs, { turnId: ctx.turnId, turn: ctx.turn })\n }\n safeSetAttrs(span, attrs)\n safeEnd(turnSpans, ctx.turnId)\n }))\n\n unregisters.push(hooks.hook('stream:error', (ctx) => {\n const span = turnSpans.get(ctx.turnId)\n const message = ctx.err instanceof Error ? ctx.err.message : String(ctx.err)\n safeSetAttrs(span, {\n 'error.type': ctx.err instanceof Error ? ctx.err.name : 'unknown',\n 'error.message': message,\n 'http.response.status_code': ctx.statusCode,\n 'gen_ai.request.id': ctx.requestId,\n })\n safeAddEvent(span, 'gen_ai.stream.error', {\n 'error.type': ctx.err instanceof Error ? ctx.err.name : 'unknown',\n 'error.message': message,\n 'http.response.status_code': ctx.statusCode,\n 'gen_ai.request.id': ctx.requestId,\n })\n }))\n\n // -----------------------------------------------------------------\n // Native tool span — OTel Gen AI `execute_tool` operation\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('tool:before', (ctx) => {\n const span = safeStartSpan(\n `execute_tool ${ctx.displayName}`,\n {\n [GEN_AI.operationName]: 'execute_tool',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolType]: 'function',\n [GEN_AI.toolCallId]: ctx.callId,\n 'sentry.op': 'gen_ai.execute_tool',\n 'gen_ai.tool.display_name': ctx.displayName,\n 'gen_ai.agent.turn_id': ctx.turnId,\n 'gen_ai.agent.depth': ctx.depth,\n 'gen_ai.agent.run.id': ctx.runId,\n 'gen_ai.agent.parent_run.id': ctx.parentRunId,\n ...(legacy\n ? {\n toolName: ctx.name,\n displayName: ctx.displayName,\n turnId: ctx.turnId,\n callId: ctx.callId,\n }\n : {}),\n },\n )\n if (span) {\n toolSpans.set(ctx.callId, span)\n if (captureContent) {\n // Attach (possibly redacted) input as an attribute. Sentry's\n // canonical key is `gen_ai.tool.call.arguments`; OTel's\n // older key is `gen_ai.tool.input` (now deprecated in\n // Sentry). Emit one or both based on `conventions`.\n try {\n const serialized = JSON.stringify(ctx.input)\n const redacted = redact('tool-input', serialized, {\n toolName: ctx.name,\n displayName: ctx.displayName,\n callId: ctx.callId,\n turnId: ctx.turnId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallArguments] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolInputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n catch {\n // Non-serializable input (circular refs) — skip the attr;\n // the tool name and call id are still on the span.\n }\n }\n }\n }))\n\n unregisters.push(hooks.hook('tool:after', (ctx) => {\n const span = toolSpans.get(ctx.callId)\n safeSetAttrs(span, {\n 'gen_ai.tool.output_bytes': ctx.outputBytes,\n 'gen_ai.tool.coercions': ctx.coercions?.length ?? 0,\n })\n if (captureContent && typeof ctx.result === 'string') {\n const redacted = redact('tool-result', ctx.result, {\n toolName: ctx.name,\n callId: ctx.callId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallResult] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolOutputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n safeEnd(toolSpans, ctx.callId)\n }))\n\n unregisters.push(hooks.hook('tool:error', (ctx) => {\n safeSetAttrs(toolSpans.get(ctx.callId), {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n safeEnd(toolSpans, ctx.callId)\n }))\n\n // Tool gate / dispatch outcomes. Listen on `tool:dispatched` (fires\n // AFTER every `tool:gate` listener has had a chance to mutate\n // `block` / `result`) so the recorded `outcome` reflects the final\n // decision rather than the as-entered state. Attaches to the\n // in-flight run span; the chat span has already closed by tool\n // dispatch time in the current loop ordering, and no tool span has\n // opened for a `gate-block` / `unknown` / `invalid-input` path.\n unregisters.push(hooks.hook('tool:dispatched', (ctx) => {\n if (ctx.outcome === 'gate-block') {\n safeAddEvent(activeRunSpan, 'gen_ai.gate.block', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n reason: ctx.reason,\n })\n }\n else if (ctx.outcome === 'gate-substitute') {\n safeAddEvent(activeRunSpan, 'gen_ai.gate.substitute', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n })\n }\n else if (ctx.outcome === 'unknown') {\n safeAddEvent(activeRunSpan, 'gen_ai.tool.unknown', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n })\n }\n else if (ctx.outcome === 'invalid-input') {\n safeAddEvent(activeRunSpan, 'gen_ai.tool.invalid_input', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n })\n }\n }))\n\n unregisters.push(hooks.hook('validation:reject', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.validation.reject', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n reason: ctx.reason,\n })\n }))\n\n unregisters.push(hooks.hook('validation:coerce', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.validation.coerce', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n coercions: ctx.coercions,\n })\n }))\n\n unregisters.push(hooks.hook('budget:exceeded', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.budget.exceeded', {\n turnId: ctx.turnId,\n bytes: ctx.bytes,\n budget: ctx.budget,\n })\n }))\n\n unregisters.push(hooks.hook('tool-budget:exceeded', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.tool_budget.exceeded', {\n [GEN_AI.toolName]: ctx.tool,\n turnId: ctx.turnId,\n count: ctx.count,\n max: ctx.max,\n mode: ctx.mode,\n })\n }))\n\n unregisters.push(hooks.hook('pairing:repair', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.pairing.repair', {\n mode: ctx.mode,\n callId: ctx.callId,\n turnId: ctx.turnId,\n })\n }))\n\n unregisters.push(hooks.hook('oauth:refresh', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.oauth.refresh', {\n provider: ctx.provider,\n providerId: ctx.providerId,\n source: ctx.source,\n })\n }))\n\n // -----------------------------------------------------------------\n // MCP tool span — OTel Gen AI `execute_tool` operation, MCP variant\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('mcp:tool:before', (ctx) => {\n const span = safeStartSpan(\n `execute_tool ${ctx.server}.${ctx.tool}`,\n {\n [GEN_AI.operationName]: 'execute_tool',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.toolName]: ctx.displayName,\n // MCP tools are Sentry's \"extension\" tool type — backed by an\n // out-of-process server rather than a local function.\n [GEN_AI.toolType]: 'extension',\n [GEN_AI.toolCallId]: ctx.callId,\n [GEN_AI.mcpServer]: ctx.server,\n 'sentry.op': 'gen_ai.execute_tool',\n 'gen_ai.mcp.tool': ctx.tool,\n 'gen_ai.agent.turn_id': ctx.turnId,\n 'gen_ai.agent.run.id': ctx.runId,\n ...(legacy\n ? {\n server: ctx.server,\n tool: ctx.tool,\n displayName: ctx.displayName,\n turnId: ctx.turnId,\n callId: ctx.callId,\n }\n : {}),\n },\n )\n if (span) {\n mcpSpans.set(ctx.callId, span)\n if (captureContent) {\n try {\n const redacted = redact('mcp-tool-input', JSON.stringify(ctx.input), {\n server: ctx.server,\n tool: ctx.tool,\n callId: ctx.callId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallArguments] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolInputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n catch { /* ignore */ }\n }\n }\n }))\n\n unregisters.push(hooks.hook('mcp:tool:after', (ctx) => {\n const span = mcpSpans.get(ctx.callId)\n safeSetAttrs(span, { 'gen_ai.tool.output_bytes': ctx.outputBytes })\n if (captureContent && typeof ctx.result === 'string') {\n const redacted = redact('mcp-tool-result', ctx.result, {\n server: ctx.server,\n tool: ctx.tool,\n callId: ctx.callId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallResult] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolOutputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n safeEnd(mcpSpans, ctx.callId)\n }))\n\n unregisters.push(hooks.hook('mcp:tool:error', (ctx) => {\n safeSetAttrs(mcpSpans.get(ctx.callId), {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n safeEnd(mcpSpans, ctx.callId)\n }))\n\n // -----------------------------------------------------------------\n // MCP server bootstrap span\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('mcp:bootstrap:start', (ctx) => {\n const span = safeStartSpan(\n `mcp.bootstrap ${ctx.name}`,\n {\n [GEN_AI.operationName]: 'mcp.bootstrap',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.mcpServer]: ctx.name,\n 'gen_ai.mcp.transport': ctx.transport,\n },\n )\n if (span)\n bootstrapSpans.set(ctx.name, span)\n }))\n\n unregisters.push(hooks.hook('mcp:bootstrap:end', (ctx) => {\n const span = bootstrapSpans.get(ctx.name)\n const ok = ctx.ok\n safeSetAttrs(span, {\n 'gen_ai.mcp.bootstrap.duration_ms': ctx.durationMs,\n 'gen_ai.mcp.bootstrap.ok': ok,\n ...(ok\n ? {\n [GEN_AI.mcpToolCount]: ctx.toolCount,\n 'gen_ai.mcp.lazy': ctx.lazy,\n 'gen_ai.mcp.cached': ctx.cached,\n }\n : {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n }),\n })\n safeEnd(bootstrapSpans, ctx.name)\n }))\n\n unregisters.push(hooks.hook('mcp:auth:required', (ctx) => {\n const span = bootstrapSpans.get(ctx.name)\n safeAddEvent(span ?? activeRunSpan, 'gen_ai.mcp.auth.required', {\n server: ctx.name,\n transport: ctx.transport,\n reason: ctx.reason,\n })\n }))\n\n unregisters.push(hooks.hook('mcp:error', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.mcp.error', {\n 'server': ctx.name,\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n }))\n\n // -----------------------------------------------------------------\n // Spawn span — parent-side. Also injects trace context for the child.\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('spawn:before', (ctx) => {\n // Sentry: \"handoff from {from_agent} to {to_agent}\". We don't\n // always know the child agent's name at spawn time — fall back\n // to the truncated task as the destination identifier.\n const toAgent = ctx.task.length > 60 ? `${ctx.task.slice(0, 57)}…` : ctx.task\n const span = safeStartSpan(\n `handoff to ${toAgent}`,\n {\n [GEN_AI.operationName]: 'handoff',\n [GEN_AI.system]: activeSystem,\n 'sentry.op': 'gen_ai.handoff',\n 'gen_ai.agent.spawn.id': ctx.id,\n 'gen_ai.agent.spawn.task': ctx.task,\n 'gen_ai.agent.depth': ctx.depth,\n },\n )\n if (span)\n spawnSpans.set(ctx.id, span)\n\n // Inject parent trace context for the child agent. The spawn tool\n // passes whatever we write into `ctx.tracingContext` to the child's\n // `agent.run({ tracingContext })` — see `tools/spawn.ts`.\n if (typeof options.getActiveTraceContext === 'function' && ctx.tracingContext) {\n let carrier: Readonly<Record<string, string>> | undefined\n try {\n carrier = options.getActiveTraceContext()\n }\n catch (err) {\n try {\n onError('getActiveTraceContext', err)\n }\n catch { /* ignore */ }\n }\n if (carrier) {\n for (const [k, v] of Object.entries(carrier))\n ctx.tracingContext[k] = v\n }\n }\n }))\n\n unregisters.push(hooks.hook('spawn:complete', (ctx) => {\n const span = spawnSpans.get(ctx.id)\n const childUsage = buildUsageAttrs({\n input: ctx.stats.totalIn,\n output: ctx.stats.totalOut,\n cacheRead: ctx.stats.totalCacheRead,\n cacheCreation: ctx.stats.totalCacheCreation,\n cost: ctx.stats.cost,\n }, conventions)\n safeSetAttrs(span, {\n 'gen_ai.agent.spawn.status': ctx.status ?? 'completed',\n 'gen_ai.agent.spawn.depth': ctx.depth,\n ...childUsage,\n })\n safeEnd(spawnSpans, ctx.id)\n }))\n\n unregisters.push(hooks.hook('spawn:error', (ctx) => {\n safeSetAttrs(spawnSpans.get(ctx.id), {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n safeEnd(spawnSpans, ctx.id)\n }))\n\n // -----------------------------------------------------------------\n // Disposal\n // -----------------------------------------------------------------\n\n let disposed = false\n return function uninstall() {\n if (disposed)\n return\n disposed = true\n for (const un of unregisters) {\n try {\n un()\n }\n catch { /* ignore */ }\n }\n endAll(runSpans)\n endAll(turnSpans)\n endAll(toolSpans)\n endAll(mcpSpans)\n endAll(spawnSpans)\n endAll(bootstrapSpans)\n activeRunSpan = undefined\n }\n },\n }\n}\n\n/**\n * OpenTelemetry Gen AI semantic-convention attribute keys used by the\n * built-in tracer. Exported so consumers integrating with raw OTel SDKs\n * (instead of going through `createTracingHooks`) can stay aligned with\n * the names the harness itself emits.\n */\nexport const GEN_AI_ATTRIBUTES = GEN_AI\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["prefixed"],"sources":["../src/behaviors/local-reliability.ts","../src/metrics.ts","../src/mutation-validation.ts","../src/tracing.ts"],"sourcesContent":["import type { AgentBehavior } from '../types'\n\nconst DEFAULT_LOCAL_RELIABILITY: AgentBehavior = {\n maxConcurrentTools: 3,\n readFileDefaults: {\n limit: 400,\n maxBytes: 64 * 1024,\n },\n toolOutputBudget: 32 * 1024,\n textToolCallRescue: { mode: 'steer' },\n thinkingOverrunPolicy: {\n mode: 'steer-next-turn',\n thresholdTokens: 2048,\n },\n}\n\n/**\n * Opt-in behavior overlay for brittle/local OpenAI-compatible endpoints.\n * Returns plain `AgentBehavior` so hosts can spread it before or after their\n * own overrides; no built-in profile uses this helper by default.\n */\nexport function localReliabilityBehavior(overrides: AgentBehavior = {}): AgentBehavior {\n return {\n ...DEFAULT_LOCAL_RELIABILITY,\n ...overrides,\n readFileDefaults: {\n ...DEFAULT_LOCAL_RELIABILITY.readFileDefaults,\n ...(overrides.readFileDefaults ?? {}),\n },\n textToolCallRescue: overrides.textToolCallRescue ?? DEFAULT_LOCAL_RELIABILITY.textToolCallRescue,\n thinkingOverrunPolicy: overrides.thinkingOverrunPolicy ?? DEFAULT_LOCAL_RELIABILITY.thinkingOverrunPolicy,\n }\n}\n","/**\n * Metrics helper — wraps agent lifecycle hooks in caller-provided meters.\n *\n * Symmetric with {@link createTracingHooks} from `./tracing`. Where the\n * tracer answers \"what happened in this run?\" by producing spans, the\n * metrics helper answers \"how is the fleet behaving?\" by emitting\n * counters / histograms / up-down counters. Both are tracer-agnostic —\n * the caller supplies a `Meter` (OTel-API-shaped) and the helper plugs\n * the right hook on each metric.\n *\n * Instrument families:\n *\n * ### Histograms (distribution metrics)\n * - `gen_ai.client.operation.duration` (ms) — wall-clock per turn (`turn:before` → `turn:after`).\n * - `gen_ai.client.token.usage` — `input` / `output` token counts per turn (tagged by `gen_ai.token.type`).\n * - `gen_ai.client.time_to_first_token` (ms) — per-turn TTFT from `TurnUsage.timeToFirstTokenMs`.\n * - `gen_ai.tool.duration` (ms) — native tool execution time (`tool:before` → `tool:after`).\n * - `gen_ai.tool.output_bytes` — `tool:after.outputBytes`.\n * - `gen_ai.mcp.tool.duration` (ms) — MCP tool execution time.\n * - `gen_ai.mcp.bootstrap.duration` (ms) — MCP server bootstrap (already measured by harness).\n *\n * ### Counters (monotonic)\n * - `gen_ai.agent.runs` — `agent:start`.\n * - `gen_ai.agent.runs.completed` — `agent:done`.\n * - `gen_ai.agent.aborts` — `agent:abort`.\n * - `gen_ai.tool.calls` — `tool:dispatched` (tagged by `outcome`).\n * - `gen_ai.tool.errors` — `tool:error`.\n * - `gen_ai.mcp.tool.errors` — `mcp:tool:error`.\n * - `gen_ai.stream.errors` — `stream:error` (tagged by `status_code`).\n * - `gen_ai.validation.rejects` — `validation:reject`.\n * - `gen_ai.validation.coercions` — `validation:coerce`.\n * - `gen_ai.gate.blocks` — `tool:dispatched` outcome `gate-block`.\n * - `gen_ai.budget.exceeded` — `budget:exceeded`.\n * - `gen_ai.tool_budget.exceeded` — `tool-budget:exceeded` (tagged by `mode`).\n * - `gen_ai.pairing.repairs` — `pairing:repair` (tagged by `mode`).\n * - `gen_ai.oauth.refreshes` — `oauth:refresh`.\n * - `gen_ai.mcp.errors` — `mcp:error`.\n * - `gen_ai.mcp.auth.required` — `mcp:auth:required`.\n * - `gen_ai.cost_usd` — accumulated cost (added on `turn:after`).\n *\n * ### Up-down counter (gauge-shaped)\n * - `gen_ai.agent.runs.active` — incremented on `agent:start`, decremented on `agent:done`.\n *\n * The `Meter` shape mirrors `@opentelemetry/api`'s `Meter` exactly — passing\n * `metrics.getMeter('zidane')` works directly. Hosts using a different\n * metrics backend (StatsD, Prometheus client, custom in-memory aggregator)\n * implement the same three factory methods and the helper plugs in\n * unchanged.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\n\n// ---------------------------------------------------------------------------\n// OTel-shaped Meter interface\n// ---------------------------------------------------------------------------\n\nexport type MetricAttributes = Record<string, string | number | boolean | undefined>\n\nexport interface Counter {\n add: (value: number, attributes?: MetricAttributes) => void\n}\n\nexport interface Histogram {\n record: (value: number, attributes?: MetricAttributes) => void\n}\n\nexport interface UpDownCounter {\n add: (value: number, attributes?: MetricAttributes) => void\n}\n\nexport interface InstrumentOptions {\n description?: string\n unit?: string\n}\n\n/**\n * Minimal Meter interface — structurally identical to OTel's `Meter`.\n * Hosts passing `metrics.getMeter(name)` (from `@opentelemetry/api`)\n * satisfy this without adaptation.\n */\nexport interface Meter {\n createCounter: (name: string, options?: InstrumentOptions) => Counter\n createHistogram: (name: string, options?: InstrumentOptions) => Histogram\n createUpDownCounter: (name: string, options?: InstrumentOptions) => UpDownCounter\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface MetricsHooksOptions {\n meter: Meter\n /**\n * Optional prefix prepended to every instrument name. Default: no prefix\n * (instrument names follow OTel Gen AI semantic conventions verbatim,\n * which is the most-portable shape). Set to e.g. `'zidane.'` to\n * namespace inside a shared meter registry.\n */\n namespace?: string\n /**\n * Optional baseline attributes applied to every measurement. Typical\n * use: `{ service: 'tui', env: 'prod' }`. Per-event attributes win on\n * key collision.\n */\n baseAttributes?: MetricAttributes\n /**\n * Error sink for meter failures. The helper still swallows the throw\n * so a broken backend can't crash a run; this callback surfaces the\n * failure for ops dashboards.\n */\n onError?: (kind: string, err: unknown) => void\n}\n\nexport interface MetricsHookSet {\n install: (hooks: Hookable<AgentHooks>) => () => void\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction prefixed(prefix: string | undefined, name: string): string {\n return prefix ? `${prefix}${name}` : name\n}\n\n/**\n * Drop `undefined` entries before handing attributes to a metrics\n * backend. OTel's `@opentelemetry/api` rejects `undefined` attribute\n * values (and Prometheus / StatsD adapters silently mis-label them); the\n * helper's own API surface allows `undefined` for ergonomic call sites\n * (`{...(cond ? { foo } : {})}`-style spreads), so we strip here at the\n * boundary.\n */\nfunction mergeAttrs(\n base: MetricAttributes | undefined,\n extra: MetricAttributes,\n): Record<string, string | number | boolean> {\n const out: Record<string, string | number | boolean> = {}\n if (base) {\n for (const [k, v] of Object.entries(base)) {\n if (v !== undefined)\n out[k] = v\n }\n }\n for (const [k, v] of Object.entries(extra)) {\n if (v !== undefined)\n out[k] = v\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// createMetricsHooks\n// ---------------------------------------------------------------------------\n\n/**\n * Build a set of metrics hook handlers that can be installed on an agent.\n *\n * @example OpenTelemetry\n * ```ts\n * import { metrics } from '@opentelemetry/api'\n * const meter = metrics.getMeter('zidane')\n * const m = createMetricsHooks({ meter, baseAttributes: { service: 'tui' } })\n * const uninstall = m.install(agent.hooks)\n * try { await agent.run({ prompt }) }\n * finally { uninstall() }\n * ```\n */\nexport function createMetricsHooks(options: MetricsHooksOptions): MetricsHookSet {\n const ns = options.namespace\n const base = options.baseAttributes\n const onError = options.onError ?? (() => {})\n\n const make = {\n counter: (name: string, opts?: InstrumentOptions) =>\n safeFactory(() => options.meter.createCounter(prefixed(ns, name), opts), name, onError),\n histogram: (name: string, opts?: InstrumentOptions) =>\n safeFactory(() => options.meter.createHistogram(prefixed(ns, name), opts), name, onError),\n upDown: (name: string, opts?: InstrumentOptions) =>\n safeFactory(() => options.meter.createUpDownCounter(prefixed(ns, name), opts), name, onError),\n }\n\n // Instruments — created once at install time.\n const turnDuration = make.histogram('gen_ai.client.operation.duration', { unit: 'ms', description: 'Per-turn LLM operation duration.' })\n const tokenUsage = make.histogram('gen_ai.client.token.usage', { unit: 'tokens', description: 'Per-turn token usage (tagged by gen_ai.token.type).' })\n const ttft = make.histogram('gen_ai.client.time_to_first_token', { unit: 'ms', description: 'Per-turn time to first token.' })\n const toolDuration = make.histogram('gen_ai.tool.duration', { unit: 'ms', description: 'Native tool execution wall clock.' })\n const toolOutput = make.histogram('gen_ai.tool.output_bytes', { unit: 'By', description: 'Native tool output bytes.' })\n const mcpToolDuration = make.histogram('gen_ai.mcp.tool.duration', { unit: 'ms', description: 'MCP tool execution wall clock.' })\n const mcpBootstrapDuration = make.histogram('gen_ai.mcp.bootstrap.duration', { unit: 'ms', description: 'MCP server bootstrap duration.' })\n\n const runsStarted = make.counter('gen_ai.agent.runs', { description: 'Runs started.' })\n const runsCompleted = make.counter('gen_ai.agent.runs.completed', { description: 'Runs completed.' })\n const aborts = make.counter('gen_ai.agent.aborts', { description: 'Run abort events.' })\n const toolCalls = make.counter('gen_ai.tool.calls', { description: 'Tool dispatches (tagged by outcome).' })\n const toolErrors = make.counter('gen_ai.tool.errors', { description: 'Native tool errors.' })\n const mcpToolErrors = make.counter('gen_ai.mcp.tool.errors', { description: 'MCP tool errors.' })\n const streamErrors = make.counter('gen_ai.stream.errors', { description: 'Provider stream errors.' })\n const validationRejects = make.counter('gen_ai.validation.rejects', { description: 'Tool input validation rejects.' })\n const validationCoercions = make.counter('gen_ai.validation.coercions', { description: 'Tool input auto-coercions.' })\n const gateBlocks = make.counter('gen_ai.gate.blocks', { description: 'Tool-gate refusals.' })\n const budgetExceeded = make.counter('gen_ai.budget.exceeded', { description: 'Per-turn byte budget exceedances.' })\n const toolBudgetExceeded = make.counter('gen_ai.tool_budget.exceeded', { description: 'Per-tool dispatch budget exceedances.' })\n const pairingRepairs = make.counter('gen_ai.pairing.repairs', { description: 'Tool-pairing repair counts.' })\n const oauthRefreshes = make.counter('gen_ai.oauth.refreshes', { description: 'Provider OAuth credential refreshes.' })\n const mcpErrors = make.counter('gen_ai.mcp.errors', { description: 'MCP server errors.' })\n const mcpAuthRequired = make.counter('gen_ai.mcp.auth.required', { description: 'MCP bootstrap blocked on missing auth.' })\n const costMeter = make.counter('gen_ai.cost_usd', { unit: 'USD', description: 'Cumulative cost across turns.' })\n\n const runsActive = make.upDown('gen_ai.agent.runs.active', { description: 'In-flight agent runs.' })\n\n return {\n install(hooks: Hookable<AgentHooks>): () => void {\n // Per-instrument book-keeping. Each map tracks instrument start times\n // keyed by the identifier that distinguishes concurrent in-flight\n // instances of that kind.\n const turnStart = new Map<string, number>() // turnId -> startedAt\n const toolStart = new Map<string, number>() // callId -> startedAt\n const mcpStart = new Map<string, number>() // callId -> startedAt\n\n const unregisters: Array<() => void> = []\n\n const record = <T extends { record: (v: number, a?: MetricAttributes) => void }>(\n instrument: T | undefined,\n value: number,\n attrs: MetricAttributes,\n kind: string,\n ): void => {\n if (!instrument)\n return\n try {\n instrument.record(value, mergeAttrs(base, attrs))\n }\n catch (err) {\n try {\n onError(kind, err)\n }\n catch { /* ignore */ }\n }\n }\n\n const add = <T extends { add: (v: number, a?: MetricAttributes) => void }>(\n instrument: T | undefined,\n value: number,\n attrs: MetricAttributes,\n kind: string,\n ): void => {\n if (!instrument)\n return\n try {\n instrument.add(value, mergeAttrs(base, attrs))\n }\n catch (err) {\n try {\n onError(kind, err)\n }\n catch { /* ignore */ }\n }\n }\n\n // ---- Agent lifecycle --------------------------------------------\n\n unregisters.push(hooks.hook('agent:start', (ctx) => {\n const attrs: MetricAttributes = {\n 'gen_ai.agent.depth': ctx.depth,\n ...(ctx.agentName ? { 'gen_ai.agent.name': ctx.agentName } : {}),\n }\n add(runsStarted, 1, attrs, 'runs')\n add(runsActive, 1, attrs, 'runs.active')\n }))\n\n unregisters.push(hooks.hook('agent:done', () => {\n add(runsCompleted, 1, {}, 'runs.completed')\n add(runsActive, -1, {}, 'runs.active')\n }))\n\n unregisters.push(hooks.hook('agent:abort', () => {\n add(aborts, 1, {}, 'aborts')\n }))\n\n // ---- Turn / stream metrics -------------------------------------\n\n unregisters.push(hooks.hook('turn:before', (ctx) => {\n turnStart.set(ctx.turnId, Date.now())\n }))\n\n unregisters.push(hooks.hook('turn:after', (ctx) => {\n const started = turnStart.get(ctx.turnId)\n turnStart.delete(ctx.turnId)\n const tagsBase: MetricAttributes = {\n 'gen_ai.operation.name': 'chat',\n ...(ctx.usage.modelId ? { 'gen_ai.response.model': ctx.usage.modelId } : {}),\n ...(ctx.usage.finishReason ? { 'gen_ai.response.finish_reason': ctx.usage.finishReason } : {}),\n }\n if (typeof started === 'number')\n record(turnDuration, Date.now() - started, tagsBase, 'turn.duration')\n if (typeof ctx.usage.timeToFirstTokenMs === 'number')\n record(ttft, ctx.usage.timeToFirstTokenMs, tagsBase, 'ttft')\n\n record(tokenUsage, ctx.usage.input, { ...tagsBase, 'gen_ai.token.type': 'input' }, 'token.input')\n record(tokenUsage, ctx.usage.output, { ...tagsBase, 'gen_ai.token.type': 'output' }, 'token.output')\n if (typeof ctx.usage.cacheRead === 'number' && ctx.usage.cacheRead > 0)\n record(tokenUsage, ctx.usage.cacheRead, { ...tagsBase, 'gen_ai.token.type': 'cache_read' }, 'token.cache_read')\n if (typeof ctx.usage.cacheCreation === 'number' && ctx.usage.cacheCreation > 0)\n record(tokenUsage, ctx.usage.cacheCreation, { ...tagsBase, 'gen_ai.token.type': 'cache_creation' }, 'token.cache_creation')\n\n if (typeof ctx.usage.cost === 'number' && ctx.usage.cost > 0)\n add(costMeter, ctx.usage.cost, tagsBase, 'cost')\n }))\n\n unregisters.push(hooks.hook('stream:error', (ctx) => {\n add(streamErrors, 1, {\n 'http.response.status_code': ctx.statusCode,\n 'error.type': ctx.err instanceof Error ? ctx.err.name : 'unknown',\n }, 'stream.error')\n }))\n\n // ---- Native tool metrics ---------------------------------------\n\n unregisters.push(hooks.hook('tool:before', (ctx) => {\n toolStart.set(ctx.callId, Date.now())\n }))\n\n unregisters.push(hooks.hook('tool:after', (ctx) => {\n const started = toolStart.get(ctx.callId)\n toolStart.delete(ctx.callId)\n const tags: MetricAttributes = { 'gen_ai.tool.name': ctx.name }\n if (typeof started === 'number')\n record(toolDuration, Date.now() - started, tags, 'tool.duration')\n record(toolOutput, ctx.outputBytes, tags, 'tool.output_bytes')\n }))\n\n // NOTE: `tool:error` must NOT delete `toolStart[callId]` — on the\n // execute-error path the loop still fires `tool:after` afterwards\n // (with the `Tool error: …` payload), and that's where the errored\n // call's duration gets recorded + the entry cleaned up.\n unregisters.push(hooks.hook('tool:error', (ctx) => {\n add(toolErrors, 1, {\n 'gen_ai.tool.name': ctx.name,\n 'error.type': ctx.error.name,\n }, 'tool.errors')\n }))\n\n // Mid-flight per-call cancels close with `tool:cancelled` instead of\n // `tool:after` — clean up the start entry here or it leaks.\n unregisters.push(hooks.hook('tool:cancelled', (ctx) => {\n toolStart.delete(ctx.callId)\n }))\n\n unregisters.push(hooks.hook('tool:dispatched', (ctx) => {\n add(toolCalls, 1, {\n 'gen_ai.tool.name': ctx.name,\n 'outcome': ctx.outcome,\n }, 'tool.calls')\n if (ctx.outcome === 'gate-block') {\n add(gateBlocks, 1, {\n 'gen_ai.tool.name': ctx.name,\n ...(ctx.reason ? { reason: ctx.reason } : {}),\n }, 'gate.blocks')\n }\n // Unknown-tool dispatches fire `tool:before` (with `unknown: true`)\n // but never `tool:after` — drop the start entry so hallucinated\n // tool names can't grow the map unboundedly. `tool:dispatched` for\n // real executions fires BEFORE `tool:before`, so this only affects\n // the unknown path.\n if (ctx.outcome === 'unknown')\n toolStart.delete(ctx.callId)\n }))\n\n unregisters.push(hooks.hook('validation:reject', (ctx) => {\n add(validationRejects, 1, { 'gen_ai.tool.name': ctx.name }, 'validation.rejects')\n }))\n\n unregisters.push(hooks.hook('validation:coerce', (ctx) => {\n add(validationCoercions, 1, {\n 'gen_ai.tool.name': ctx.name,\n 'coercions': ctx.coercions.length,\n }, 'validation.coercions')\n }))\n\n unregisters.push(hooks.hook('budget:exceeded', (ctx) => {\n add(budgetExceeded, 1, {\n bytes: ctx.bytes,\n budget: ctx.budget,\n }, 'budget.exceeded')\n }))\n\n unregisters.push(hooks.hook('tool-budget:exceeded', (ctx) => {\n add(toolBudgetExceeded, 1, {\n 'gen_ai.tool.name': ctx.tool,\n 'mode': ctx.mode,\n 'count': ctx.count,\n 'max': ctx.max,\n }, 'tool_budget.exceeded')\n }))\n\n unregisters.push(hooks.hook('pairing:repair', (ctx) => {\n add(pairingRepairs, 1, { mode: ctx.mode }, 'pairing.repairs')\n }))\n\n unregisters.push(hooks.hook('oauth:refresh', (ctx) => {\n add(oauthRefreshes, 1, { provider: ctx.provider, source: ctx.source }, 'oauth.refreshes')\n }))\n\n // ---- MCP metrics -----------------------------------------------\n\n unregisters.push(hooks.hook('mcp:tool:before', (ctx) => {\n mcpStart.set(ctx.callId, Date.now())\n }))\n\n unregisters.push(hooks.hook('mcp:tool:after', (ctx) => {\n const started = mcpStart.get(ctx.callId)\n mcpStart.delete(ctx.callId)\n const tags: MetricAttributes = {\n 'gen_ai.mcp.server': ctx.server,\n 'gen_ai.tool.name': ctx.displayName,\n }\n if (typeof started === 'number')\n record(mcpToolDuration, Date.now() - started, tags, 'mcp.tool.duration')\n }))\n\n unregisters.push(hooks.hook('mcp:tool:error', (ctx) => {\n mcpStart.delete(ctx.callId)\n add(mcpToolErrors, 1, {\n 'gen_ai.mcp.server': ctx.server,\n 'gen_ai.tool.name': ctx.displayName,\n 'error.type': ctx.error.name,\n }, 'mcp.tool.errors')\n }))\n\n unregisters.push(hooks.hook('mcp:bootstrap:end', (ctx) => {\n record(mcpBootstrapDuration, ctx.durationMs, {\n 'gen_ai.mcp.server': ctx.name,\n 'ok': ctx.ok,\n }, 'mcp.bootstrap.duration')\n }))\n\n unregisters.push(hooks.hook('mcp:error', (ctx) => {\n add(mcpErrors, 1, {\n 'gen_ai.mcp.server': ctx.name,\n 'error.type': ctx.error.name,\n }, 'mcp.errors')\n }))\n\n unregisters.push(hooks.hook('mcp:auth:required', (ctx) => {\n add(mcpAuthRequired, 1, {\n 'gen_ai.mcp.server': ctx.name,\n 'transport': ctx.transport,\n 'reason': ctx.reason,\n }, 'mcp.auth.required')\n }))\n\n // -----------------------------------------------------------------\n // Disposal\n // -----------------------------------------------------------------\n\n let disposed = false\n return function uninstall() {\n if (disposed)\n return\n disposed = true\n for (const un of unregisters) {\n try {\n un()\n }\n catch { /* ignore */ }\n }\n turnStart.clear()\n toolStart.clear()\n mcpStart.clear()\n }\n },\n }\n}\n\n/**\n * Defensive factory wrapper — returns undefined when meter creation\n * throws. Lets a half-broken meter (one unsupported instrument) still\n * give partial metrics rather than collapsing the whole install.\n */\nfunction safeFactory<T>(\n factory: () => T,\n name: string,\n onError: (kind: string, err: unknown) => void,\n): T | undefined {\n try {\n return factory()\n }\n catch (err) {\n try {\n onError(`createInstrument:${name}`, err)\n }\n catch { /* ignore */ }\n return undefined\n }\n}\n","import type { AgentHookMap } from './agent'\nimport type { ToolOutcome, ToolResultContent } from './types'\n\ntype MaybePromise<T> = T | Promise<T>\n\nexport type SuccessfulMutationOutcome = Extract<ToolOutcome, 'created' | 'updated' | 'edited'>\n\nexport interface MutationValidationMutation {\n turnId: string\n callId: string\n tool: string\n displayName: string\n input: Record<string, unknown>\n outcome: SuccessfulMutationOutcome\n result: string | ToolResultContent[]\n}\n\nexport interface MutationValidationBatch {\n turnId: string\n mutations: readonly MutationValidationMutation[]\n}\n\nexport type MutationValidationResult\n = | { ok: true }\n | { ok: false, message?: string, errors?: readonly string[] }\n\nexport interface MutationValidationFailure {\n batch: MutationValidationBatch\n result: Extract<MutationValidationResult, { ok: false }>\n message: string\n failureCount: number\n}\n\nexport interface MutationValidationHooksOptions {\n validate: (batch: MutationValidationBatch) => MaybePromise<MutationValidationResult | void>\n /**\n * Called when validation fails and the run has not crossed\n * `maxFailuresPerRun`. Hosts typically call `agent.followUp(message)` here.\n */\n onFailure?: (failure: MutationValidationFailure) => MaybePromise<void>\n buildFailureMessage?: (failure: Omit<MutationValidationFailure, 'message'>) => string\n onError?: (error: unknown, batch: MutationValidationBatch) => MaybePromise<void>\n maxFailuresPerRun?: number\n}\n\nfunction defaultFailureMessage(failure: Omit<MutationValidationFailure, 'message'>): string {\n const changed = failure.batch.mutations\n .map(m => `${m.displayName} ${String(m.input.path ?? m.callId)}`)\n .join(', ')\n const details = failure.result.message\n ?? failure.result.errors?.join('\\n')\n ?? 'Validation failed after the last file mutation.'\n const seen = failure.failureCount > 1 ? ` (failure ${failure.failureCount})` : ''\n return `[Mutation validation failed${seen}] ${changed}\\n${details}\\nFix the validation errors with the smallest focused change.`\n}\n\nfunction isSuccessfulMutation(outcome: ToolOutcome | undefined): outcome is SuccessfulMutationOutcome {\n return outcome === 'created' || outcome === 'updated' || outcome === 'edited'\n}\n\n/**\n * Build host-side hooks for post-mutation validation without changing the\n * built-in edit/write tools. The helper only observes successful mutations\n * reported through `tool:after.outcome`; validation commands and recovery\n * prompts remain host policy.\n */\nexport function createMutationValidationHooks(options: MutationValidationHooksOptions): AgentHookMap {\n const pending: MutationValidationMutation[] = []\n let failureCount = 0\n const maxFailures = Math.max(1, Math.floor(options.maxFailuresPerRun ?? 2))\n\n return {\n 'tool:after': (ctx) => {\n if (!isSuccessfulMutation(ctx.outcome))\n return\n pending.push({\n turnId: ctx.turnId,\n callId: ctx.callId,\n tool: ctx.name,\n displayName: ctx.displayName,\n input: ctx.input,\n outcome: ctx.outcome,\n result: ctx.result,\n })\n },\n 'tool-results:after': async (ctx) => {\n if (pending.length === 0)\n return\n const mutations = pending.splice(0)\n const batch: MutationValidationBatch = {\n turnId: ctx.turnId,\n mutations,\n }\n let result: MutationValidationResult | void\n try {\n result = await options.validate(batch)\n }\n catch (err) {\n await options.onError?.(err, batch)\n return\n }\n if (!result || result.ok)\n return\n failureCount++\n if (failureCount > maxFailures)\n return\n const withoutMessage = { batch, result, failureCount }\n const message = options.buildFailureMessage?.(withoutMessage)\n ?? defaultFailureMessage(withoutMessage)\n await options.onFailure?.({ ...withoutMessage, message })\n },\n 'agent:done': () => {\n pending.length = 0\n // `agent:done` fires at the end of every run, so resetting here gives\n // `maxFailuresPerRun` true per-run semantics even when this hook map is\n // registered at agent level and reused across runs.\n failureCount = 0\n },\n }\n}\n","/**\n * Tracing helper — wraps agent lifecycle hooks in caller-provided spans.\n *\n * Zidane is hooks-native; rather than introducing a plugin abstraction just for\n * observability, we ship a small helper that turns an arbitrary `startSpan`\n * function into a bundle of hook handlers. Works with Sentry, OpenTelemetry,\n * Datadog — any tracer that can hand back an object with an `end()` method.\n *\n * Attribute conventions follow the Sentry AI Agents spec (which itself\n * tracks OpenTelemetry Gen AI semconv v1.36, with a few divergences). The\n * `conventions` option lets callers pick `'sentry'` (default — Sentry's\n * exact keys), `'otel'` (vendor-neutral OTel 1.36), or `'both'` (emit\n * every variant for maximum portability).\n *\n * Span coverage:\n *\n * - `invoke_agent <name?>` — root span, opens on `agent:start`, closes on `agent:done`. Sentry op `gen_ai.invoke_agent`.\n * - `chat <model?>` — per-turn LLM call, opens on `turn:before`, closes on `turn:after`. Sentry op `gen_ai.chat`.\n * - `execute_tool <name>` — native tool execution, opens on `tool:before`, closes on `tool:after` / `tool:error`. Sentry op `gen_ai.execute_tool`.\n * - `execute_tool <server>.<name>` — MCP tool variant, same op. Tagged with `gen_ai.tool.type: 'extension'`.\n * - `handoff to <task>` — subagent handoff (parent→child), opens on `spawn:before`, closes on `spawn:complete` / `spawn:error`. Sentry op `gen_ai.handoff`.\n * Also injects parent trace context into the spawn carrier when `propagator` is configured.\n * - `mcp.bootstrap <server>` — server bootstrap, opens on `mcp:bootstrap:start`, closes on `mcp:bootstrap:end`. Zidane-specific (no Sentry op equivalent).\n *\n * Span events (not spans — recorded on the active span via `addEvent`):\n *\n * - `gen_ai.gate.block` — a `tool:gate` listener refused a call.\n * - `gen_ai.validation.reject` — tool input failed schema validation.\n * - `gen_ai.validation.coerce` — tool input was auto-coerced to satisfy the schema.\n * - `gen_ai.budget.exceeded` — byte budget exceeded (`budget:exceeded`).\n * - `gen_ai.tool_budget.exceeded` — per-tool dispatch cap exceeded.\n * - `gen_ai.pairing.repair` — pre-send pairing repair fired.\n * - `gen_ai.stream.error` — provider stream errored (carries `statusCode` / `requestId`).\n * - `gen_ai.mcp.auth.required` — MCP server bootstrap blocked on missing OAuth tokens.\n * - `gen_ai.oauth.refresh` — provider OAuth credentials refreshed.\n *\n * Attribute naming follows the Sentry AI Agents conventions\n * (https://develop.sentry.dev/sdk/telemetry/traces/modules/ai-agents/) by\n * default — which closely track OTel Gen AI semconv v1.36 with a few\n * intentional differences (`usage.input_tokens.cached` instead of\n * `usage.cache_read_input_tokens`, `cost.total_tokens` instead of\n * `usage.cost_usd`, seconds instead of ms for `time_to_first_token`).\n * Set `conventions: 'otel'` to emit only the vendor-neutral OTel keys, or\n * `'both'` to emit everything for maximum portability. Legacy attribute\n * names (`inputTokens`, `toolName`, `displayName`, …) are also emitted by\n * default for back-compat; set `legacyAttributes: false` to drop them.\n *\n * On `agent:done` or `uninstall()` it closes any spans still open (defensive —\n * normally all tool/turn spans have matching end hooks, but an abort\n * mid-execution can leave dangling ones).\n *\n * Returns an `install(hooks)` helper that registers every handler at once and\n * yields an `uninstall()` function for cleanup. Safe across multiple runs.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { SessionMessage } from './types'\n\n/** Minimal span shape — any tracer that provides these methods is compatible. */\nexport interface Span {\n /** Close the span. Called exactly once per span. */\n end: () => void\n /** Optional: attach additional attributes after the span is started (ignored if unsupported). */\n setAttributes?: (attrs: Record<string, unknown>) => void\n /**\n * Optional: record a structured event on the span. Used for non-span\n * occurrences (gate blocks, validation rejects, budget hits, pairing\n * repairs). Maps to OTel's `Span.addEvent` and Sentry's `addBreadcrumb`.\n * Tracers without an event surface should treat this as a no-op (the\n * helper falls back to `setAttributes` with an `event.*` key prefix).\n */\n addEvent?: (name: string, attrs?: Record<string, unknown>) => void\n}\n\n/**\n * Function that opens a span. Caller-provided so we stay tracer-agnostic.\n *\n * `parentContext` carries opaque trace metadata propagated from another\n * agent (typically a W3C `{ traceparent, tracestate }` carrier received on\n * `agent:start.tracingContext` after a parent agent's tracer injected it on\n * `spawn:before`). Implementations that integrate with OTel should extract\n * the carrier into a `Context` and use it as the parent when opening the\n * span; implementations that don't care about cross-agent linkage can\n * ignore the third argument entirely.\n */\nexport type StartSpan = (\n name: string,\n attrs?: Record<string, unknown>,\n parentContext?: Readonly<Record<string, string>>,\n) => Span\n\nexport type TracingConventions = 'sentry' | 'otel' | 'both'\n\nexport interface TracingHooksOptions {\n /** Tracer seam. Receives a span name + attributes; must return a `Span`. */\n startSpan: StartSpan\n /**\n * Optional attribute namespace. Prepended to every span name with a `/`\n * separator (e.g. `\"agent\"` → `agent/chat <model>`, `agent/execute_tool Bash`).\n *\n * Empty / undefined = no prefix.\n */\n namespace?: string\n /**\n * Which Gen-AI attribute conventions to emit.\n *\n * - `'sentry'` (default) — Sentry AI Agents conventions. Most common\n * choice — Sentry, Datadog AI, Honeycomb derived dashboards and\n * Langfuse all consume these.\n * - `'otel'` — vendor-neutral OpenTelemetry Gen AI semconv v1.36.\n * Diverges from Sentry on cache-token keys, cost keys, and TTFT unit.\n * - `'both'` — emit every variant. Doubles the per-span attribute\n * payload; pick when shipping to multiple backends with different\n * ingestion conventions.\n */\n conventions?: TracingConventions\n /**\n * Capture the actual prompt / completion text on spans\n * (`gen_ai.input.messages`, `gen_ai.output.messages`,\n * `gen_ai.system_instructions`, `gen_ai.tool.definitions`,\n * `gen_ai.tool.call.arguments`, `gen_ai.tool.call.result`).\n *\n * Defaults to `true` (required for the Sentry AI Agents conversation\n * viewer). Full prompts and tool arguments can carry secrets and PII;\n * captured content flows through `redact`, so pair the default with a\n * redactor when payloads may hold secrets, or set `false` to keep all\n * content-shaped data in-process.\n */\n captureMessageContent?: boolean\n /**\n * Emit legacy attribute keys (`inputTokens`, `outputTokens`, `toolName`,\n * `displayName`, `finishReason`, `modelId`) alongside the new\n * `gen_ai.*` semconv keys. Defaults to `true` so existing dashboards\n * keep working. Set `false` once you've migrated all consumers off the\n * legacy names.\n */\n legacyAttributes?: boolean\n /**\n * Error sink for tracer failures. Replaces the historic silent-swallow.\n * Called when `Span.end()`, `setAttributes()`, `addEvent()`, or\n * `startSpan()` throws — so degraded tracers stay visible. The helper\n * still does not let tracer errors propagate into the agent loop.\n *\n * `kind` identifies which step failed (`'startSpan'`, `'end'`,\n * `'setAttributes'`, `'addEvent'`, `'redact'`, `'getActiveTraceContext'`).\n * Default: no-op (silent).\n */\n onError?: (kind: string, err: unknown) => void\n /**\n * Optional callback the helper invokes on `spawn:before` (after opening\n * the spawn span) to read the active trace context. Whatever it returns\n * is written into `ctx.tracingContext` and forwarded to the child's\n * `agent.run({ tracingContext })`. Typical use:\n *\n * ```ts\n * getActiveTraceContext: () => {\n * const carrier: Record<string, string> = {}\n * propagation.inject(context.active(), carrier)\n * return carrier\n * }\n * ```\n *\n * Returning `undefined` or an empty object leaves the carrier empty\n * and the child runs with no parent context. The helper's own\n * `propagator` is preferred over this when both are set (the\n * propagator runs inside the helper; this callback is the escape\n * hatch for hosts wanting full control).\n */\n getActiveTraceContext?: () => Readonly<Record<string, string>> | undefined\n /**\n * Optional in-process span redactor. When set, every potentially\n * sensitive string (tool input, tool result, system prompt) flows\n * through this fn before landing on a span attribute / event. Returning\n * the input unchanged is a no-op.\n *\n * Composes with the harness-wide `tracing:redact` hook: if a host has\n * already registered a hook handler that mutates `ctx.redacted`, the\n * tracer reuses that pipeline; setting `redact` here registers an extra\n * step that runs only for the tracer's attributes. The hook is the\n * canonical path; `redact` is the convenience surface for tracer-only\n * setups.\n */\n redact?: (kind: string, value: string, meta?: Readonly<Record<string, unknown>>) => string\n}\n\n/** Value returned by {@link createTracingHooks} — install entrypoint. */\nexport interface TracingHookSet {\n /**\n * Attach every hook handler to the given agent hooks instance.\n *\n * @returns an `uninstall` function that detaches every handler and closes any\n * still-open spans. Safe to call multiple times.\n */\n install: (hooks: Hookable<AgentHooks>) => () => void\n}\n\n// ---------------------------------------------------------------------------\n// Gen AI semantic-convention attribute keys\n// ---------------------------------------------------------------------------\n\n/**\n * Stable keys we emit unconditionally — present in BOTH Sentry and OTel\n * conventions with identical semantics, so no `conventions` branching is\n * needed at the call site.\n */\nconst GEN_AI = {\n system: 'gen_ai.system',\n operationName: 'gen_ai.operation.name',\n requestModel: 'gen_ai.request.model',\n responseModel: 'gen_ai.response.model',\n responseFinishReasons: 'gen_ai.response.finish_reasons',\n responseId: 'gen_ai.response.id',\n responseStreaming: 'gen_ai.response.streaming',\n responseTokensPerSecond: 'gen_ai.response.tokens_per_second',\n // Sentry uses seconds; OTel uses ms. We emit one or both based on `conventions`.\n responseTimeToFirstTokenSeconds: 'gen_ai.response.time_to_first_token',\n responseTimeToFirstTokenMs: 'gen_ai.client.time_to_first_token',\n // Usage — Sentry expects input_tokens to INCLUDE cached, with subkeys for cache slices.\n usageInputTokens: 'gen_ai.usage.input_tokens',\n usageOutputTokens: 'gen_ai.usage.output_tokens',\n usageTotalTokens: 'gen_ai.usage.total_tokens',\n // Sentry-specific cache keys.\n usageInputTokensCached: 'gen_ai.usage.input_tokens.cached',\n usageInputTokensCacheWrite: 'gen_ai.usage.input_tokens.cache_write',\n usageOutputTokensReasoning: 'gen_ai.usage.output_tokens.reasoning',\n // OTel cache keys (older / vendor-neutral).\n usageCacheReadInputTokens: 'gen_ai.usage.cache_read_input_tokens',\n usageCacheCreationInputTokens: 'gen_ai.usage.cache_creation_input_tokens',\n usageReasoningTokens: 'gen_ai.usage.reasoning_tokens',\n // Cost — Sentry splits, OTel rolls up.\n costTotalTokens: 'gen_ai.cost.total_tokens',\n costInputTokens: 'gen_ai.cost.input_tokens',\n costOutputTokens: 'gen_ai.cost.output_tokens',\n usageCostUsd: 'gen_ai.usage.cost_usd',\n // Tool — Sentry uses `tool.call.arguments` / `tool.call.result`; OTel uses `tool.input` / `tool.output` (deprecated in Sentry).\n toolName: 'gen_ai.tool.name',\n toolDescription: 'gen_ai.tool.description',\n toolType: 'gen_ai.tool.type',\n toolCallId: 'gen_ai.tool.call.id',\n toolCallArguments: 'gen_ai.tool.call.arguments',\n toolCallResult: 'gen_ai.tool.call.result',\n toolMessage: 'gen_ai.tool.message',\n toolInputDeprecated: 'gen_ai.tool.input',\n toolOutputDeprecated: 'gen_ai.tool.output',\n // Request configuration.\n requestMaxTokens: 'gen_ai.request.max_tokens',\n requestTemperature: 'gen_ai.request.temperature',\n requestTopP: 'gen_ai.request.top_p',\n requestTopK: 'gen_ai.request.top_k',\n requestSeed: 'gen_ai.request.seed',\n requestFrequencyPenalty: 'gen_ai.request.frequency_penalty',\n requestPresencePenalty: 'gen_ai.request.presence_penalty',\n // Message content surfaces (Sentry conversation viewer).\n inputMessages: 'gen_ai.input.messages',\n outputMessages: 'gen_ai.output.messages',\n systemInstructions: 'gen_ai.system_instructions',\n toolDefinitions: 'gen_ai.tool.definitions',\n // Agent identity.\n agentName: 'gen_ai.agent.name',\n agentRunId: 'gen_ai.agent.run.id',\n agentParentRunId: 'gen_ai.agent.parent_run.id',\n agentDepth: 'gen_ai.agent.depth',\n pipelineName: 'gen_ai.pipeline.name',\n turn: 'gen_ai.agent.turn',\n // MCP-specific (zidane extension; no Sentry op equivalent).\n mcpServer: 'gen_ai.mcp.server',\n mcpToolCount: 'gen_ai.mcp.tool_count',\n} as const\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Compose namespace prefix once. */\nfunction prefixed(namespace: string | undefined, name: string): string {\n return namespace ? `${namespace}/${name}` : name\n}\n\n/** Drop undefined entries — tracers vary on how they render `undefined`. */\nfunction compact(attrs: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(attrs)) {\n if (v !== undefined)\n out[k] = v\n }\n return out\n}\n\n/**\n * Convert a zidane `SessionMessage` (or `StreamOptions.messages` entry)\n * into Sentry's `{role, parts: [{type, content}]}` shape, JSON-stringify\n * the result. Returns `undefined` on serialization failure so the caller\n * skips the attribute rather than poisoning the span.\n *\n * Per Sentry footnote [7], binary blobs in image content are replaced\n * with `\"[Blob substitute]\"`. Tool calls become `{type: 'tool_call'}`\n * parts; tool results become `{type: 'tool_result'}` parts.\n */\ninterface SentryMessagePart {\n type: 'text' | 'tool_call' | 'tool_result' | 'reasoning'\n content?: string\n name?: string\n arguments?: string\n result?: string\n call_id?: string\n}\ninterface SentryMessage {\n role: 'user' | 'assistant' | 'system' | 'tool'\n parts: SentryMessagePart[]\n}\n\n/**\n * Wide-shape block record. `SessionContentBlock` is a discriminated\n * union — accepting the wide record lets us peek at the discriminator\n * without re-importing the entire union at this layer.\n */\ninterface AnyBlock { type: string, [k: string]: unknown }\n\nfunction blockToParts(block: AnyBlock): SentryMessagePart[] {\n switch (block.type) {\n case 'text':\n return [{ type: 'text', content: typeof block.text === 'string' ? block.text : '' }]\n case 'image':\n case 'audio':\n case 'video':\n case 'document':\n return [{ type: 'text', content: '[Blob substitute]' }]\n case 'tool_call':\n return [{\n type: 'tool_call',\n ...(typeof block.name === 'string' ? { name: block.name } : {}),\n ...(typeof block.id === 'string' ? { call_id: block.id } : {}),\n arguments: safeJson(block.input),\n }]\n case 'tool_result': {\n const output = block.output\n const text = typeof output === 'string'\n ? output\n : Array.isArray(output)\n ? (output as Array<{ type: string, text?: string }>)\n .map(b => (b.type === 'image' || b.type === 'audio' || b.type === 'video' || b.type === 'document') ? '[Blob substitute]' : (b.text ?? ''))\n .join('\\n')\n : ''\n return [{\n type: 'tool_result',\n ...(typeof block.callId === 'string' ? { call_id: block.callId } : {}),\n content: text,\n }]\n }\n case 'thinking':\n return [{ type: 'reasoning', content: typeof block.text === 'string' ? block.text : '' }]\n default:\n return []\n }\n}\n\nfunction messageToSentry(msg: { role: 'user' | 'assistant', content: readonly AnyBlock[] }): SentryMessage {\n const parts: SentryMessagePart[] = []\n for (const block of msg.content)\n parts.push(...blockToParts(block))\n return { role: msg.role, parts }\n}\n\nfunction safeJson(value: unknown): string {\n try {\n return JSON.stringify(value ?? null)\n }\n catch {\n return '\"[unserializable]\"'\n }\n}\n\n/**\n * Stringify an array of `SessionMessage`s into Sentry's `gen_ai.input.messages`\n * format. Each entry's role + content is mapped via `messageToSentry`.\n * Returns `undefined` when the input is empty or unserializable.\n */\nfunction stringifyMessages(messages: readonly SessionMessage[]): string | undefined {\n if (messages.length === 0)\n return undefined\n try {\n const sentry = messages.map(m => messageToSentry({\n role: m.role,\n content: m.content as readonly AnyBlock[],\n }))\n return JSON.stringify(sentry)\n }\n catch {\n return undefined\n }\n}\n\n/**\n * Stringify a `StreamOptions.tools` array into Sentry's\n * `gen_ai.tool.definitions` format: `[{name, description?, parameters?}, …]`.\n *\n * The input is `unknown[]` because `StreamOptions.tools` carries the\n * provider-formatted shape (Anthropic / OpenAI / OpenAI-compat all\n * differ). We probe the three names that overlap (`name`, `description`,\n * `inputSchema` / `parameters`) and degrade gracefully otherwise.\n */\nfunction stringifyToolDefs(tools: readonly unknown[] | undefined): string | undefined {\n if (!tools || tools.length === 0)\n return undefined\n try {\n return JSON.stringify(tools.map((raw) => {\n if (!raw || typeof raw !== 'object')\n return { name: 'anonymous' }\n const t = raw as Record<string, unknown>\n const name = typeof t.name === 'string' ? t.name : 'anonymous'\n const description = typeof t.description === 'string' ? t.description : undefined\n // OpenAI's wire format calls it `parameters`; Anthropic / ToolSpec\n // call it `input_schema` / `inputSchema`. Probe all three.\n const parameters = t.parameters ?? t.input_schema ?? t.inputSchema\n return {\n name,\n ...(description ? { description } : {}),\n ...(parameters !== undefined ? { parameters } : {}),\n }\n }))\n }\n catch {\n return undefined\n }\n}\n\n/**\n * Build the usage attribute set per the configured conventions. Sentry\n * expects `input_tokens` to include cached, with `input_tokens.cached`\n * + `input_tokens.cache_write` subkeys; OTel splits cache into\n * separate top-level keys. `'both'` emits everything.\n */\nfunction buildUsageAttrs(\n usage: {\n input: number\n output: number\n cacheRead?: number\n cacheCreation?: number\n thinking?: number\n cost?: number\n modelId?: string\n finishReason?: string\n timeToFirstTokenMs?: number\n },\n conventions: TracingConventions,\n): Record<string, unknown> {\n const cacheRead = usage.cacheRead ?? 0\n const cacheWrite = usage.cacheCreation ?? 0\n // Per Sentry: `input_tokens` includes cached. zidane reports `input` as\n // the uncached new-input slice, so the headline number is the sum.\n const inputInclCache = usage.input + cacheRead + cacheWrite\n const totalTokens = inputInclCache + usage.output\n const wantSentry = conventions === 'sentry' || conventions === 'both'\n const wantOtel = conventions === 'otel' || conventions === 'both'\n\n const out: Record<string, unknown> = {\n [GEN_AI.responseModel]: usage.modelId,\n [GEN_AI.responseFinishReasons]: usage.finishReason ? [usage.finishReason] : undefined,\n [GEN_AI.usageOutputTokens]: usage.output,\n [GEN_AI.usageTotalTokens]: totalTokens,\n }\n\n if (wantSentry) {\n out[GEN_AI.usageInputTokens] = inputInclCache\n if (cacheRead > 0)\n out[GEN_AI.usageInputTokensCached] = cacheRead\n if (cacheWrite > 0)\n out[GEN_AI.usageInputTokensCacheWrite] = cacheWrite\n if (typeof usage.thinking === 'number' && usage.thinking > 0)\n out[GEN_AI.usageOutputTokensReasoning] = usage.thinking\n if (typeof usage.cost === 'number')\n out[GEN_AI.costTotalTokens] = usage.cost\n if (typeof usage.timeToFirstTokenMs === 'number')\n out[GEN_AI.responseTimeToFirstTokenSeconds] = usage.timeToFirstTokenMs / 1000\n }\n if (wantOtel) {\n // OTel: input_tokens is the uncached slice; cache is separate.\n if (!wantSentry)\n out[GEN_AI.usageInputTokens] = usage.input\n if (cacheRead > 0)\n out[GEN_AI.usageCacheReadInputTokens] = cacheRead\n if (cacheWrite > 0)\n out[GEN_AI.usageCacheCreationInputTokens] = cacheWrite\n if (typeof usage.thinking === 'number' && usage.thinking > 0)\n out[GEN_AI.usageReasoningTokens] = usage.thinking\n if (typeof usage.cost === 'number')\n out[GEN_AI.usageCostUsd] = usage.cost\n if (typeof usage.timeToFirstTokenMs === 'number')\n out[GEN_AI.responseTimeToFirstTokenMs] = usage.timeToFirstTokenMs\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Build a set of tracing hook handlers that can be installed on an agent.\n *\n * @example Sentry\n * ```ts\n * const tracing = createTracingHooks({\n * startSpan: (name, attrs) => Sentry.startInactiveSpan({ name, attributes: attrs }),\n * })\n * const uninstall = tracing.install(agent.hooks)\n * try { await agent.run({ prompt }) }\n * finally { uninstall() }\n * ```\n *\n * @example OpenTelemetry with parent-context propagation\n * ```ts\n * import { trace, context, propagation } from '@opentelemetry/api'\n *\n * const tracer = trace.getTracer('zidane')\n * const tracing = createTracingHooks({\n * startSpan: (name, attrs, parentCtx) => {\n * const ctx = parentCtx ? propagation.extract(context.active(), parentCtx) : context.active()\n * return tracer.startSpan(name, { attributes: attrs }, ctx)\n * },\n * getActiveTraceContext: () => {\n * const carrier: Record<string, string> = {}\n * propagation.inject(context.active(), carrier)\n * return carrier\n * },\n * })\n * ```\n */\nexport function createTracingHooks(options: TracingHooksOptions): TracingHookSet {\n const namespace = options.namespace\n const legacy = options.legacyAttributes ?? true\n const conventions = options.conventions ?? 'sentry'\n const wantSentry = conventions === 'sentry' || conventions === 'both'\n const captureContent = options.captureMessageContent !== false\n const onError = options.onError ?? (() => {})\n\n return {\n install(hooks: Hookable<AgentHooks>): () => void {\n // Span book-keeping. Each map keys by the identifier that's unique\n // across concurrent in-flight spans of that kind.\n const runSpans = new Map<string, Span>() // keyed by runId\n const turnSpans = new Map<string, Span>() // keyed by turnId\n const toolSpans = new Map<string, Span>() // keyed by callId\n const mcpSpans = new Map<string, Span>() // keyed by callId\n const spawnSpans = new Map<string, Span>() // keyed by spawn id\n const bootstrapSpans = new Map<string, Span>() // keyed by server name\n // Provider system identifier (`anthropic`, `openai`, …) captured at\n // `agent:start`. Stamped onto every chat / tool span belonging to\n // this run so Sentry's per-vendor breakdowns work. Reset on\n // `agent:done`.\n let activeSystem: string | undefined\n // Active turn book-keeping for tokens-per-second derivation.\n const turnTrack = new Map<string, { startedAt: number }>()\n // Active run span ref — used so non-span events (gate blocks,\n // budget hits, validation rejects, policy/pairing repairs) can\n // attach via `addEvent` on the in-flight run span. The run span is\n // the natural parent for cross-cutting policy events: it outlives\n // turn spans (which close before tool dispatch starts in the\n // current loop), and tool spans (which haven't opened on a\n // gate-block path).\n let activeRunSpan: Span | undefined\n\n function safeStartSpan(\n name: string,\n attrs: Record<string, unknown>,\n parentContext?: Readonly<Record<string, string>>,\n ): Span | undefined {\n try {\n return options.startSpan(prefixed(namespace, name), compact(attrs), parentContext)\n }\n catch (err) {\n try {\n onError('startSpan', err)\n }\n catch { /* ignore */ }\n return undefined\n }\n }\n\n function safeSetAttrs(span: Span | undefined, attrs: Record<string, unknown>): void {\n if (!span?.setAttributes)\n return\n try {\n span.setAttributes(compact(attrs))\n }\n catch (err) {\n try {\n onError('setAttributes', err)\n }\n catch { /* ignore */ }\n }\n }\n\n function safeEnd(map: Map<string, Span>, key: string): void {\n const span = map.get(key)\n if (!span)\n return\n try {\n span.end()\n }\n catch (err) {\n try {\n onError('end', err)\n }\n catch { /* ignore */ }\n }\n map.delete(key)\n }\n\n function endAll(map: Map<string, Span>): void {\n for (const [, span] of map) {\n try {\n span.end()\n }\n catch (err) {\n try {\n onError('end', err)\n }\n catch { /* ignore */ }\n }\n }\n map.clear()\n }\n\n function safeAddEvent(span: Span | undefined, name: string, attrs: Record<string, unknown>): void {\n if (!span)\n return\n if (typeof span.addEvent === 'function') {\n try {\n span.addEvent(name, compact(attrs))\n }\n catch (err) {\n try {\n onError('addEvent', err)\n }\n catch { /* ignore */ }\n }\n return\n }\n // Tracer doesn't support events — fall back to a single\n // `event.<name>.*` attribute so the data lands somewhere.\n safeSetAttrs(span, Object.fromEntries(\n Object.entries(compact(attrs)).map(([k, v]) => [`event.${name}.${k}`, v]),\n ))\n }\n\n function redact(kind: string, value: string, meta?: Readonly<Record<string, unknown>>): string {\n if (typeof options.redact !== 'function')\n return value\n try {\n return options.redact(kind, value, meta)\n }\n catch (err) {\n try {\n onError('redact', err)\n }\n catch { /* ignore */ }\n return value\n }\n }\n\n const unregisters: Array<() => void> = []\n\n // -----------------------------------------------------------------\n // agent.run (root)\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('agent:start', (ctx) => {\n activeSystem = ctx.providerName\n // Empty-string names produce `invoke_agent ` (trailing space).\n // Treat empty as \"no name\" so the span name reads cleanly.\n const displayName = ctx.agentName && ctx.agentName.length > 0\n ? ctx.agentName\n : 'agent'\n const span = safeStartSpan(\n `invoke_agent ${displayName}`,\n {\n [GEN_AI.operationName]: 'invoke_agent',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.agentName]: ctx.agentName,\n [GEN_AI.agentRunId]: ctx.runId,\n [GEN_AI.agentParentRunId]: ctx.parentRunId,\n [GEN_AI.agentDepth]: ctx.depth,\n // Sentry-specific span op hint — backends that key off\n // `op` (Sentry Python/JS) read this directly; OTel\n // backends ignore unknown keys, so it's harmless.\n 'sentry.op': 'gen_ai.invoke_agent',\n ...(legacy\n ? {\n runId: ctx.runId,\n parentRunId: ctx.parentRunId,\n agentName: ctx.agentName,\n depth: ctx.depth,\n }\n : {}),\n },\n ctx.tracingContext,\n )\n if (span) {\n runSpans.set(ctx.runId, span)\n activeRunSpan = span\n }\n }))\n\n unregisters.push(hooks.hook('agent:done', (stats) => {\n // `agent:done` doesn't carry a runId on its payload (it's `AgentStats`).\n // The 99% case is a single in-flight run — close every open run span\n // and stamp the totals on each. Multi-run-concurrent users plug a\n // runId into stats via their own integration; for now we close all.\n const usageAttrs = buildUsageAttrs({\n input: stats.totalIn,\n output: stats.totalOut,\n cacheRead: stats.totalCacheRead,\n cacheCreation: stats.totalCacheCreation,\n cost: stats.cost,\n timeToFirstTokenMs: stats.timeTillFirstTokenMs,\n }, conventions)\n for (const [, span] of runSpans) {\n safeSetAttrs(span, {\n ...usageAttrs,\n [GEN_AI.turn]: stats.turns,\n 'gen_ai.agent.elapsed_ms': stats.elapsed,\n ...(legacy\n ? {\n totalIn: stats.totalIn,\n totalOut: stats.totalOut,\n totalCacheRead: stats.totalCacheRead,\n totalCacheCreation: stats.totalCacheCreation,\n cost: stats.cost,\n turns: stats.turns,\n elapsed: stats.elapsed,\n }\n : {}),\n })\n }\n endAll(runSpans)\n // Defensive — close anything else still hanging open.\n endAll(turnSpans)\n endAll(toolSpans)\n endAll(mcpSpans)\n endAll(spawnSpans)\n endAll(bootstrapSpans)\n activeRunSpan = undefined\n activeSystem = undefined\n turnTrack.clear()\n }))\n\n unregisters.push(hooks.hook('agent:abort', () => {\n for (const [, span] of runSpans)\n safeSetAttrs(span, { 'gen_ai.agent.status': 'aborted' })\n }))\n\n // -----------------------------------------------------------------\n // Turn span — OTel Gen AI `chat` operation\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('turn:before', (ctx) => {\n const requestedModel = ctx.options.model\n // Built-in Sentry/OTel attrs that don't depend on content capture.\n const baseAttrs: Record<string, unknown> = {\n [GEN_AI.operationName]: 'chat',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.requestModel]: requestedModel,\n [GEN_AI.turn]: ctx.turn,\n [GEN_AI.responseStreaming]: true,\n [GEN_AI.requestMaxTokens]: ctx.options.maxTokens,\n 'sentry.op': 'gen_ai.chat',\n 'gen_ai.agent.turn_id': ctx.turnId,\n ...(legacy ? { turnId: ctx.turnId, turn: ctx.turn } : {}),\n }\n // Optionally surface conversation content — prompts, system\n // instructions, available tools. Each piece flows through the\n // redact seam so hosts can scrub secrets without losing the\n // structural attribute. Skipping content keeps the span cheap\n // and privacy-safe.\n if (captureContent) {\n const systemText = ctx.options.system\n if (systemText) {\n baseAttrs[GEN_AI.systemInstructions] = redact('system', systemText, {\n turnId: ctx.turnId,\n turn: ctx.turn,\n })\n }\n const inputMsgs = stringifyMessages(ctx.options.messages)\n if (inputMsgs) {\n baseAttrs[GEN_AI.inputMessages] = redact('prompt', inputMsgs, {\n turnId: ctx.turnId,\n turn: ctx.turn,\n })\n }\n const toolDefs = stringifyToolDefs(ctx.options.tools)\n if (toolDefs)\n baseAttrs[GEN_AI.toolDefinitions] = toolDefs\n }\n const span = safeStartSpan(\n `chat${requestedModel ? ` ${requestedModel}` : ''}`,\n baseAttrs,\n )\n if (span) {\n turnSpans.set(ctx.turnId, span)\n turnTrack.set(ctx.turnId, { startedAt: Date.now() })\n }\n }))\n\n unregisters.push(hooks.hook('stream:start', (ctx) => {\n safeAddEvent(turnSpans.get(ctx.turnId), 'gen_ai.stream.start', {\n startedAt: ctx.startedAt,\n })\n }))\n\n unregisters.push(hooks.hook('turn:after', (ctx) => {\n const span = turnSpans.get(ctx.turnId)\n const tracked = turnTrack.get(ctx.turnId)\n turnTrack.delete(ctx.turnId)\n // Tokens-per-second derivation. Use wall-clock duration since the\n // turn span opened, fall back to TTFT-adjusted slice when present.\n let tokensPerSecond: number | undefined\n if (tracked && ctx.usage.output > 0) {\n const elapsedMs = Date.now() - tracked.startedAt\n if (elapsedMs > 0)\n tokensPerSecond = (ctx.usage.output / elapsedMs) * 1000\n }\n const usageAttrs = buildUsageAttrs(ctx.usage, conventions)\n // Cumulative-through-this-turn totals. We compute `input_tokens`\n // here to mirror `gen_ai.usage.input_tokens`'s semantic on the\n // same span: it INCLUDES cached when Sentry conventions are in\n // play, matches the uncached slice when OTel-only. Without this\n // alignment the two keys (`usage.*` vs `cumulative.*`) would\n // silently differ in arithmetic.\n const cumInputTokens = wantSentry\n ? ctx.cumulativeUsage.input + ctx.cumulativeUsage.cacheRead + ctx.cumulativeUsage.cacheCreation\n : ctx.cumulativeUsage.input\n const attrs: Record<string, unknown> = {\n ...usageAttrs,\n [GEN_AI.responseTokensPerSecond]: tokensPerSecond,\n 'gen_ai.agent.cumulative.input_tokens': cumInputTokens,\n 'gen_ai.agent.cumulative.output_tokens': ctx.cumulativeUsage.output,\n 'gen_ai.agent.cumulative.total_tokens': cumInputTokens + ctx.cumulativeUsage.output,\n 'gen_ai.agent.cumulative.cache_read_input_tokens': ctx.cumulativeUsage.cacheRead,\n 'gen_ai.agent.cumulative.cache_creation_input_tokens': ctx.cumulativeUsage.cacheCreation,\n 'gen_ai.agent.cumulative.cost_usd': ctx.cumulativeUsage.cost,\n 'gen_ai.agent.cumulative.turns': ctx.cumulativeUsage.turns,\n ...(legacy\n ? {\n inputTokens: ctx.usage.input,\n outputTokens: ctx.usage.output,\n finishReason: ctx.usage.finishReason,\n modelId: ctx.usage.modelId,\n }\n : {}),\n }\n // Output messages — the assistant turn that just landed. Sentry's\n // conversation viewer keys off this; skipped when content capture\n // is off. `system` turns aren't serialized (Sentry's schema only\n // accepts user / assistant / system / tool — and we never emit\n // system role from the loop).\n if (captureContent && ctx.message && ctx.message.role !== 'system' && ctx.message.role !== 'command') {\n const outputMsgs = stringifyMessages([{\n role: ctx.message.role,\n content: ctx.message.content,\n }])\n if (outputMsgs)\n attrs[GEN_AI.outputMessages] = redact('stream-text', outputMsgs, { turnId: ctx.turnId, turn: ctx.turn })\n }\n safeSetAttrs(span, attrs)\n safeEnd(turnSpans, ctx.turnId)\n }))\n\n unregisters.push(hooks.hook('stream:error', (ctx) => {\n const span = turnSpans.get(ctx.turnId)\n const message = ctx.err instanceof Error ? ctx.err.message : String(ctx.err)\n safeSetAttrs(span, {\n 'error.type': ctx.err instanceof Error ? ctx.err.name : 'unknown',\n 'error.message': message,\n 'http.response.status_code': ctx.statusCode,\n 'gen_ai.request.id': ctx.requestId,\n })\n safeAddEvent(span, 'gen_ai.stream.error', {\n 'error.type': ctx.err instanceof Error ? ctx.err.name : 'unknown',\n 'error.message': message,\n 'http.response.status_code': ctx.statusCode,\n 'gen_ai.request.id': ctx.requestId,\n })\n }))\n\n // -----------------------------------------------------------------\n // Native tool span — OTel Gen AI `execute_tool` operation\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('tool:before', (ctx) => {\n const span = safeStartSpan(\n `execute_tool ${ctx.displayName}`,\n {\n [GEN_AI.operationName]: 'execute_tool',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolType]: 'function',\n [GEN_AI.toolCallId]: ctx.callId,\n 'sentry.op': 'gen_ai.execute_tool',\n 'gen_ai.tool.display_name': ctx.displayName,\n 'gen_ai.agent.turn_id': ctx.turnId,\n 'gen_ai.agent.depth': ctx.depth,\n 'gen_ai.agent.run.id': ctx.runId,\n 'gen_ai.agent.parent_run.id': ctx.parentRunId,\n ...(legacy\n ? {\n toolName: ctx.name,\n displayName: ctx.displayName,\n turnId: ctx.turnId,\n callId: ctx.callId,\n }\n : {}),\n },\n )\n if (span) {\n toolSpans.set(ctx.callId, span)\n if (captureContent) {\n // Attach (possibly redacted) input as an attribute. Sentry's\n // canonical key is `gen_ai.tool.call.arguments`; OTel's\n // older key is `gen_ai.tool.input` (now deprecated in\n // Sentry). Emit one or both based on `conventions`.\n try {\n const serialized = JSON.stringify(ctx.input)\n const redacted = redact('tool-input', serialized, {\n toolName: ctx.name,\n displayName: ctx.displayName,\n callId: ctx.callId,\n turnId: ctx.turnId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallArguments] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolInputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n catch {\n // Non-serializable input (circular refs) — skip the attr;\n // the tool name and call id are still on the span.\n }\n }\n }\n }))\n\n unregisters.push(hooks.hook('tool:after', (ctx) => {\n const span = toolSpans.get(ctx.callId)\n safeSetAttrs(span, {\n 'gen_ai.tool.output_bytes': ctx.outputBytes,\n 'gen_ai.tool.coercions': ctx.coercions?.length ?? 0,\n })\n if (captureContent && typeof ctx.result === 'string') {\n const redacted = redact('tool-result', ctx.result, {\n toolName: ctx.name,\n callId: ctx.callId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallResult] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolOutputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n safeEnd(toolSpans, ctx.callId)\n }))\n\n unregisters.push(hooks.hook('tool:error', (ctx) => {\n safeSetAttrs(toolSpans.get(ctx.callId), {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n safeEnd(toolSpans, ctx.callId)\n }))\n\n // Tool gate / dispatch outcomes. Listen on `tool:dispatched` (fires\n // AFTER every `tool:gate` listener has had a chance to mutate\n // `block` / `result`) so the recorded `outcome` reflects the final\n // decision rather than the as-entered state. Attaches to the\n // in-flight run span; the chat span has already closed by tool\n // dispatch time in the current loop ordering, and no tool span has\n // opened for a `gate-block` / `unknown` / `invalid-input` path.\n unregisters.push(hooks.hook('tool:dispatched', (ctx) => {\n if (ctx.outcome === 'gate-block') {\n safeAddEvent(activeRunSpan, 'gen_ai.gate.block', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n reason: ctx.reason,\n })\n }\n else if (ctx.outcome === 'gate-substitute') {\n safeAddEvent(activeRunSpan, 'gen_ai.gate.substitute', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n })\n }\n else if (ctx.outcome === 'unknown') {\n safeAddEvent(activeRunSpan, 'gen_ai.tool.unknown', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n })\n }\n else if (ctx.outcome === 'invalid-input') {\n safeAddEvent(activeRunSpan, 'gen_ai.tool.invalid_input', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n })\n }\n }))\n\n unregisters.push(hooks.hook('validation:reject', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.validation.reject', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n reason: ctx.reason,\n })\n }))\n\n unregisters.push(hooks.hook('validation:coerce', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.validation.coerce', {\n [GEN_AI.toolName]: ctx.name,\n [GEN_AI.toolCallId]: ctx.callId,\n coercions: ctx.coercions,\n })\n }))\n\n unregisters.push(hooks.hook('budget:exceeded', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.budget.exceeded', {\n turnId: ctx.turnId,\n bytes: ctx.bytes,\n budget: ctx.budget,\n })\n }))\n\n unregisters.push(hooks.hook('tool-budget:exceeded', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.tool_budget.exceeded', {\n [GEN_AI.toolName]: ctx.tool,\n turnId: ctx.turnId,\n count: ctx.count,\n max: ctx.max,\n mode: ctx.mode,\n })\n }))\n\n unregisters.push(hooks.hook('pairing:repair', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.pairing.repair', {\n mode: ctx.mode,\n callId: ctx.callId,\n turnId: ctx.turnId,\n })\n }))\n\n unregisters.push(hooks.hook('oauth:refresh', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.oauth.refresh', {\n provider: ctx.provider,\n providerId: ctx.providerId,\n source: ctx.source,\n })\n }))\n\n // -----------------------------------------------------------------\n // MCP tool span — OTel Gen AI `execute_tool` operation, MCP variant\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('mcp:tool:before', (ctx) => {\n const span = safeStartSpan(\n `execute_tool ${ctx.server}.${ctx.tool}`,\n {\n [GEN_AI.operationName]: 'execute_tool',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.toolName]: ctx.displayName,\n // MCP tools are Sentry's \"extension\" tool type — backed by an\n // out-of-process server rather than a local function.\n [GEN_AI.toolType]: 'extension',\n [GEN_AI.toolCallId]: ctx.callId,\n [GEN_AI.mcpServer]: ctx.server,\n 'sentry.op': 'gen_ai.execute_tool',\n 'gen_ai.mcp.tool': ctx.tool,\n 'gen_ai.agent.turn_id': ctx.turnId,\n 'gen_ai.agent.run.id': ctx.runId,\n ...(legacy\n ? {\n server: ctx.server,\n tool: ctx.tool,\n displayName: ctx.displayName,\n turnId: ctx.turnId,\n callId: ctx.callId,\n }\n : {}),\n },\n )\n if (span) {\n mcpSpans.set(ctx.callId, span)\n if (captureContent) {\n try {\n const redacted = redact('mcp-tool-input', JSON.stringify(ctx.input), {\n server: ctx.server,\n tool: ctx.tool,\n callId: ctx.callId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallArguments] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolInputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n catch { /* ignore */ }\n }\n }\n }))\n\n unregisters.push(hooks.hook('mcp:tool:after', (ctx) => {\n const span = mcpSpans.get(ctx.callId)\n safeSetAttrs(span, { 'gen_ai.tool.output_bytes': ctx.outputBytes })\n if (captureContent && typeof ctx.result === 'string') {\n const redacted = redact('mcp-tool-result', ctx.result, {\n server: ctx.server,\n tool: ctx.tool,\n callId: ctx.callId,\n })\n const attrs: Record<string, unknown> = {}\n if (wantSentry)\n attrs[GEN_AI.toolCallResult] = redacted\n if (conventions === 'otel' || conventions === 'both')\n attrs[GEN_AI.toolOutputDeprecated] = redacted\n safeSetAttrs(span, attrs)\n }\n safeEnd(mcpSpans, ctx.callId)\n }))\n\n unregisters.push(hooks.hook('mcp:tool:error', (ctx) => {\n safeSetAttrs(mcpSpans.get(ctx.callId), {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n safeEnd(mcpSpans, ctx.callId)\n }))\n\n // -----------------------------------------------------------------\n // MCP server bootstrap span\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('mcp:bootstrap:start', (ctx) => {\n const span = safeStartSpan(\n `mcp.bootstrap ${ctx.name}`,\n {\n [GEN_AI.operationName]: 'mcp.bootstrap',\n [GEN_AI.system]: activeSystem,\n [GEN_AI.mcpServer]: ctx.name,\n 'gen_ai.mcp.transport': ctx.transport,\n },\n )\n if (span)\n bootstrapSpans.set(ctx.name, span)\n }))\n\n unregisters.push(hooks.hook('mcp:bootstrap:end', (ctx) => {\n const span = bootstrapSpans.get(ctx.name)\n const ok = ctx.ok\n safeSetAttrs(span, {\n 'gen_ai.mcp.bootstrap.duration_ms': ctx.durationMs,\n 'gen_ai.mcp.bootstrap.ok': ok,\n ...(ok\n ? {\n [GEN_AI.mcpToolCount]: ctx.toolCount,\n 'gen_ai.mcp.lazy': ctx.lazy,\n 'gen_ai.mcp.cached': ctx.cached,\n }\n : {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n }),\n })\n safeEnd(bootstrapSpans, ctx.name)\n }))\n\n unregisters.push(hooks.hook('mcp:auth:required', (ctx) => {\n const span = bootstrapSpans.get(ctx.name)\n safeAddEvent(span ?? activeRunSpan, 'gen_ai.mcp.auth.required', {\n server: ctx.name,\n transport: ctx.transport,\n reason: ctx.reason,\n })\n }))\n\n unregisters.push(hooks.hook('mcp:error', (ctx) => {\n safeAddEvent(activeRunSpan, 'gen_ai.mcp.error', {\n 'server': ctx.name,\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n }))\n\n // -----------------------------------------------------------------\n // Spawn span — parent-side. Also injects trace context for the child.\n // -----------------------------------------------------------------\n\n unregisters.push(hooks.hook('spawn:before', (ctx) => {\n // Sentry: \"handoff from {from_agent} to {to_agent}\". We don't\n // always know the child agent's name at spawn time — fall back\n // to the truncated task as the destination identifier.\n const toAgent = ctx.task.length > 60 ? `${ctx.task.slice(0, 57)}…` : ctx.task\n const span = safeStartSpan(\n `handoff to ${toAgent}`,\n {\n [GEN_AI.operationName]: 'handoff',\n [GEN_AI.system]: activeSystem,\n 'sentry.op': 'gen_ai.handoff',\n 'gen_ai.agent.spawn.id': ctx.id,\n 'gen_ai.agent.spawn.task': ctx.task,\n 'gen_ai.agent.depth': ctx.depth,\n },\n )\n if (span)\n spawnSpans.set(ctx.id, span)\n\n // Inject parent trace context for the child agent. The spawn tool\n // passes whatever we write into `ctx.tracingContext` to the child's\n // `agent.run({ tracingContext })` — see `tools/spawn.ts`.\n if (typeof options.getActiveTraceContext === 'function' && ctx.tracingContext) {\n let carrier: Readonly<Record<string, string>> | undefined\n try {\n carrier = options.getActiveTraceContext()\n }\n catch (err) {\n try {\n onError('getActiveTraceContext', err)\n }\n catch { /* ignore */ }\n }\n if (carrier) {\n for (const [k, v] of Object.entries(carrier))\n ctx.tracingContext[k] = v\n }\n }\n }))\n\n unregisters.push(hooks.hook('spawn:complete', (ctx) => {\n const span = spawnSpans.get(ctx.id)\n const childUsage = buildUsageAttrs({\n input: ctx.stats.totalIn,\n output: ctx.stats.totalOut,\n cacheRead: ctx.stats.totalCacheRead,\n cacheCreation: ctx.stats.totalCacheCreation,\n cost: ctx.stats.cost,\n }, conventions)\n safeSetAttrs(span, {\n 'gen_ai.agent.spawn.status': ctx.status ?? 'completed',\n 'gen_ai.agent.spawn.depth': ctx.depth,\n ...childUsage,\n })\n safeEnd(spawnSpans, ctx.id)\n }))\n\n unregisters.push(hooks.hook('spawn:error', (ctx) => {\n safeSetAttrs(spawnSpans.get(ctx.id), {\n 'error.type': ctx.error.name,\n 'error.message': ctx.error.message,\n })\n safeEnd(spawnSpans, ctx.id)\n }))\n\n // -----------------------------------------------------------------\n // Disposal\n // -----------------------------------------------------------------\n\n let disposed = false\n return function uninstall() {\n if (disposed)\n return\n disposed = true\n for (const un of unregisters) {\n try {\n un()\n }\n catch { /* ignore */ }\n }\n endAll(runSpans)\n endAll(turnSpans)\n endAll(toolSpans)\n endAll(mcpSpans)\n endAll(spawnSpans)\n endAll(bootstrapSpans)\n activeRunSpan = undefined\n }\n },\n }\n}\n\n/**\n * OpenTelemetry Gen AI semantic-convention attribute keys used by the\n * built-in tracer. Exported so consumers integrating with raw OTel SDKs\n * (instead of going through `createTracingHooks`) can stay aligned with\n * the names the harness itself emits.\n */\nexport const GEN_AI_ATTRIBUTES = GEN_AI\n"],"mappings":"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"}
|