eve 0.78.0 → 0.79.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.
Files changed (270) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/src/approval/definition.d.ts +42 -0
  3. package/dist/src/cli/commands/trace-detail.d.ts +2 -2
  4. package/dist/src/cli/commands/trace-detail.js +1 -1
  5. package/dist/src/cli/commands/trace.d.ts +1 -1
  6. package/dist/src/cli/commands/trace.js +1 -1
  7. package/dist/src/cli/dev/tui/traces/trace-conversation.d.ts +1 -1
  8. package/dist/src/cli/dev/tui/traces/trace-conversation.js +1 -1
  9. package/dist/src/cli/dev/tui/traces/trace-store.d.ts +1 -1
  10. package/dist/src/cli/dev/tui/traces/trace-store.js +1 -1
  11. package/dist/src/cli/dev/tui/traces/trace-view.d.ts +1 -1
  12. package/dist/src/cli/dev/tui/traces/trace-view.js +1 -1
  13. package/dist/src/cli/dev/tui/traces/trace-viewer-state.d.ts +1 -1
  14. package/dist/src/compiled/.vendor-stamp.json +3 -1
  15. package/dist/src/compiled/@eve/tracing/adapters/agent-transport.d.ts +8 -0
  16. package/dist/src/compiled/@eve/tracing/adapters/ai-sdk-payload.d.ts +15 -0
  17. package/dist/src/compiled/@eve/tracing/adapters/ai-sdk-telemetry.d.ts +14 -0
  18. package/dist/src/{tracing/agent-span-id-generator.d.ts → compiled/@eve/tracing/adapters/otel-ids.d.ts} +1 -1
  19. package/dist/src/compiled/@eve/tracing/adapters/otel.d.ts +33 -0
  20. package/dist/src/{tracing/agent-otel-content.d.ts → compiled/@eve/tracing/adapters/serialization.d.ts} +9 -3
  21. package/dist/src/compiled/@eve/tracing/agent-tracing.d.ts +84 -0
  22. package/dist/src/compiled/@eve/tracing/ai-sdk.d.ts +7 -0
  23. package/dist/src/compiled/@eve/tracing/ai-sdk.js +1 -0
  24. package/dist/src/compiled/@eve/tracing/capture.d.ts +5 -0
  25. package/dist/src/compiled/@eve/tracing/core/activation.d.ts +3 -0
  26. package/dist/src/compiled/@eve/tracing/core/attributes.d.ts +14 -0
  27. package/dist/src/{tracing/content-attributes.d.ts → compiled/@eve/tracing/core/content-policy.d.ts} +1 -1
  28. package/dist/src/compiled/@eve/tracing/core/context.d.ts +3 -0
  29. package/dist/src/compiled/@eve/tracing/core/delegation.d.ts +13 -0
  30. package/dist/src/compiled/@eve/tracing/core/mcp.d.ts +24 -0
  31. package/dist/src/compiled/@eve/tracing/core/scopes.d.ts +59 -0
  32. package/dist/src/compiled/@eve/tracing/core/snapshot.d.ts +7 -0
  33. package/dist/src/compiled/@eve/tracing/core/span-kinds.d.ts +12 -0
  34. package/dist/src/compiled/@eve/tracing/core/types.d.ts +292 -0
  35. package/dist/src/compiled/@eve/tracing/core/writer.d.ts +15 -0
  36. package/dist/src/compiled/@eve/tracing/delegation.d.ts +2 -0
  37. package/dist/src/compiled/@eve/tracing/delegation.js +1 -0
  38. package/dist/src/compiled/@eve/tracing/index.d.ts +6 -0
  39. package/dist/src/compiled/@eve/tracing/index.js +1 -0
  40. package/dist/src/compiled/@eve/tracing/operations.d.ts +96 -0
  41. package/dist/src/compiled/@eve/tracing/otel.d.ts +12 -0
  42. package/dist/src/compiled/@eve/tracing/otel.js +1 -0
  43. package/dist/src/compiled/@opentelemetry/api/index.d.ts +4 -0
  44. package/dist/src/compiled/@workflow/world-vercel/index.js +7 -7
  45. package/dist/src/compiled/_chunks/workflow/delegation-BqhZ398D.js +1 -0
  46. package/dist/src/compiled/_chunks/workflow/mcp-CrGp4EC8.js +5 -0
  47. package/dist/src/compiler/extension-compatibility.d.ts +6 -6
  48. package/dist/src/compiler/extension-compatibility.js +1 -1
  49. package/dist/src/context/build-dynamic-tools.js +1 -1
  50. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  51. package/dist/src/evals/assertions/collector.d.ts +4 -1
  52. package/dist/src/evals/assertions/collector.js +1 -1
  53. package/dist/src/evals/context.js +1 -1
  54. package/dist/src/evals/index.d.ts +1 -1
  55. package/dist/src/evals/runner/artifacts.js +1 -1
  56. package/dist/src/evals/runner/reporters/assertion-diagnostics.js +2 -2
  57. package/dist/src/evals/runner/reporters/assertion-scores.d.ts +11 -2
  58. package/dist/src/evals/runner/reporters/assertion-scores.js +1 -1
  59. package/dist/src/evals/runner/reporters/braintrust.js +1 -1
  60. package/dist/src/evals/runner/reporters/console.js +1 -1
  61. package/dist/src/evals/runner/reporters/datadog.js +2 -2
  62. package/dist/src/evals/runner/reporters/junit.js +1 -1
  63. package/dist/src/evals/runner/verdict.d.ts +2 -2
  64. package/dist/src/evals/runner/verdict.js +1 -1
  65. package/dist/src/evals/types.d.ts +22 -6
  66. package/dist/src/eve-channel/index.js +1 -1
  67. package/dist/src/eve-channel/stream-headers.d.ts +1 -0
  68. package/dist/src/eve-channel/stream-headers.js +1 -0
  69. package/dist/src/execution/agent-sessions/context.d.ts +1 -1
  70. package/dist/src/execution/agent-sessions/context.js +1 -1
  71. package/dist/src/execution/agent-sessions/remote.js +1 -1
  72. package/dist/src/execution/agent-sessions/steps.js +1 -1
  73. package/dist/src/execution/cancelled-model-call-batch.js +1 -1
  74. package/dist/src/execution/catalog/connection-entry.js +1 -1
  75. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  76. package/dist/src/execution/eve-workflow-attributes.js +1 -1
  77. package/dist/src/execution/invoke-tool.d.ts +1 -1
  78. package/dist/src/execution/invoke-tool.js +1 -1
  79. package/dist/src/execution/session/turn-step.js +1 -1
  80. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  81. package/dist/src/execution/workflow-runtime.js +1 -1
  82. package/dist/src/harness/execute-tool.d.ts +2 -2
  83. package/dist/src/harness/input-extraction.js +1 -1
  84. package/dist/src/instrumentation/ai-sdk-hook-bridge.js +1 -1
  85. package/dist/src/instrumentation/dispatch.js +1 -1
  86. package/dist/src/instrumentation/memory.d.ts +1 -4
  87. package/dist/src/instrumentation/memory.js +1 -1
  88. package/dist/src/instrumentation/principal-summary.js +1 -1
  89. package/dist/src/instrumentation/providers.js +1 -1
  90. package/dist/src/instrumentation/runtime-context.d.ts +1 -1
  91. package/dist/src/instrumentation/runtime.d.ts +3 -3
  92. package/dist/src/instrumentation/runtime.js +1 -1
  93. package/dist/src/instrumentation/session-init.js +1 -1
  94. package/dist/src/internal/application/stamped-package-version.js +1 -1
  95. package/dist/src/internal/authored-definition/approval.d.ts +3 -1
  96. package/dist/src/internal/authored-definition/approval.js +1 -1
  97. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  98. package/dist/src/internal/logging.js +1 -1
  99. package/dist/src/internal/nitro/host/local-tracing-runtime-plugin.js +1 -1
  100. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  101. package/dist/src/internal/nitro/routes/channel-request-instrumentation.d.ts +10 -31
  102. package/dist/src/internal/nitro/routes/channel-request-instrumentation.js +1 -1
  103. package/dist/src/internal/nitro/routes/route-invoke-tool.d.ts +1 -1
  104. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
  105. package/dist/src/public/channels/slack/hitl.js +1 -1
  106. package/dist/src/public/definitions/approval.d.ts +1 -1
  107. package/dist/src/public/instrumentation/otel.d.ts +2 -2
  108. package/dist/src/public/instrumentation/otel.js +1 -1
  109. package/dist/src/public/tools/approval/index.d.ts +1 -1
  110. package/dist/src/runtime/connections/mcp-tracing.d.ts +10 -18
  111. package/dist/src/runtime/connections/mcp-tracing.js +1 -1
  112. package/dist/src/runtime/resolve-tool.js +1 -1
  113. package/dist/src/runtime/types.d.ts +2 -2
  114. package/dist/src/self-modification/extension/subagents/agent/tools/inspect_trace.d.ts +12 -12
  115. package/dist/src/self-modification/extension/subagents/agent/tools/inspect_trace.js +1 -1
  116. package/dist/src/self-modification/extension/subagents/agent/tools/search_traces.d.ts +1 -1
  117. package/dist/src/self-modification/extension/subagents/agent/tools/search_traces.js +1 -1
  118. package/dist/src/self-modification/extension/trace-inspection.d.ts +1 -1
  119. package/dist/src/self-modification/extension/trace-inspection.js +1 -1
  120. package/dist/src/setup/scaffold/create/project.js +1 -1
  121. package/dist/src/shared/trace-policy.d.ts +3 -0
  122. package/dist/src/shared/trace-policy.js +1 -1
  123. package/dist/src/tools/definition.d.ts +3 -3
  124. package/dist/src/tools/durable-callbacks.d.ts +5 -3
  125. package/dist/src/tools/durable-callbacks.js +1 -1
  126. package/dist/src/tools/dynamic.d.ts +2 -2
  127. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  128. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  129. package/dist/src/tools/workflow-definition.d.ts +2 -2
  130. package/dist/src/tracing/eve/agent-approval-instrumentation.d.ts +8 -0
  131. package/dist/src/tracing/eve/agent-approval-instrumentation.js +1 -0
  132. package/dist/src/tracing/{agent-channel-delivery-instrumentation.d.ts → eve/agent-channel-delivery-instrumentation.d.ts} +1 -1
  133. package/dist/src/tracing/{agent-channel-delivery-instrumentation.js → eve/agent-channel-delivery-instrumentation.js} +1 -1
  134. package/dist/src/tracing/eve/agent-invocation-coordinator.js +1 -0
  135. package/dist/src/tracing/eve/agent-memory-instrumentation.d.ts +12 -0
  136. package/dist/src/tracing/eve/agent-memory-instrumentation.js +1 -0
  137. package/dist/src/tracing/{agent-otel-provider.d.ts → eve/agent-otel-provider.d.ts} +6 -8
  138. package/dist/src/tracing/eve/agent-otel-provider.js +1 -0
  139. package/dist/src/tracing/eve/agent-tool-instrumentation.d.ts +44 -0
  140. package/dist/src/tracing/eve/agent-tool-instrumentation.js +1 -0
  141. package/dist/src/tracing/{agent-trace-context-store.d.ts → eve/agent-trace-context-store.d.ts} +8 -16
  142. package/dist/src/tracing/eve/agent-trace-context-store.js +1 -0
  143. package/dist/src/tracing/eve/agent-trace-context.js +1 -0
  144. package/dist/src/tracing/eve/agent-trace-state.d.ts +75 -0
  145. package/dist/src/tracing/{batch-span-processor.d.ts → eve/batch-span-processor.d.ts} +5 -1
  146. package/dist/src/tracing/eve/batch-span-processor.js +1 -0
  147. package/dist/src/tracing/{content-span-processor.d.ts → eve/content-span-processor.d.ts} +1 -1
  148. package/dist/src/tracing/eve/content-span-processor.js +1 -0
  149. package/dist/src/tracing/eve/delegation.d.ts +20 -0
  150. package/dist/src/tracing/eve/delegation.js +1 -0
  151. package/dist/src/tracing/eve/gateway.d.ts +16 -0
  152. package/dist/src/tracing/eve/gateway.js +1 -0
  153. package/dist/src/tracing/{install-instrumentation-runtime.d.ts → eve/install-instrumentation-runtime.d.ts} +1 -1
  154. package/dist/src/tracing/eve/install-instrumentation-runtime.js +1 -0
  155. package/dist/src/tracing/eve/invoke-tool-span.js +1 -0
  156. package/dist/src/tracing/eve/mcp.d.ts +29 -0
  157. package/dist/src/tracing/eve/mcp.js +1 -0
  158. package/dist/src/tracing/eve/metadata.d.ts +7 -0
  159. package/dist/src/tracing/eve/metadata.js +1 -0
  160. package/dist/src/tracing/eve/operation-input.d.ts +30 -0
  161. package/dist/src/tracing/eve/operation-input.js +1 -0
  162. package/dist/src/tracing/eve/otel-configuration.d.ts +70 -0
  163. package/dist/src/tracing/eve/otel-configuration.js +1 -0
  164. package/dist/src/tracing/{otel-declaration.d.ts → eve/otel-declaration.d.ts} +4 -11
  165. package/dist/src/tracing/eve/otel-declaration.js +1 -0
  166. package/dist/src/tracing/{otel-registration.d.ts → eve/otel-registration.d.ts} +12 -5
  167. package/dist/src/tracing/eve/otel-registration.js +1 -0
  168. package/dist/src/tracing/eve/policy.d.ts +15 -0
  169. package/dist/src/tracing/eve/policy.js +1 -0
  170. package/dist/src/tracing/eve/profile.d.ts +7 -0
  171. package/dist/src/tracing/eve/profile.js +1 -0
  172. package/dist/src/tracing/eve/session.d.ts +27 -0
  173. package/dist/src/tracing/eve/session.js +1 -0
  174. package/dist/src/tracing/{vercel-runtime-span-exporter.d.ts → eve/vercel-runtime-span-exporter.d.ts} +1 -1
  175. package/dist/src/tracing/local/agent-trace-span-processor.js +1 -0
  176. package/dist/src/tracing/local/inspection.d.ts +15 -0
  177. package/dist/src/tracing/local/inspection.js +1 -0
  178. package/dist/src/tracing/{local-instrumentation-runtime.d.ts → local/instrumentation-runtime.d.ts} +1 -1
  179. package/dist/src/tracing/local/instrumentation-runtime.js +1 -0
  180. package/dist/src/tracing/{local-trace-analysis.d.ts → local/trace-analysis.d.ts} +2 -2
  181. package/dist/src/tracing/{local-trace-analysis.js → local/trace-analysis.js} +1 -1
  182. package/dist/src/tracing/{local-trace-operations.d.ts → local/trace-operations.d.ts} +1 -1
  183. package/dist/src/tracing/{local-trace-query.d.ts → local/trace-query.d.ts} +1 -1
  184. package/dist/src/tracing/local/trace-reader.js +1 -0
  185. package/dist/src/tracing/{local-trace-retention.js → local/trace-retention.js} +1 -1
  186. package/dist/src/tracing/{local-trace-span-processor.js → local/trace-span-processor.js} +1 -1
  187. package/dist/src/tracing/{local-trace-summary.d.ts → local/trace-summary.d.ts} +1 -1
  188. package/dist/src/tracing/local/trace-summary.js +1 -0
  189. package/dist/src/tracing/{local-traces.d.ts → local/traces.d.ts} +1 -1
  190. package/dist/src/tracing/local/traces.js +1 -0
  191. package/docs/connections/mcp.mdx +22 -1
  192. package/docs/evals/assertions.mdx +50 -3
  193. package/docs/evals/overview.mdx +2 -1
  194. package/docs/evals/reporters.mdx +3 -1
  195. package/docs/tools/human-in-the-loop.md +23 -1
  196. package/package.json +2 -1
  197. package/dist/src/tracing/agent-approval-instrumentation.d.ts +0 -11
  198. package/dist/src/tracing/agent-approval-instrumentation.js +0 -1
  199. package/dist/src/tracing/agent-invocation-coordinator.js +0 -1
  200. package/dist/src/tracing/agent-memory-instrumentation.d.ts +0 -16
  201. package/dist/src/tracing/agent-memory-instrumentation.js +0 -1
  202. package/dist/src/tracing/agent-otel-attributes.d.ts +0 -10
  203. package/dist/src/tracing/agent-otel-attributes.js +0 -1
  204. package/dist/src/tracing/agent-otel-content.js +0 -4
  205. package/dist/src/tracing/agent-otel-provider.js +0 -2
  206. package/dist/src/tracing/agent-otel-runtime-context.d.ts +0 -36
  207. package/dist/src/tracing/agent-otel-runtime-context.js +0 -1
  208. package/dist/src/tracing/agent-otel-session-context.d.ts +0 -22
  209. package/dist/src/tracing/agent-otel-session-context.js +0 -1
  210. package/dist/src/tracing/agent-otel-turn-state.d.ts +0 -6
  211. package/dist/src/tracing/agent-otel-turn-state.js +0 -1
  212. package/dist/src/tracing/agent-otel-usage.d.ts +0 -10
  213. package/dist/src/tracing/agent-otel-usage.js +0 -1
  214. package/dist/src/tracing/agent-span-contract.d.ts +0 -34
  215. package/dist/src/tracing/agent-span-contract.js +0 -1
  216. package/dist/src/tracing/agent-span-error.js +0 -1
  217. package/dist/src/tracing/agent-span-id-generator.js +0 -1
  218. package/dist/src/tracing/agent-span-naming.d.ts +0 -1
  219. package/dist/src/tracing/agent-span-naming.js +0 -1
  220. package/dist/src/tracing/agent-tool-instrumentation.d.ts +0 -40
  221. package/dist/src/tracing/agent-tool-instrumentation.js +0 -1
  222. package/dist/src/tracing/agent-tool-span-context.d.ts +0 -16
  223. package/dist/src/tracing/agent-tool-span-context.js +0 -1
  224. package/dist/src/tracing/agent-trace-context-codec.d.ts +0 -15
  225. package/dist/src/tracing/agent-trace-context-codec.js +0 -1
  226. package/dist/src/tracing/agent-trace-context-store.js +0 -1
  227. package/dist/src/tracing/agent-trace-context.js +0 -1
  228. package/dist/src/tracing/agent-trace-span-processor.js +0 -1
  229. package/dist/src/tracing/agent-trace-state.d.ts +0 -91
  230. package/dist/src/tracing/batch-span-processor.js +0 -1
  231. package/dist/src/tracing/bounded-error.d.ts +0 -1
  232. package/dist/src/tracing/bounded-error.js +0 -1
  233. package/dist/src/tracing/content-attributes.js +0 -1
  234. package/dist/src/tracing/content-span-processor.js +0 -1
  235. package/dist/src/tracing/error-content-context.d.ts +0 -3
  236. package/dist/src/tracing/error-content-context.js +0 -1
  237. package/dist/src/tracing/install-instrumentation-runtime.js +0 -1
  238. package/dist/src/tracing/invoke-tool-span.js +0 -1
  239. package/dist/src/tracing/local-instrumentation-runtime.js +0 -1
  240. package/dist/src/tracing/local-trace-reader.js +0 -1
  241. package/dist/src/tracing/local-trace-summary.js +0 -1
  242. package/dist/src/tracing/local-traces.js +0 -1
  243. package/dist/src/tracing/otel-declaration.js +0 -1
  244. package/dist/src/tracing/otel-registration.js +0 -1
  245. package/dist/src/tracing/sampled-trace.d.ts +0 -4
  246. package/dist/src/tracing/sampled-trace.js +0 -1
  247. package/dist/src/tracing/suppress-tracing.d.ts +0 -2
  248. package/dist/src/tracing/suppress-tracing.js +0 -1
  249. package/dist/src/tracing/telemetry-budget.d.ts +0 -3
  250. package/dist/src/tracing/telemetry-budget.js +0 -1
  251. /package/dist/src/{tracing/agent-span-error.d.ts → compiled/@eve/tracing/adapters/otel-error.d.ts} +0 -0
  252. /package/dist/src/tracing/{agent-invocation-coordinator.d.ts → eve/agent-invocation-coordinator.d.ts} +0 -0
  253. /package/dist/src/tracing/{agent-trace-context.d.ts → eve/agent-trace-context.d.ts} +0 -0
  254. /package/dist/src/tracing/{agent-trace-state.js → eve/agent-trace-state.js} +0 -0
  255. /package/dist/src/tracing/{channel-audience-context.d.ts → eve/channel-audience-context.d.ts} +0 -0
  256. /package/dist/src/tracing/{channel-audience-context.js → eve/channel-audience-context.js} +0 -0
  257. /package/dist/src/tracing/{conversation-context.d.ts → eve/conversation-context.d.ts} +0 -0
  258. /package/dist/src/tracing/{conversation-context.js → eve/conversation-context.js} +0 -0
  259. /package/dist/src/tracing/{invoke-tool-span.d.ts → eve/invoke-tool-span.d.ts} +0 -0
  260. /package/dist/src/tracing/{span-export-policy.d.ts → eve/span-export-policy.d.ts} +0 -0
  261. /package/dist/src/tracing/{span-export-policy.js → eve/span-export-policy.js} +0 -0
  262. /package/dist/src/tracing/{vercel-runtime-span-exporter.js → eve/vercel-runtime-span-exporter.js} +0 -0
  263. /package/dist/src/tracing/{agent-trace-span-processor.d.ts → local/agent-trace-span-processor.d.ts} +0 -0
  264. /package/dist/src/tracing/{local-trace-discovery-index.d.ts → local/trace-discovery-index.d.ts} +0 -0
  265. /package/dist/src/tracing/{local-trace-discovery-index.js → local/trace-discovery-index.js} +0 -0
  266. /package/dist/src/tracing/{local-trace-operations.js → local/trace-operations.js} +0 -0
  267. /package/dist/src/tracing/{local-trace-query.js → local/trace-query.js} +0 -0
  268. /package/dist/src/tracing/{local-trace-reader.d.ts → local/trace-reader.d.ts} +0 -0
  269. /package/dist/src/tracing/{local-trace-retention.d.ts → local/trace-retention.d.ts} +0 -0
  270. /package/dist/src/tracing/{local-trace-span-processor.d.ts → local/trace-span-processor.d.ts} +0 -0
@@ -1,5 +1,5 @@
1
- import type { LocalTraceSpan } from "#tracing/local-trace-reader.js";
2
- import { type LocalTraceSummary } from "#tracing/local-trace-summary.js";
1
+ import type { LocalTraceSpan } from "#tracing/local/trace-reader.js";
2
+ import { type LocalTraceSummary } from "#tracing/local/trace-summary.js";
3
3
  interface TraceAnalysisSelector {
4
4
  readonly excludeSessionId?: string;
5
5
  readonly fromMs?: number;
@@ -1 +1 @@
1
- import{summarizeLocalTrace}from"#tracing/local-trace-summary.js";import{localTraceOperations,traceModelName,traceSessionId,traceStringAttribute,traceToolName,uniqueLocalTraceSpans}from"#tracing/local-trace-operations.js";function analyzeLocalTrace(e,t,n={}){let r=uniqueLocalTraceSpans(t),i=new Map(localTraceOperations(r).map(({span:e})=>[e.spanId,e])),a=r.filter(e=>matches(i.get(e.spanId)??e,n)),o=a.reduce((e,t)=>t.startTimeNs<e?t.startTimeNs:e,a[0]?.startTimeNs??0n),s=localTraceOperations(a).map(e=>recordFor(e,o)).sort((e,t)=>e.startOffsetMs-t.startOffsetMs||e.endOffsetMs-t.endOffsetMs||e.spanId.localeCompare(t.spanId));return{summary:summarizeLocalTrace(e,a),groups:groups(s),modelWorkMs:sum(s,`model`),toolWorkMs:sum(s,`tool`),records:s}}function matches(e,t){let n=traceSessionId(e),r=traceStringAttribute(e,`agent.turn.id`);if(t.excludeSessionId!==void 0&&n===t.excludeSessionId||t.sessionId!==void 0&&n!==t.sessionId||t.turnId!==void 0&&r!==t.turnId)return!1;let i=Number(e.startTimeNs/1000000n);return(t.fromMs===void 0||i>=t.fromMs)&&(t.toMs===void 0||i<=t.toMs)}function recordFor(e,t){let{span:n,category:r}=e,i={category:r,durationMs:Number(n.endTimeNs-n.startTimeNs)/1e6,endOffsetMs:Number(n.endTimeNs-t)/1e6,outcome:n.statusCode===2?`failed`:`completed`,spanId:n.spanId,startOffsetMs:Number(n.startTimeNs-t)/1e6},a=traceStringAttribute(n,`gen_ai.tool.call.id`),o=traceModelName(n),s=traceSessionId(n),c=traceToolName(n),l=traceStringAttribute(n,`agent.turn.id`);if(a!==void 0&&(i.callId=a),n.statusMessage!==void 0&&(i.error=n.statusMessage),o!==void 0&&(i.model=o),n.parentSpanId!==void 0&&(i.parentSpanId=n.parentSpanId),s!==void 0&&(i.sessionId=s),c!==void 0&&r===`tool`&&(i.toolName=c),c!==void 0&&r===`other`&&(i.actionName=c),l!==void 0&&(i.turnId=l),e.actionDurationMs!==void 0&&(i.actionDurationMs=e.actionDurationMs),r===`model`){let e={};for(let[t,r]of Object.entries({inputTokens:`gen_ai.usage.input_tokens`,outputTokens:`gen_ai.usage.output_tokens`,cacheReadTokens:`gen_ai.usage.cache_read.input_tokens`,cacheWriteTokens:`gen_ai.usage.cache_write.input_tokens`})){let i=n.attributes[r];typeof i==`number`&&Number.isFinite(i)&&i>=0&&(e[t]=i)}Object.keys(e).length>0&&(i.usage=e)}return i}function groups(e){let t=new Map;for(let n of e){let e=JSON.stringify([n.sessionId,n.turnId]),r=t.get(e);r===void 0&&(r={modelCalls:0,modelWorkMs:0,toolCalls:0,toolWorkMs:0},n.sessionId!==void 0&&(r.sessionId=n.sessionId),n.turnId!==void 0&&(r.turnId=n.turnId),t.set(e,r)),n.category===`model`&&(r.modelCalls+=1,r.modelWorkMs+=n.durationMs),n.category===`tool`&&(r.toolCalls+=1,r.toolWorkMs+=n.durationMs)}return[...t.values()]}function sum(e,t){return e.reduce((e,n)=>e+(n.category===t?n.durationMs:0),0)}export{analyzeLocalTrace};
1
+ import{summarizeLocalTrace}from"#tracing/local/trace-summary.js";import{localTraceOperations,traceModelName,traceSessionId,traceStringAttribute,traceToolName,uniqueLocalTraceSpans}from"#tracing/local/trace-operations.js";function analyzeLocalTrace(e,t,n={}){let r=uniqueLocalTraceSpans(t),i=new Map(localTraceOperations(r).map(({span:e})=>[e.spanId,e])),a=r.filter(e=>matches(i.get(e.spanId)??e,n)),o=a.reduce((e,t)=>t.startTimeNs<e?t.startTimeNs:e,a[0]?.startTimeNs??0n),s=localTraceOperations(a).map(e=>recordFor(e,o)).sort((e,t)=>e.startOffsetMs-t.startOffsetMs||e.endOffsetMs-t.endOffsetMs||e.spanId.localeCompare(t.spanId));return{summary:summarizeLocalTrace(e,a),groups:groups(s),modelWorkMs:sum(s,`model`),toolWorkMs:sum(s,`tool`),records:s}}function matches(e,t){let n=traceSessionId(e),r=traceStringAttribute(e,`agent.turn.id`);if(t.excludeSessionId!==void 0&&n===t.excludeSessionId||t.sessionId!==void 0&&n!==t.sessionId||t.turnId!==void 0&&r!==t.turnId)return!1;let i=Number(e.startTimeNs/1000000n);return(t.fromMs===void 0||i>=t.fromMs)&&(t.toMs===void 0||i<=t.toMs)}function recordFor(e,t){let{span:n,category:r}=e,i={category:r,durationMs:Number(n.endTimeNs-n.startTimeNs)/1e6,endOffsetMs:Number(n.endTimeNs-t)/1e6,outcome:n.statusCode===2?`failed`:`completed`,spanId:n.spanId,startOffsetMs:Number(n.startTimeNs-t)/1e6},a=traceStringAttribute(n,`gen_ai.tool.call.id`),o=traceModelName(n),s=traceSessionId(n),c=traceToolName(n),l=traceStringAttribute(n,`agent.turn.id`);if(a!==void 0&&(i.callId=a),n.statusMessage!==void 0&&(i.error=n.statusMessage),o!==void 0&&(i.model=o),n.parentSpanId!==void 0&&(i.parentSpanId=n.parentSpanId),s!==void 0&&(i.sessionId=s),c!==void 0&&r===`tool`&&(i.toolName=c),c!==void 0&&r===`other`&&(i.actionName=c),l!==void 0&&(i.turnId=l),e.actionDurationMs!==void 0&&(i.actionDurationMs=e.actionDurationMs),r===`model`){let e={};for(let[t,r]of Object.entries({inputTokens:`gen_ai.usage.input_tokens`,outputTokens:`gen_ai.usage.output_tokens`,cacheReadTokens:`gen_ai.usage.cache_read.input_tokens`,cacheWriteTokens:`gen_ai.usage.cache_write.input_tokens`})){let i=n.attributes[r];typeof i==`number`&&Number.isFinite(i)&&i>=0&&(e[t]=i)}Object.keys(e).length>0&&(i.usage=e)}return i}function groups(e){let t=new Map;for(let n of e){let e=JSON.stringify([n.sessionId,n.turnId]),r=t.get(e);r===void 0&&(r={modelCalls:0,modelWorkMs:0,toolCalls:0,toolWorkMs:0},n.sessionId!==void 0&&(r.sessionId=n.sessionId),n.turnId!==void 0&&(r.turnId=n.turnId),t.set(e,r)),n.category===`model`&&(r.modelCalls+=1,r.modelWorkMs+=n.durationMs),n.category===`tool`&&(r.toolCalls+=1,r.toolWorkMs+=n.durationMs)}return[...t.values()]}function sum(e,t){return e.reduce((e,n)=>e+(n.category===t?n.durationMs:0),0)}export{analyzeLocalTrace};
@@ -1,4 +1,4 @@
1
- import type { LocalTraceSpan } from "#tracing/local-trace-reader.js";
1
+ import type { LocalTraceSpan } from "#tracing/local/trace-reader.js";
2
2
  export interface LocalTraceOperation {
3
3
  readonly span: LocalTraceSpan;
4
4
  readonly category: "model" | "other" | "tool";
@@ -1,4 +1,4 @@
1
- import type { LocalTraceSummary } from "#tracing/local-trace-summary.js";
1
+ import type { LocalTraceSummary } from "#tracing/local/trace-summary.js";
2
2
  export type LocalTraceSortBy = "duration" | "failures" | "inputTokens" | "latest";
3
3
  interface LocalTraceQueryFilter {
4
4
  readonly agentName?: string;
@@ -0,0 +1 @@
1
+ import{readFile,readdir,stat}from"node:fs/promises";import{join}from"node:path";import{isAgentActivationSpan}from"#tracing/local/inspection.js";import{resolveLocalTraceSchemaDirectory,resolveLocalTraceSegmentsDirectory}from"#tracing/local/trace-span-processor.js";const TRACE_ID_PATTERN=/^[0-9a-f]{32}$/u,SPAN_FILE_PATTERN=/^[0-9a-f]{16}\.otlp\.json$/u;async function listLocalTraceIds(e){let t;try{t=await readdir(resolveLocalTraceSchemaDirectory(e),{withFileTypes:!0})}catch(e){if(isMissing(e))return[];throw e}return t.filter(e=>e.isDirectory()&&TRACE_ID_PATTERN.test(e.name)).map(e=>e.name)}async function readLocalTraceActivityMs(e,t){try{return(await stat(resolveLocalTraceSegmentsDirectory(e,t))).mtimeMs}catch(e){if(isMissing(e))return;throw e}}async function listLocalTraceSegments(e,t){let n;try{n=await readdir(resolveLocalTraceSegmentsDirectory(e,t),{withFileTypes:!0})}catch(e){if(isMissing(e))return;throw e}return n.filter(e=>e.isFile()&&SPAN_FILE_PATTERN.test(e.name)).map(e=>e.name).sort((e,t)=>e.localeCompare(t))}async function readLocalTraceSegment(e,t,n){let r=join(resolveLocalTraceSegmentsDirectory(e,t),n),i;try{if((await stat(r)).size>8388608)return[];i=await readFile(r,`utf8`)}catch{return[]}return parseLocalTraceSegment(i,t)}async function listLocalTraces(e){let t=[];for(let n of await listLocalTraceIds(e)){let r=await readLocalTrace(e,n).catch(()=>void 0);r!==void 0&&t.push(r)}return t.sort((e,t)=>e.startTimeNs===t.startTimeNs?e.traceId.localeCompare(t.traceId):e.startTimeNs>t.startTimeNs?-1:1)}async function readLocalTrace(e,t){let n=await listLocalTraceSegments(e,t);if(n===void 0)return;let r=new Map;for(let i of n)for(let n of await readLocalTraceSegment(e,t,i))r.has(n.spanId)||r.set(n.spanId,n);if(r.size!==0)return assembleLocalTrace(t,[...r.values()])}function compareLocalTraceSpans(e,t){return e.startTimeNs===t.startTimeNs?e.endTimeNs===t.endTimeNs?e.name.localeCompare(t.name)||e.spanId.localeCompare(t.spanId):e.endTimeNs<t.endTimeNs?-1:1:e.startTimeNs<t.startTimeNs?-1:1}function assembleLocalTrace(e,t){let n=[...t].sort(compareLocalTraceSpans),r=n.map(e=>e.attributes),i=distinctAttributes(r,`gen_ai.conversation.id`);return{agentName:firstAttribute(r,`agent.name`),endTimeNs:n.reduce((e,t)=>t.endTimeNs>e?t.endTimeNs:e,0n),conversationId:i[0],conversationIds:i,spans:n,startTimeNs:n.reduce((e,t)=>t.startTimeNs<e?t.startTimeNs:e,n[0].startTimeNs),traceId:e}}function describeLocalTraceSpan(e){let t=[],n=stringSpanAttribute(e,`agent.turn.id`),r=valueSpanAttribute(e,`agent.step.index`),i=valueSpanAttribute(e,`agent.step.attempt`),a=stringSpanAttribute(e,`agent.action.kind`),o=stringSpanAttribute(e,`agent.action.name`),s=stringSpanAttribute(e,`agent.model.id`)??stringSpanAttribute(e,`gen_ai.request.model`);return isAgentTurnSpan(e)&&n!==void 0&&t.push(n),e.name===`agent.step`&&r!==void 0&&t.push(`step ${String(r)}${i===void 0?``:`, attempt ${String(i)}`}`),e.name===`agent.action`&&o!==void 0&&t.push(`${a??`action`}: ${o}`),s!==void 0&&e.name.includes(`do`)&&t.push(`model ${s}`),t}function isAgentTurnSpan(e){return isAgentActivationSpan(e)}function parseLocalTraceSegment(e,t){try{let n=JSON.parse(e);if(!isRecord(n)||!Array.isArray(n.resourceSpans))return[];let r=[];for(let e of n.resourceSpans)if(isRecord(e)&&Array.isArray(e.scopeSpans))for(let n of e.scopeSpans){if(!isRecord(n)||!Array.isArray(n.spans))continue;let e=isRecord(n.scope)&&typeof n.scope.name==`string`?n.scope.name:void 0;for(let i of n.spans){let n=parseLocalTraceSpan(i,t,e);n!==void 0&&r.push(n)}}return r}catch{return[]}}function parseLocalTraceSpan(e,t,n){if(!isRecord(e)||e.traceId!==t||typeof e.spanId!=`string`||!/^[0-9a-f]{16}$/u.test(e.spanId)||typeof e.name!=`string`)return;let r=parseNanos(e.startTimeUnixNano),i=parseNanos(e.endTimeUnixNano);if(!(r===void 0||i===void 0||i<r))return{attributes:parseAttributes(e.attributes),endTimeNs:i,events:parseEvents(e.events),kind:typeof e.kind==`number`?e.kind:void 0,name:e.name,parentSpanId:typeof e.parentSpanId==`string`&&/^[0-9a-f]{16}$/u.test(e.parentSpanId)?e.parentSpanId:void 0,scope:n,spanId:e.spanId,startTimeNs:r,statusCode:parseStatusCode(e.status),statusMessage:parseStatusMessage(e.status),traceId:t}}function parseEvents(e){if(!Array.isArray(e))return[];let t=[];for(let n of e){if(!isRecord(n)||typeof n.name!=`string`)continue;let e=parseNanos(n.timeUnixNano);e!==void 0&&t.push({attributes:parseAttributes(n.attributes),name:n.name,timeNs:e})}return t.sort((e,t)=>e.timeNs===t.timeNs?e.name.localeCompare(t.name):e.timeNs<t.timeNs?-1:1)}function parseAttributes(e){if(!Array.isArray(e))return{};let t={};for(let n of e){if(!isRecord(n)||typeof n.key!=`string`||!isRecord(n.value))continue;let e=parseAnyValue(n.value);e!==void 0&&(t[n.key]=e)}return t}function parseAnyValue(e){for(let t of[`stringValue`,`boolValue`,`intValue`,`doubleValue`])if(t in e)return e[t];if(isRecord(e.arrayValue)&&Array.isArray(e.arrayValue.values))return e.arrayValue.values.filter(isRecord).map(e=>parseAnyValue(e))}function parseNanos(e){if(typeof e==`string`||typeof e==`number`)try{let t=BigInt(e);return t>=0n&&t<=18446744073709551615n?t:void 0}catch{return}}function parseStatusCode(e){return isRecord(e)?typeof e.code==`number`?e.code:e.code===`STATUS_CODE_ERROR`?2:0:0}function parseStatusMessage(e){if(isRecord(e)&&typeof e.message==`string`)return e.message.length===0?void 0:e.message}function firstAttribute(e,t){for(let n of e){let e=n[t];if(typeof e==`string`&&e.length>0)return e}}function distinctAttributes(e,t){let n=new Set;for(let r of e){let e=r[t];typeof e==`string`&&e.length>0&&n.add(e)}return[...n]}function stringSpanAttribute(e,t){let n=e.attributes[t];return typeof n==`string`?n:void 0}function valueSpanAttribute(e,t){let n=e.attributes[t];return typeof n==`string`||typeof n==`number`?n:void 0}function isMissing(e){return e.code===`ENOENT`}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{assembleLocalTrace,compareLocalTraceSpans,describeLocalTraceSpan,isAgentTurnSpan,listLocalTraceIds,listLocalTraceSegments,listLocalTraces,parseLocalTraceSegment,readLocalTraceActivityMs,readLocalTraceSegment};
@@ -1 +1 @@
1
- import{readdir,rm,stat}from"node:fs/promises";import{createLogger,formatError}from"#internal/logging.js";import{join}from"node:path";import{resolveLocalTraceSchemaDirectory,resolveLocalTraceSegmentsDirectory}from"#tracing/local-trace-span-processor.js";const log=createLogger(`harness.local-trace-retention`),LOCAL_TRACE_QUIESCENCE_MS=3e5,LOCAL_TRACE_MAX_AGE_MS=6048e5,LOCAL_TRACE_MAX_TOTAL_BYTES=536870912;function resolveLocalTraceRetentionSettings(e=process.env){return{enabled:!isDisabled(e.EVE_TRACES),maxAgeMs:readBound(e,`EVE_TRACES_MAX_AGE_MS`,LOCAL_TRACE_MAX_AGE_MS),maxTotalBytes:readBound(e,`EVE_TRACES_MAX_TOTAL_BYTES`,LOCAL_TRACE_MAX_TOTAL_BYTES),retainCount:readBound(e,`EVE_TRACES_RETAIN_COUNT`,20)}}async function pruneLocalTraceStore(e){let t=e.now??Date.now(),n=clampBound(e.maxAgeMs??LOCAL_TRACE_MAX_AGE_MS),r=clampBound(e.maxTotalBytes??LOCAL_TRACE_MAX_TOTAL_BYTES),i=clampCount(e.retainCount??20),a=await readStoredTraces(e.appRoot,t),o=[...a].sort((e,t)=>t.modifiedAtMs-e.modifiedAtMs),s=new Set(o.slice(0,i===!1?0:i)),c=new Set,l=a.reduce((e,t)=>e+t.byteSize,0),u=0,d=0,f=0;for(let i of o.toReversed()){let a=t-i.modifiedAtMs,o=e.activeTraceIds.has(i.traceId)||s.has(i)||a<=LOCAL_TRACE_QUIESCENCE_MS?void 0:n!==!1&&a>n?`maxAgeMs`:r!==!1&&l>r?`maxTotalBytes`:void 0;if(o===void 0){f+=1;continue}await rm(i.path,{force:!0,recursive:!0}),l-=i.byteSize,u+=i.byteSize,d+=1,c.add(o)}return{reasons:[...c],reclaimedBytes:u,removedTraces:d,retainedTraces:f}}const pruneRequest={input:{activeTraceIds:new Set,appRoot:``},requested:!1,running:void 0};function requestLocalTraceStorePrune(e){pruneRequest.input=e,pruneRequest.requested=!0,pruneRequest.running===void 0&&startPruning()}function startPruning(){pruneRequest.running=(async()=>{for(;pruneRequest.requested;)pruneRequest.requested=!1,report(await pruneLocalTraceStore(pruneRequest.input))})().catch(e=>{log.warn(`local trace retention failed`,{error:formatError(e)})}).finally(()=>{pruneRequest.running=void 0,pruneRequest.requested&&startPruning()})}function report(e){e.removedTraces!==0&&log.info(`pruned local traces`,{reasons:e.reasons.join(`,`),reclaimedBytes:e.reclaimedBytes,removedTraces:e.removedTraces,retainedTraces:e.retainedTraces})}async function readStoredTraces(e,t){let n=resolveLocalTraceSchemaDirectory(e),r=await readDirectoryEntries(n);return r===void 0?[]:(await Promise.all(r.filter(e=>e.isDirectory()).map(async r=>{let i=join(n,r.name),a=resolveLocalTraceSegmentsDirectory(e,r.name);await reapAbandonedTemporaryFiles(a,t);let o=await directoryMtime(a)??await directoryMtime(i);if(o!==void 0)return{byteSize:await directorySize(i),modifiedAtMs:o,path:i,traceId:r.name}}))).filter(e=>e!==void 0)}async function reapAbandonedTemporaryFiles(e,t){let n=await readDirectoryEntries(e);if(n!==void 0)for(let r of n){if(!r.isFile()||!r.name.includes(`.tmp-`))continue;let n=join(e,r.name);try{if(t-(await stat(n)).mtimeMs<=LOCAL_TRACE_QUIESCENCE_MS)continue;await rm(n,{force:!0})}catch{}}}async function directoryMtime(e){try{return(await stat(e)).mtimeMs}catch{return}}async function directorySize(e){let t=await readDirectoryEntries(e);if(t===void 0)return 0;let n=0;for(let r of t){let t=join(e,r.name);if(r.isDirectory()){n+=await directorySize(t);continue}try{n+=(await stat(t)).size}catch{}}return n}async function readDirectoryEntries(e){try{return await readdir(e,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&(e.code===`ENOENT`||e.code===`ENOTDIR`))return;throw e}}function isDisabled(e){if(e===void 0)return!1;let t=e.trim().toLowerCase();return t===`off`||t===`false`||t===`0`}function readBound(e,t,n){let r=e[t];if(r===void 0)return n;let i=r.trim().toLowerCase();if(i===`off`||i===`false`)return!1;let a=Number(i);return!Number.isFinite(a)||a<0?(log.warn(`ignoring invalid local trace retention value`,{fallback:n,name:t,value:r}),n):a}function clampBound(e){return e!==!1&&Math.max(0,e)}function clampCount(e){return e!==!1&&Math.max(0,Math.trunc(e))}export{pruneLocalTraceStore,requestLocalTraceStorePrune,resolveLocalTraceRetentionSettings};
1
+ import{readdir,rm,stat}from"node:fs/promises";import{createLogger,formatError}from"#internal/logging.js";import{join}from"node:path";import{resolveLocalTraceSchemaDirectory,resolveLocalTraceSegmentsDirectory}from"#tracing/local/trace-span-processor.js";const log=createLogger(`harness.local-trace-retention`),LOCAL_TRACE_QUIESCENCE_MS=3e5,LOCAL_TRACE_MAX_AGE_MS=6048e5,LOCAL_TRACE_MAX_TOTAL_BYTES=536870912;function resolveLocalTraceRetentionSettings(e=process.env){return{enabled:!isDisabled(e.EVE_TRACES),maxAgeMs:readBound(e,`EVE_TRACES_MAX_AGE_MS`,LOCAL_TRACE_MAX_AGE_MS),maxTotalBytes:readBound(e,`EVE_TRACES_MAX_TOTAL_BYTES`,LOCAL_TRACE_MAX_TOTAL_BYTES),retainCount:readBound(e,`EVE_TRACES_RETAIN_COUNT`,20)}}async function pruneLocalTraceStore(e){let t=e.now??Date.now(),n=clampBound(e.maxAgeMs??LOCAL_TRACE_MAX_AGE_MS),r=clampBound(e.maxTotalBytes??LOCAL_TRACE_MAX_TOTAL_BYTES),i=clampCount(e.retainCount??20),a=await readStoredTraces(e.appRoot,t),o=[...a].sort((e,t)=>t.modifiedAtMs-e.modifiedAtMs),s=new Set(o.slice(0,i===!1?0:i)),c=new Set,l=a.reduce((e,t)=>e+t.byteSize,0),u=0,d=0,f=0;for(let i of o.toReversed()){let a=t-i.modifiedAtMs,o=e.activeTraceIds.has(i.traceId)||s.has(i)||a<=LOCAL_TRACE_QUIESCENCE_MS?void 0:n!==!1&&a>n?`maxAgeMs`:r!==!1&&l>r?`maxTotalBytes`:void 0;if(o===void 0){f+=1;continue}await rm(i.path,{force:!0,recursive:!0}),l-=i.byteSize,u+=i.byteSize,d+=1,c.add(o)}return{reasons:[...c],reclaimedBytes:u,removedTraces:d,retainedTraces:f}}const pruneRequest={input:{activeTraceIds:new Set,appRoot:``},requested:!1,running:void 0};function requestLocalTraceStorePrune(e){pruneRequest.input=e,pruneRequest.requested=!0,pruneRequest.running===void 0&&startPruning()}function startPruning(){pruneRequest.running=(async()=>{for(;pruneRequest.requested;)pruneRequest.requested=!1,report(await pruneLocalTraceStore(pruneRequest.input))})().catch(e=>{log.warn(`local trace retention failed`,{error:formatError(e)})}).finally(()=>{pruneRequest.running=void 0,pruneRequest.requested&&startPruning()})}function report(e){e.removedTraces!==0&&log.info(`pruned local traces`,{reasons:e.reasons.join(`,`),reclaimedBytes:e.reclaimedBytes,removedTraces:e.removedTraces,retainedTraces:e.retainedTraces})}async function readStoredTraces(e,t){let n=resolveLocalTraceSchemaDirectory(e),r=await readDirectoryEntries(n);return r===void 0?[]:(await Promise.all(r.filter(e=>e.isDirectory()).map(async r=>{let i=join(n,r.name),a=resolveLocalTraceSegmentsDirectory(e,r.name);await reapAbandonedTemporaryFiles(a,t);let o=await directoryMtime(a)??await directoryMtime(i);if(o!==void 0)return{byteSize:await directorySize(i),modifiedAtMs:o,path:i,traceId:r.name}}))).filter(e=>e!==void 0)}async function reapAbandonedTemporaryFiles(e,t){let n=await readDirectoryEntries(e);if(n!==void 0)for(let r of n){if(!r.isFile()||!r.name.includes(`.tmp-`))continue;let n=join(e,r.name);try{if(t-(await stat(n)).mtimeMs<=LOCAL_TRACE_QUIESCENCE_MS)continue;await rm(n,{force:!0})}catch{}}}async function directoryMtime(e){try{return(await stat(e)).mtimeMs}catch{return}}async function directorySize(e){let t=await readDirectoryEntries(e);if(t===void 0)return 0;let n=0;for(let r of t){let t=join(e,r.name);if(r.isDirectory()){n+=await directorySize(t);continue}try{n+=(await stat(t)).size}catch{}}return n}async function readDirectoryEntries(e){try{return await readdir(e,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&(e.code===`ENOENT`||e.code===`ENOTDIR`))return;throw e}}function isDisabled(e){if(e===void 0)return!1;let t=e.trim().toLowerCase();return t===`off`||t===`false`||t===`0`}function readBound(e,t,n){let r=e[t];if(r===void 0)return n;let i=r.trim().toLowerCase();if(i===`off`||i===`false`)return!1;let a=Number(i);return!Number.isFinite(a)||a<0?(log.warn(`ignoring invalid local trace retention value`,{fallback:n,name:t,value:r}),n):a}function clampBound(e){return e!==!1&&Math.max(0,e)}function clampCount(e){return e!==!1&&Math.max(0,Math.trunc(e))}export{pruneLocalTraceStore,requestLocalTraceStorePrune,resolveLocalTraceRetentionSettings};
@@ -1 +1 @@
1
- import{mkdir}from"node:fs/promises";import{createLogger,formatError}from"#internal/logging.js";import{join}from"node:path";import{atomicWriteFile}from"#shared/atomic-write-file.js";import{indexLocalTraceConversation}from"#tracing/local-trace-discovery-index.js";import{JsonTraceSerializer}from"#compiled/@opentelemetry/otlp-transformer/index.js";const log=createLogger(`harness.local-trace-span-processor`);function resolveLocalTraceStoreDirectory(e){return join(e,`.eve`,`traces`)}function resolveLocalTraceSchemaDirectory(e){return join(resolveLocalTraceStoreDirectory(e),`v1`)}function resolveLocalTraceDirectory(e,t){return join(resolveLocalTraceSchemaDirectory(e),t)}function resolveLocalTraceSegmentsDirectory(e,t){return join(resolveLocalTraceDirectory(e,t),`segments`)}var LocalTraceSpanProcessor=class{#e;#t=Promise.resolve();#n=!1;constructor(e){this.#e=e}forceFlush(){return this.#t}onStart(){}onEnd(e){if(!isReadableSpan(e))return;let{spanId:t,traceId:n}=e.spanContext();if(!isHexId(n,32)||!isHexId(t,16))return;let r=JsonTraceSerializer.serializeRequest([e]);if(r===void 0)return;let i=e.attributes[`gen_ai.conversation.id`],a=typeof i==`string`&&i.length>0?i:void 0;this.#t=this.#t.then(async()=>{let e=resolveLocalTraceDirectory(this.#e,n),i=resolveLocalTraceSegmentsDirectory(this.#e,n);await mkdir(i,{recursive:!0}),await atomicWriteFile(join(i,`${t}.otlp.json`),r),a!==void 0&&await indexLocalTraceConversation({conversationId:a,traceDirectory:e})}).catch(e=>{this.#n||(this.#n=!0,log.warn(`local trace persistence failed`,{error:formatError(e)}))})}shutdown(){return this.forceFlush()}};function isReadableSpan(e){return typeof e==`object`&&!!e&&`attributes`in e&&`spanContext`in e&&typeof e.spanContext==`function`}function isHexId(e,t){return e.length===t&&/^[0-9a-f]+$/u.test(e)}export{LocalTraceSpanProcessor,resolveLocalTraceSchemaDirectory,resolveLocalTraceSegmentsDirectory};
1
+ import{mkdir}from"node:fs/promises";import{createLogger,formatError}from"#internal/logging.js";import{join}from"node:path";import{atomicWriteFile}from"#shared/atomic-write-file.js";import{indexLocalTraceConversation}from"#tracing/local/trace-discovery-index.js";import{JsonTraceSerializer}from"#compiled/@opentelemetry/otlp-transformer/index.js";const log=createLogger(`harness.local-trace-span-processor`);function resolveLocalTraceStoreDirectory(e){return join(e,`.eve`,`traces`)}function resolveLocalTraceSchemaDirectory(e){return join(resolveLocalTraceStoreDirectory(e),`v1`)}function resolveLocalTraceDirectory(e,t){return join(resolveLocalTraceSchemaDirectory(e),t)}function resolveLocalTraceSegmentsDirectory(e,t){return join(resolveLocalTraceDirectory(e,t),`segments`)}var LocalTraceSpanProcessor=class{#e;#t=Promise.resolve();#n=!1;constructor(e){this.#e=e}forceFlush(){return this.#t}onStart(){}onEnd(e){if(!isReadableSpan(e))return;let{spanId:t,traceId:n}=e.spanContext();if(!isHexId(n,32)||!isHexId(t,16))return;let r=JsonTraceSerializer.serializeRequest([e]);if(r===void 0)return;let i=e.attributes[`gen_ai.conversation.id`],a=typeof i==`string`&&i.length>0?i:void 0;this.#t=this.#t.then(async()=>{let e=resolveLocalTraceDirectory(this.#e,n),i=resolveLocalTraceSegmentsDirectory(this.#e,n);await mkdir(i,{recursive:!0}),await atomicWriteFile(join(i,`${t}.otlp.json`),r),a!==void 0&&await indexLocalTraceConversation({conversationId:a,traceDirectory:e})}).catch(e=>{this.#n||(this.#n=!0,log.warn(`local trace persistence failed`,{error:formatError(e)}))})}shutdown(){return this.forceFlush()}};function isReadableSpan(e){return typeof e==`object`&&!!e&&`attributes`in e&&`spanContext`in e&&typeof e.spanContext==`function`}function isHexId(e,t){return e.length===t&&/^[0-9a-f]+$/u.test(e)}export{LocalTraceSpanProcessor,resolveLocalTraceSchemaDirectory,resolveLocalTraceSegmentsDirectory};
@@ -1,4 +1,4 @@
1
- import type { LocalTraceSpan } from "#tracing/local-trace-reader.js";
1
+ import type { LocalTraceSpan } from "#tracing/local/trace-reader.js";
2
2
  /** Structural metadata and totals for one retained trace, not its final outcome. */
3
3
  export interface LocalTraceSummary {
4
4
  readonly traceId: string;
@@ -0,0 +1 @@
1
+ import{localTraceOperations,traceModelName,traceSessionId,traceStringAttribute,traceToolName,uniqueLocalTraceSpans}from"#tracing/local/trace-operations.js";import{USAGE_FIELDS}from"#compiled/@eve/tracing/otel.js";function summarizeLocalTrace(e,t){let n=uniqueLocalTraceSpans(t),r=new Set,i=new Set,a=new Set,o=new Set,s=n[0]?.startTimeNs??0n,c=s,l=0,u=0,d,f=0,p=0,m=0;for(let e of n){if(e.startTimeNs<s&&(s=e.startTimeNs),e.endTimeNs>c&&(c=e.endTimeNs),add(r,traceModelName(e)),add(i,traceStringAttribute(e,`agent.name`)),add(a,traceStringAttribute(e,`gen_ai.conversation.id`)),add(o,traceSessionId(e)),e.statusCode===2&&(f+=1),e.name!==`agent.step`)continue;p+=numberAttribute(e,`agent.usage.input_tokens`)??0,m+=numberAttribute(e,`agent.usage.output_tokens`)??0,l+=numberAttribute(e,USAGE_FIELDS.cacheReadTokens)??numberAttribute(e,`gen_ai.usage.cache_read.input_tokens`)??0,u+=numberAttribute(e,USAGE_FIELDS.cacheWriteTokens)??numberAttribute(e,`gen_ai.usage.cache_creation.input_tokens`)??0;let t=localTraceSpanCostUsd(e);t!==void 0&&(d=(d??0)+t)}let h=new Set,g=0,_=0;for(let e of localTraceOperations(n))e.category===`model`&&(g+=1),e.category===`tool`&&(_+=1,add(h,traceToolName(e.span)));return{traceId:e,startedAt:new Date(Number(s/1000000n)).toISOString(),durationMs:Number(c-s)/1e6,spanCount:n.length,agentNames:[...i].sort(),conversationIds:[...a].sort(),sessionIds:[...o].sort(),models:[...r].sort(),toolNames:[...h].sort(),modelCalls:g,toolCalls:_,errorSpanCount:f,cacheReadTokens:l,cacheWriteTokens:u,costUsd:d,inputTokens:p,outputTokens:m}}function localTraceSpanCostUsd(e){return numberAttribute(e,`gen_ai.usage.gateway_cost`)??numberAttribute(e,`gen_ai.usage.cost`)}function numberAttribute(e,t){let n=e.attributes[t];if(typeof n==`number`)return Number.isFinite(n)&&n>=0?n:void 0;if(typeof n==`string`&&n.trim()!==``){let e=Number(n);return Number.isFinite(e)&&e>=0?e:void 0}}function add(e,t){t!==void 0&&e.add(t)}export{localTraceSpanCostUsd,summarizeLocalTrace};
@@ -1,5 +1,5 @@
1
1
  import type { SpanProcessor } from "#compiled/@vercel/otel/index.js";
2
- import { type SpanExportPolicy } from "#tracing/span-export-policy.js";
2
+ import { type SpanExportPolicy } from "#tracing/eve/span-export-policy.js";
3
3
  /**
4
4
  * The local spool, as a span processor.
5
5
  *
@@ -0,0 +1 @@
1
+ import{normalizeSpanExportPolicies}from"#tracing/eve/span-export-policy.js";import{LocalTraceSpanProcessor}from"#tracing/local/trace-span-processor.js";import{AgentTraceSpanProcessor}from"#tracing/local/agent-trace-span-processor.js";import{requestLocalTraceStorePrune,resolveLocalTraceRetentionSettings}from"#tracing/local/trace-retention.js";function hasConversationRelease(e){return typeof e.releaseConversation==`function`}function createLocalTracesProcessor(e={}){let t=e.appRoot??process.env.EVE_DEV_WORKER_APP_ROOT;if(t===void 0)return inertLocalTracesProcessor();let n=resolveLocalTraceRetentionSettings(),r=new AgentTraceSpanProcessor(n.enabled?[new LocalTraceSpanProcessor(t)]:[]),requestPrune=()=>{n.enabled&&requestLocalTraceStorePrune({activeTraceIds:r.activeTraceIds(),appRoot:t,maxAgeMs:n.maxAgeMs,maxTotalBytes:n.maxTotalBytes,retainCount:n.retainCount})};requestPrune();let forceFlush=async()=>{await r.forceFlush(),r.releaseCompletedTraces()&&requestPrune()};return{forceFlush,onEnd:e=>r.onEnd(e),onStart:(e,t)=>r.onStart(e,t),async releaseConversation(e){return await forceFlush(),r.releaseConversation(e)?(requestPrune(),!0):!1},shutdown:()=>r.shutdown()}}function resolveLocalTracesExportPolicy(e){return process.env.EVE_TRACES_CONTENT===`off`?[{span:()=>({redact:!0,inputs:!0,outputs:!0})},...normalizeSpanExportPolicies(e)]:e}function inertLocalTracesProcessor(){return{forceFlush:async()=>void 0,onEnd:()=>void 0,onStart:()=>void 0,releaseConversation:async()=>!1,shutdown:async()=>void 0}}export{createLocalTracesProcessor,hasConversationRelease,resolveLocalTracesExportPolicy};
@@ -115,7 +115,7 @@ Use the shared `approval` option to gate every tool served by an MCP connection.
115
115
 
116
116
  ### Gate specific tools by name or input
117
117
 
118
- A remote MCP server usually mixes read tools with destructive or publishing ones, so a blanket `always()` would prompt on every harmless call. Pass a custom policy instead — the same [`Approval`](/docs/human-in-the-loop#approvals) shape authored tools use — to gate only the calls that matter. The policy receives `{ session, toolName, toolInput, approvedTools, callId, abortSignal }` and returns an approval status, synchronously or as a promise.
118
+ A remote MCP server usually mixes read tools with destructive or publishing ones, so a blanket `always()` would prompt on every harmless call. Pass a custom policy instead — the same [`Approval`](/docs/human-in-the-loop#approvals) shape authored tools use — to gate only the calls that matter. The policy receives `{ session, toolName, toolInput, toolAnnotations, approvedTools, callId, abortSignal }` and returns an approval status, synchronously or as a promise.
119
119
 
120
120
  This connection always gates deletes, gates a publish only when the call actually schedules a post, and lets everything else through:
121
121
 
@@ -157,6 +157,27 @@ Two details are specific to connection tools:
157
157
 
158
158
  Return `"user-approval"` (or `true`) to pause for a person and `"not-applicable"` (or `false`) to run without a prompt; return `"approved"` or `"denied"` to decide automatically without involving anyone.
159
159
 
160
+ ### Gate by the server's tool annotations
161
+
162
+ Many MCP servers declare [tool annotations](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#tool) such as `readOnlyHint` and `destructiveHint` for each tool. eve passes what the server declared for the called tool as `toolAnnotations`, typed as `ConnectionToolAnnotations` from `eve/tools/approval`. It is `undefined` when the server declares none, so keep a fallback:
163
+
164
+ ```ts title="agent/connections/linear.ts"
165
+ import { connect } from "@vercel/connect/eve";
166
+ import { defineMcpClientConnection } from "eve/connections";
167
+
168
+ export default defineMcpClientConnection({
169
+ url: "https://mcp.linear.app/mcp",
170
+ description: "Linear issues and projects.",
171
+ auth: connect("mcp.linear.app/linear"),
172
+ approval: ({ toolAnnotations }) => {
173
+ if (toolAnnotations?.readOnlyHint === true) return "not-applicable";
174
+ return "user-approval";
175
+ },
176
+ });
177
+ ```
178
+
179
+ Annotations are hints from the server, not guarantees. Trust them only as far as you trust the server that sent them.
180
+
160
181
  [Human-in-the-loop](/docs/human-in-the-loop#approvals) covers the full set of statuses, how `approvedTools` and `session.auth` factor in, and how a gated call pauses and resumes durably.
161
182
 
162
183
  ## Forward the caller to an eve agent
@@ -3,7 +3,7 @@ title: "Assertions"
3
3
  description: "Scoped methods, value assertions, the matcher mini-language, and gate vs soft severity."
4
4
  ---
5
5
 
6
- Assertions are how an eval grades what its `test(t)` function produced. Each one records a result and returns a chainable handle. The runner reads every recorded result to compute the verdict, so a single run reports every failing assertion rather than dying on the first. There are two deterministic surfaces: scoped methods and `t.check` for grading a specific value. For model-graded assertions, see [Judge](./judge).
6
+ Assertions are how an eval grades what its `test(t)` function produced. Each one records a result and returns a chainable handle. The runner reads every recorded result to compute the verdict, so a single run reports every failing assertion rather than dying on the first. There are three deterministic surfaces: scoped methods, `t.check` for grading a specific value, and `t.score` for recording a measurement you computed yourself. For model-graded assertions, see [Judge](./judge).
7
7
 
8
8
  ## Scoped assertions
9
9
 
@@ -83,6 +83,53 @@ For example, a failed labeled equality check prints:
83
83
 
84
84
  Pick the cheapest builder that captures what "correct" means. When exact match is too strict but a judge model is overkill, `similarity` is the middle ground. For nuanced grading, reach for the [judge](./judge).
85
85
 
86
+ ## Scores with `t.score`
87
+
88
+ `t.score(evaluation)` records a score from 0 to 1. The evaluation is the number or `{ score, message?, metadata? }`, or a promise of either. Chain `.label(key)` to name it; reporters and artifacts expose the label as `key`. Without a label the score reports as `score`, and several unlabeled scores share that name.
89
+
90
+ ```ts
91
+ const reply = turn.message ?? "";
92
+ t.score({
93
+ score: Math.max(0, 1 - reply.length / 400),
94
+ metadata: { length: reply.length },
95
+ }).label("reply-brevity");
96
+ t.score(gradeFaithfulness(reply, reference)).label("faithfulness"); // async
97
+ ```
98
+
99
+ On its own a score has no verdict and does not affect the eval's outcome. Chain a rule when it should:
100
+
101
+ ```ts
102
+ t.score(gradeFaithfulness(reply, reference)).label("faithfulness").gate(0.9); // fails below 0.9
103
+ t.score(brevity).label("reply-brevity").atLeast(0.5); // marks the eval `scored`, fatal under --strict
104
+ ```
105
+
106
+ The score is reported as measured. A `0.82` gated at `0.9` is reported as `score: 0.82`, `threshold: 0.9`, `passed: false`. An evaluator that throws or returns a score outside 0 to 1 records an errored outcome with the error message and no score, and fails the eval.
107
+
108
+ Every [reporter](./reporters#custom-reporters) receives the entries in `onEvalComplete` and can read them by `key`:
109
+
110
+ ```ts
111
+ onEvalComplete(result) {
112
+ for (const { key, score, threshold, passed } of result.assertions) {
113
+ if (key === undefined) continue;
114
+ store.write({ evalId: result.id, key, score, threshold, passed });
115
+ }
116
+ }
117
+ ```
118
+
119
+ The same entries land in the [run artifacts](./running#artifacts) under `.eve/evals/`, in `summary.json` and one line per eval in `results.jsonl`:
120
+
121
+ ```json
122
+ {
123
+ "name": "score [reply-brevity]",
124
+ "key": "reply-brevity",
125
+ "score": 0.84,
126
+ "severity": "soft",
127
+ "errored": false
128
+ }
129
+ ```
130
+
131
+ `threshold` and `passed` are present only when a rule was chained.
132
+
86
133
  ## The matcher mini-language
87
134
 
88
135
  `t.calledTool` and `t.calledSubagent` take matcher objects. Tools accept `{ input, output, status, count }`; subagents accept `{ callId, childSessionId, remoteUrl, output, status, count }`. Calls match `status: "completed"` by default. Tool lifecycle checks also accept `"pending"`, `"failed"`, and `"rejected"`. Subagent checks accept `"working"`, `"completed"`, `"failed"`, and `"cancelled"`. A numeric `count` requires an exact number of calls matching every supplied constraint. Use a predicate for ranges or other custom count requirements; it receives the observed number of matching calls.
@@ -164,9 +211,9 @@ const request = session.requireInputRequest({ toolName: "guarded" });
164
211
  Every assertion returns a chainable handle. Severity rides on the assertion, so there is no separate thresholds map to keep in sync.
165
212
 
166
213
  - `.gate(threshold?)` is hard. A miss marks the eval `failed` and `eve eval` exits non-zero.
167
- - `.soft(threshold?)` is tracked data. A below-threshold miss marks the eval `scored`, fatal only under `--strict`. With no threshold, it is tracked-only and never fails.
214
+ - `.soft(threshold?)` is tracked data. A below-threshold miss marks the eval `scored`, fatal only under `--strict`. With no threshold it records no verdict and never fails.
168
215
  - `.atLeast(threshold)` is soft with a bar (equivalent to `.soft(threshold)`).
169
- - `.label(name)` adds a stable name when an eval records several assertions from the same family.
216
+ - `.label(key)` adds a stable name when an eval records several assertions from the same family. Reporters and artifacts expose it as `key`. Braintrust and Datadog keep one score per name, so `eve eval` warns when soft assertions in one eval share a name with different scores.
170
217
 
171
218
  The defaults are chosen so you rarely set severity. Run-level methods and `includes`/`equals`/`matches` are gates; `similarity` and every `t.judge(...)` assertion are soft. Annotate only when you deviate:
172
219
 
@@ -154,6 +154,7 @@ Each surface matches a genuinely different kind of judgment:
154
154
 
155
155
  - **Scoped methods** read the final whole run on `t`, snapshot one independent session when invoked there, or inspect one immutable `EveEvalTurn`. See [Assertions](./assertions).
156
156
  - **`t.check(value, assertion)`** grades an explicit value with a deterministic builder from `eve/evals/expect`, such as `t.check(turn.message, includes("sunny"))`. Grade `turn.message`, an intermediate draft, parsed JSON, or anything else. See [Assertions](./assertions).
157
+ - **`t.score(evaluation)`** records a score, such as a length ratio or an evaluator's result. Chain `.label(key)` to name it, and `.gate(threshold)` or `.atLeast(threshold)` to let it decide the eval. See [Assertions](./assertions#scores-with-tscore).
157
158
  - **`t.judge(...)`** is the LLM-as-judge surface, like `t.judge("cites a source")`. It grades the most recently settled turn’s assistant message by default; pass `{ on: turn.session.transcript }` to grade a multi-turn conversation. The judge uses the configured judge model, never the agent under test. See [Judge](./judge).
158
159
 
159
160
  ## Gate vs soft
@@ -161,7 +162,7 @@ Each surface matches a genuinely different kind of judgment:
161
162
  Every assertion returns a chainable handle, so severity rides on the assertion itself. There is no separate thresholds map.
162
163
 
163
164
  - **Gates** are hard. A failed gate marks the eval `failed` and `eve eval` exits non-zero. Run-level methods, `includes`, `equals`, and `matches` are gates by default.
164
- - **Soft** assertions are tracked data. They land in reports and artifacts, and a below-threshold soft assertion marks the eval `scored` (visible but not fatal, unless you pass `--strict`). `similarity` and every `t.judge(...)` assertion are soft by default. A soft assertion with no threshold is tracked-only and never fails.
165
+ - **Soft** assertions are tracked data. They land in reports and artifacts, and a below-threshold soft assertion marks the eval `scored` (visible but not fatal, unless you pass `--strict`). `similarity`, every `t.judge(...)` assertion, and every `t.score(...)` are soft by default. A soft assertion with no threshold records no verdict and never fails.
165
166
 
166
167
  Override per assertion: `.gate(threshold?)` promotes to a hard gate, `.soft(threshold?)` demotes to tracked, and `.atLeast(threshold)` is a soft assertion with a bar.
167
168
 
@@ -38,7 +38,7 @@ export default defineEval({
38
38
  });
39
39
  ```
40
40
 
41
- The reporter config takes an optional `projectName` and `experimentName`, plus a base experiment (by name or id) to diff against. Gate assertions log as binary scores under a `gate:` prefix so experiments diff gate regressions the same way they diff soft-score regressions. Assertions that share a name, such as several unlabeled judges, log one score: the lowest. Use `.label(name)` to group or separate them. Each assertion's score is stored in the Braintrust metadata under `eveAssertionScores` and failed assertion details under `eveFailedAssertions`; observed traces are stored under `eveTraceIds` and `eveTraceContexts`.
41
+ The reporter config takes an optional `projectName` and `experimentName`, plus a base experiment (by name or id) to diff against. Gate assertions log as binary scores under a `gate:` prefix so experiments diff gate regressions the same way they diff soft-score regressions. Assertions that share a name, such as several unlabeled judges, log one score: the lowest. The console warns under the eval when merged soft scores differ; use `.label(name)` to group or separate them. Errored assertions log no score. Each assertion's score is stored in the Braintrust metadata under `eveAssertionScores` and failed assertion details under `eveFailedAssertions`; observed traces are stored under `eveTraceIds` and `eveTraceContexts`.
42
42
 
43
43
  A reporter instance observes the evals that reference it. Share one instance across several evals (the config, a `shared.ts` export, or every entry of a dataset array) and their results land in a single experiment. Listing the same config reporter on an eval too does not double-report it.
44
44
 
@@ -97,6 +97,8 @@ interface EvalReporter {
97
97
  - `onSessionStart` fires once for each session after eve receives its first trace context. It includes `sessionId`, `primary`, and `traceContext` with `traceId`, `spanId`, and `traceFlags`.
98
98
  - `onEvalComplete` fires with the checks, scores, and verdict. The runner also supplies `context`, including every distinct trace context collected across the eval's sessions. The same list is available as `result.result.traceContexts`.
99
99
 
100
+ Each entry in `result.assertions` is an `AssertionResult`. `name` is the display label, `key` the identifier set by `.label(key)`, and `score` the measurement. `threshold` and `passed` describe the rule and are absent when no rule applies. When a scorer threw, `errored` is `true`, `message` carries the error, and `score` is absent. The `.eve/evals/` artifacts write the same fields.
101
+
100
102
  An eval can create several sessions, and a long session can produce several traces, so completion exposes a list instead of a single trace id. `onEvalStart` does not include a trace because the agent session has not started yet. If the target has no tracing configured, `onSessionStart` does not fire and the completed trace list is empty.
101
103
 
102
104
  `result.result.derived` holds the facts the runner derived from the eval's sessions, such as tool calls and `models`: the distinct ids of the models the steps started with, in session order. Each entry in `result.result.sessions` holds the same facts for one session, in first-use order, so a reporter can tell the primary session's models from those of the other sessions the eval created or attached. A delegated subagent runs in its own session, so its models appear only when the eval attaches that session with `t.target.attachSession`. Compaction and `auto` routing calls are not included.
@@ -64,7 +64,29 @@ approval: auto({
64
64
 
65
65
  A reusable approval grant applies only after every matching request that is already pending has been resolved. If several calls to a `once()`-gated tool have each produced an approval prompt, approving one does not authorize the others; each visible prompt remains an independent decision. After those pending requests are resolved, later calls in the session are allowed automatically.
66
66
 
67
- When the decision depends on the input, pass your own policy instead of a helper. It receives the same session context as tool execution, plus `{ toolName, toolInput, approvedTools, callId, abortSignal }`, and returns an AI SDK 7 approval status synchronously or as a promise. Use `abortSignal` for asynchronous policy work so cancellation stops it with the turn. Use `ctx.session.auth.current` to guard by the caller of the current turn and `ctx.session.auth.initiator` to guard by the caller that created the session. Return `"user-approval"` to pause for a person or `"not-applicable"` to continue without a prompt. `toolInput` can be undefined, so guard the access. This policy denies cross-tenant calls, then requires approval only when an amount crosses a threshold:
67
+ Use the object form of `approval` to replace the default `Approve <tool label>?` text with a tool-specific summary. The `prompt` callback receives the validated `input`, final `toolName`, and `callId`:
68
+
69
+ ```ts title="agent/tools/refund_charge.ts"
70
+ import { defineTool } from "eve/tools";
71
+ import { always } from "eve/tools/approval";
72
+ import { z } from "zod";
73
+
74
+ export default defineTool({
75
+ description: "Refund a charge.",
76
+ inputSchema: z.object({ chargeId: z.string(), amount: z.number() }),
77
+ approval: {
78
+ request: always(),
79
+ prompt: ({ input }) => `Refund $${input.amount.toFixed(2)} for charge ${input.chargeId}?`,
80
+ },
81
+ async execute(input) {
82
+ return refund(input);
83
+ },
84
+ });
85
+ ```
86
+
87
+ Channels render this prompt in their approval UI. Slack also includes the complete tool input in a collapsed **Tool input** block so an approver can inspect the original structured value.
88
+
89
+ When the decision depends on the input, pass your own policy instead of a helper. It receives the same session context as tool execution, plus `{ toolName, toolInput, approvedTools, callId, abortSignal }` (connection tools also get `toolAnnotations`), and returns an AI SDK 7 approval status synchronously or as a promise. Use `abortSignal` for asynchronous policy work so cancellation stops it with the turn. Use `ctx.session.auth.current` to guard by the caller of the current turn and `ctx.session.auth.initiator` to guard by the caller that created the session. Return `"user-approval"` to pause for a person or `"not-applicable"` to continue without a prompt. `toolInput` can be undefined, so guard the access. This policy denies cross-tenant calls, then requires approval only when an amount crosses a threshold:
68
90
 
69
91
  ```ts
70
92
  approval: ({ session, toolInput }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.78.0",
3
+ "version": "0.79.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -574,6 +574,7 @@
574
574
  "@chat-adapter/twilio": "4.41.0",
575
575
  "@clack/core": "1.3.1",
576
576
  "@eve/catalog": "0.0.1",
577
+ "@eve/tracing": "0.0.0",
577
578
  "@linqapp/chat-sdk-adapter": "^0.5.1",
578
579
  "@modelcontextprotocol/server": "2.0.0",
579
580
  "@nuxt/kit": "^4.0.0",
@@ -1,11 +0,0 @@
1
- import { type Tracer } from "#compiled/@opentelemetry/api/index.js";
2
- import type { InstrumentationProviderDefinition } from "#instrumentation/lifecycle.js";
3
- import type { AgentToolContext } from "#tracing/agent-tool-instrumentation.js";
4
- import type { AgentSpanIdGenerator } from "#tracing/agent-span-id-generator.js";
5
- /** Builds durable approval wait spans under their originating runtime action. */
6
- export declare function createAgentApprovalInstrumentation(input: {
7
- readonly actionContextFor: (sessionId: string, turnId: string, callId: string) => Promise<AgentToolContext | undefined>;
8
- readonly frameworkVersion: string;
9
- readonly idGenerator: AgentSpanIdGenerator;
10
- readonly tracer: Tracer;
11
- }): Pick<NonNullable<InstrumentationProviderDefinition["events"]>, "input.requested" | "input.resolved">;
@@ -1 +0,0 @@
1
- import{normalizeChannelAudience}from"#shared/channel-audience.js";import{AGENT_SPAN_NAMES}from"#tracing/agent-span-contract.js";import{ROOT_CONTEXT,trace}from"#compiled/@opentelemetry/api/index.js";import{agentSpanNamingAttributes}from"#tracing/agent-span-naming.js";import{contentAttribute}from"#tracing/agent-otel-content.js";import{recordAgentSpanError}from"#tracing/agent-span-error.js";import{agentTraceIdentityAttributes,traceSessionIdOf}from"#tracing/agent-otel-attributes.js";import{decodeTraceSessionId}from"#tracing/agent-trace-context-codec.js";import{withChannelAudience}from"#tracing/channel-audience-context.js";function createAgentApprovalInstrumentation(e){return{"input.requested":async(t,n)=>{if(t.kind!==`tool-approval`||readState(n.state.get())!==void 0)return;let r=await e.actionContextFor(t.scope.sessionId,t.scope.turnId,t.action.callId);if(r===void 0)return;let i={actionCallId:t.action.callId,actionName:t.action.name,attemptIndex:t.scope.attemptIndex,channelAudience:normalizeChannelAudience(t.scope.channelAudience),parent:{spanId:r.spanContext.spanId,traceFlags:r.spanContext.traceFlags,traceId:r.spanContext.traceId},requestId:t.requestId,rootSessionId:t.scope.rootSessionId??t.scope.sessionId,traceSessionId:traceSessionIdOf(t.scope),sessionId:t.scope.sessionId,startTimeMs:Date.now(),stepIndex:t.scope.stepIndex,turnId:t.scope.turnId},a=contentAttribute(t.request);a!==void 0&&(i.requestAttribute=a),n.state.set(i)},"input.resolved":(t,n)=>{let r=readState(n.state.get());if(r===void 0)return;let i=e.idGenerator.withSpanId(e.idGenerator.deriveSpanId(`approval:${t.idempotencyKey}`),()=>e.tracer.startSpan(AGENT_SPAN_NAMES.approval,{attributes:{"gen_ai.tool.call.id":r.actionCallId,"agent.action.name":r.actionName,"agent.approval.kind":`tool-approval`,"agent.approval.outcome":t.outcome,"agent.approval.request_id":r.requestId,"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.step.attempt":r.attemptIndex,"agent.step.index":r.stepIndex,"agent.turn.id":r.turnId,"gen_ai.operation.name":`workflow`,...agentSpanNamingAttributes(`agent.approval`,`workflow`),...agentTraceIdentityAttributes({rootSessionId:r.rootSessionId,traceSessionId:r.traceSessionId,sessionId:r.sessionId})},startTime:r.startTimeMs},withChannelAudience(trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext({...r.parent,isRemote:!1})),r.channelAudience)));if(r.requestAttribute!==void 0&&i.setAttribute(`agent.approval.request`,r.requestAttribute),t.response!==void 0){let e=contentAttribute(t.response);e!==void 0&&i.setAttribute(`agent.approval.response`,e)}t.outcome===`failed`&&recordAgentSpanError(i,t.error),i.end()}}}function readState(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e,n=t.parent;if(typeof n!=`object`||!n||Array.isArray(n))return;let r=n;if(typeof t.actionCallId!=`string`||typeof t.actionName!=`string`||typeof t.attemptIndex!=`number`||typeof r.spanId!=`string`||typeof r.traceFlags!=`number`||typeof r.traceId!=`string`||typeof t.requestId!=`string`||typeof t.rootSessionId!=`string`||typeof t.sessionId!=`string`||typeof t.startTimeMs!=`number`||typeof t.stepIndex!=`number`||typeof t.turnId!=`string`)return;let i=t.requestAttribute;if(i===void 0||typeof i==`string`)return{actionCallId:t.actionCallId,actionName:t.actionName,attemptIndex:t.attemptIndex,channelAudience:normalizeChannelAudience(t.channelAudience),parent:{isRemote:!1,spanId:r.spanId,traceFlags:r.traceFlags,traceId:r.traceId},requestAttribute:i,requestId:t.requestId,rootSessionId:t.rootSessionId,traceSessionId:decodeTraceSessionId(t),sessionId:t.sessionId,startTimeMs:t.startTimeMs,stepIndex:t.stepIndex,turnId:t.turnId}}export{createAgentApprovalInstrumentation};
@@ -1 +0,0 @@
1
- import{applyLiveDeliveryAudienceCeiling,readForwardedTraceAssertion}from"#shared/forwarded-trace-policy.js";import{ConversationIdKey}from"#context/keys.js";import{readConversationId}from"#shared/conversation-identity.js";import{readActionTraceContext,readTurnTraceContext}from"#tracing/agent-trace-context-store.js";function resolveToolCallAgentTrace(e){let{serializedContext:t,sessionId:n,turnId:r}=e;return toChildTraceDispatch({conversation:e.conversation,conversationId:readConversationId(t[ConversationIdKey.name]),stored:readActionTraceContext(t,n,r,e.callId)??readTurnTraceContext(t,n,r)})}function toChildTraceDispatch(e){let{stored:t}=e,n=e.conversation?.audience??`unknown`,r=e.conversation?.environment??`production`,i=readForwardedTraceAssertion(t?.forwardedTracePolicy),a=t?.decision===void 0?t:{...t,decision:applyLiveDeliveryAudienceCeiling(t.decision,n,i,r)};return{conversationId:e.conversationId,originAudience:i?.originAudience??n,parentTraceContext:a}}export{resolveToolCallAgentTrace};
@@ -1,16 +0,0 @@
1
- import { type Tracer } from "#compiled/@opentelemetry/api/index.js";
2
- import type { InstrumentationProviderDefinition } from "#instrumentation/lifecycle.js";
3
- import type { InstrumentationMemoryExecutionOperation } from "#instrumentation/memory.js";
4
- import type { AgentTraceStateStore } from "#tracing/agent-trace-state.js";
5
- import type { ConversationEnvironment } from "#shared/conversation-context.js";
6
- interface AgentMemoryInstrumentation {
7
- readonly events: Pick<NonNullable<InstrumentationProviderDefinition["events"]>, "memory.operation.completed" | "memory.operation.failed" | "memory.operation.started">;
8
- runInContext<T>(operation: InstrumentationMemoryExecutionOperation, execute: () => PromiseLike<T>): Promise<T>;
9
- }
10
- export declare function createAgentMemoryInstrumentation(input: {
11
- readonly environment: ConversationEnvironment;
12
- readonly recordOutputs?: boolean;
13
- readonly stateStore: AgentTraceStateStore;
14
- readonly tracer: Tracer;
15
- }): AgentMemoryInstrumentation;
16
- export {};
@@ -1 +0,0 @@
1
- import{normalizeChannelAudience}from"#shared/channel-audience.js";import{applyLiveDeliveryAudienceCeiling,resolveForwardedTraceSeed}from"#shared/forwarded-trace-policy.js";import{contextStorage}from"#context/container.js";import{SessionTraceSeedKey}from"#context/keys.js";import{withOperationConversation}from"#tracing/conversation-context.js";import{isSampledTrace}from"#tracing/sampled-trace.js";import{ROOT_CONTEXT,SpanKind,context,trace}from"#compiled/@opentelemetry/api/index.js";import{isAgentTraceContext,markAgentTraceContext}from"#tracing/agent-trace-context.js";import{withErrorContent}from"#tracing/error-content-context.js";import{agentSpanNamingAttributes}from"#tracing/agent-span-naming.js";import{genAiMemoryRecordsAttribute}from"#tracing/agent-otel-content.js";import{recordAgentSpanError}from"#tracing/agent-span-error.js";import{agentTraceIdentityAttributes,traceSessionIdOf}from"#tracing/agent-otel-attributes.js";import{withChannelAudience}from"#tracing/channel-audience-context.js";import{suppressTracing}from"#tracing/suppress-tracing.js";function createAgentMemoryInstrumentation(e){let t=e.recordOutputs??!1,n=new Map,parentContext=async t=>{let n=context.active();if(isAgentTraceContext(n))return n;let r=await e.stateStore.getSession(t.sessionId);if(t.turnId!==void 0){let n=await e.stateStore.getTurn(t.sessionId,t.turnId);if(n!==void 0)return withChannelAudience(contextFromSpanContext(n.context),r?.channelAudience)}return r===void 0?void 0:withChannelAudience(contextFromSpanContext(r.context),r.channelAudience)},onStarted=async t=>{if(n.has(t.idempotencyKey))return;let r=await parentContext(t),i=r===void 0?void 0:trace.getSpan(r)?.spanContext();if(r===void 0||i===void 0||!isSampledTrace(i))return;let a=e.tracer.startSpan(t.operationName,{attributes:memorySpanAttributes(t),kind:SpanKind.CLIENT},r);n.set(t.idempotencyKey,{context:trace.setSpan(r,a),span:a})},onTerminal=e=>{let t=n.get(e.idempotencyKey);t!==void 0&&(n.delete(e.idempotencyKey),updateMemorySpan(t.span,e),t.span.end())};return{events:{"memory.operation.completed":onTerminal,"memory.operation.failed":onTerminal,"memory.operation.started":onStarted},async runInContext(r,i){let a=await e.stateStore.getSession(r.sessionId),o=n.get(r.idempotencyKey)?.context;if(o===void 0&&r.turnId!==void 0){let t=await e.stateStore.getTurn(r.sessionId,r.turnId);t!==void 0&&(o=withChannelAudience(contextFromSpanContext(t.context),a?.channelAudience),isSampledTrace(t.context)||(o=suppressTracing(o)))}o===void 0&&a!==void 0&&(o=withChannelAudience(contextFromSpanContext(a.context),a.channelAudience),isSampledTrace(a.context)||(o=suppressTracing(o)));let s=resolveForwardedTraceSeed(contextStorage.getStore()?.get(SessionTraceSeedKey)),c=s?.decision??a?.decision,l=c===void 0?void 0:applyLiveDeliveryAudienceCeiling(c,normalizeChannelAudience(a?.channelAudience),s?.forwardedTracePolicy,e.environment);return o===void 0?await i():await context.with(markAgentTraceContext(withErrorContent(withOperationConversation(o,{rootSessionId:a?.rootSessionId,sessionId:r.sessionId}),t&&l?.action===`record`&&l.recordOutputs)),i)}}}function memorySpanAttributes(e){let t={"agent.memory.phase":e.phase,"agent.memory.slot":e.slot,"gen_ai.memory.store.id":e.storeId,"gen_ai.operation.name":e.operationName,...agentSpanNamingAttributes(e.operationName,e.operationName),...agentTraceIdentityAttributes({rootSessionId:e.rootSessionId,traceSessionId:traceSessionIdOf(e),sessionId:e.sessionId})};return e.turnId!==void 0&&(t[`agent.turn.id`]=e.turnId),t}function updateMemorySpan(e,t){if(t.type===`memory.operation.failed`)recordAgentSpanError(e,t.error);else{t.recordCount!==void 0&&e.setAttribute(`gen_ai.memory.record.count`,t.recordCount);let n=genAiMemoryRecordsAttribute(t.outputRecords??[]);n!==void 0&&t.outputRecords!==void 0&&e.setAttribute(`gen_ai.memory.records`,n)}}function contextFromSpanContext(e){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(e))}export{createAgentMemoryInstrumentation};
@@ -1,10 +0,0 @@
1
- export declare function traceSessionIdOf(scope: {
2
- readonly traceSessionId?: string;
3
- readonly rootSessionId?: string;
4
- readonly sessionId: string;
5
- }): string;
6
- export declare function agentTraceIdentityAttributes(input: {
7
- readonly rootSessionId: string;
8
- readonly sessionId: string;
9
- readonly traceSessionId: string;
10
- }): Record<string, string | number>;
@@ -1 +0,0 @@
1
- import{AGENT_TRACE_SCHEMA_VERSION}from"#tracing/agent-span-contract.js";import{operationConversationId}from"#tracing/conversation-context.js";function traceSessionIdOf(e){return e.traceSessionId??e.rootSessionId??e.sessionId}function agentTraceIdentityAttributes(e){let t=operationConversationId(e),n={"agent.run.id":e.sessionId,"agent.trace.schema.version":AGENT_TRACE_SCHEMA_VERSION,"gen_ai.conversation.id":t};return process.env.VERCEL_ENV!==void 0&&(n[`vercel.session_id`]=e.traceSessionId),n}export{agentTraceIdentityAttributes,traceSessionIdOf};
@@ -1,4 +0,0 @@
1
- import{isUserMessageKind}from"#harness/messages.js";const CONTENT_ATTRIBUTE_LIMIT=32768;function contentAttribute(e){if(e===void 0)return;let t;try{t=JSON.stringify(e)}catch{return}if(t!==void 0)return textContentAttribute(t)}function genAiInputMessagesAttribute(e){if(!Array.isArray(e))return;let t=e.flatMap(e=>{if(!isRecord(e)||e.role===`system`||typeof e.role!=`string`)return[];let t=semanticParts(e.content);if(t.length===0)return[];let n=e.role===`user`&&isUserMessageKind(e.kind)?e.kind:void 0;return[n===void 0?{parts:t,role:e.role}:{kind:n,parts:t,role:e.role}]});for(let e=0;e<t.length;e+=1){let n=semanticJsonAttribute(t.slice(e));if(n!==void 0)return n}return truncateSingleSemanticMessage(t)??semanticJsonAttribute([])}function genAiSystemInstructionsAttribute(e){let t=systemPromptText(e);if(t!==void 0)return fitSemanticText(t,e=>[{content:e,type:`text`}])}function genAiToolDefinitionsAttribute(e){if(!Array.isArray(e))return;let t=e.flatMap(e=>{if(!isRecord(e)||typeof e.name!=`string`)return[];let t={name:e.name};return typeof e.description==`string`&&(t.description=e.description),e.inputSchema!==void 0&&(t.parameters=e.inputSchema),[t]});if(t.length===0)return;let n=[],r=2;for(let e of t){let t=stringifyContent(e);if(t===void 0)break;let i=r+(n.length===0?0:1)+t.length;if(i>32768)break;n.push(t),r=i}return`[${n.join(`,`)}]`}function genAiOutputMessagesAttribute(e,t){let n=semanticParts(e);return semanticJsonAttribute([{finish_reason:t===`tool-calls`?`tool_call`:t,parts:n,role:`assistant`}])}function genAiMemoryRecordsAttribute(e){return semanticJsonAttribute(e)}function toolResultsContentAttribute(e){if(e.length===0)return;let t=stringifyContent(e);if(t!==void 0&&t.length<=32768)return t;for(let t=CONTENT_ATTRIBUTE_LIMIT;t>=0;t=t>=256?Math.floor(t/2):-1){let n=stringifyContent(e.map(e=>cappedToolResult(e,t)));if(n!==void 0&&n.length<=32768)return n}}function cappedToolResult(e,t){let n={toolName:e.toolName};for(let r of[`input`,`output`,`error`]){if(!(r in e))continue;let i=e[r],a=typeof i==`string`?i:stringifyContent(i)??``;n[r]=a.length<=t?a:`${a.slice(0,t)}… [truncated]`}return n}function systemPromptText(e){if(typeof e==`string`)return e.length===0?void 0:e;if(!isRecord(e)&&!Array.isArray(e))return;let t=Array.isArray(e)?e:[e],n=[];for(let e of t)if(isRecord(e)){if(typeof e.content==`string`)n.push(e.content);else if(Array.isArray(e.content))for(let t of e.content)isRecord(t)&&t.type===`text`&&typeof t.text==`string`&&n.push(t.text)}let r=n.join(`
2
-
3
- `).trim();return r.length===0?void 0:r}function textContentAttribute(e){if(e.length!==0)return e.length<=32768?e:`${e.slice(0,CONTENT_ATTRIBUTE_LIMIT)}… [truncated]`}function stringifyContent(e){try{return JSON.stringify(e)}catch{return}}function semanticJsonAttribute(e){let t=stringifyContent(e);return t!==void 0&&t.length<=32768?t:void 0}function truncateSingleSemanticMessage(e){let t=e.at(-1);if(t===void 0||typeof t.role!=`string`)return;let n=semanticMessageText(t.parts),r=typeof t.kind==`string`?{kind:t.kind,role:t.role}:{role:t.role};return fitSemanticText(n,e=>[{...r,parts:[{content:e,type:`text`}]}],!0)}function fitSemanticText(e,t,n=!1){if(!n&&e.length<=32768){let n=semanticJsonAttribute(t(e));if(n!==void 0)return n}for(let n=Math.min(e.length,CONTENT_ATTRIBUTE_LIMIT);n>0;n-=256){let r=semanticJsonAttribute(t(`${e.slice(0,n)}… [truncated]`));if(r!==void 0)return r}return semanticJsonAttribute(t(`… [truncated]`))}function semanticMessageText(e){if(!Array.isArray(e))return``;let t=``;for(let n of e){if(!isRecord(n)||n.type!==`text`||typeof n.content!=`string`)continue;let e=t.length===0?``:`
4
- `,r=32769-t.length-e.length;if(r<=0)break;t+=e+n.content.slice(0,r)}return t}function semanticParts(e){if(typeof e==`string`)return[{content:e,type:`text`}];if(!Array.isArray(e))return[];let t=[];for(let n of e){let e=semanticPart(n);e!==void 0&&t.push(e)}return t}function semanticPart(e){if(isRecord(e)&&typeof e.type==`string`)switch(e.type){case`text`:case`reasoning`:{let t=typeof e.text==`string`?e.text:e.content;return typeof t==`string`?{content:t,type:e.type}:void 0}case`tool-call`:return{arguments:e.input,id:stringValue(e.toolCallId)??stringValue(e.callId)??null,name:e.toolName,type:`tool_call`};case`tool-result`:return{id:stringValue(e.toolCallId)??stringValue(e.callId)??null,response:toolResponse(e.output),type:`tool_call_response`};case`tool-error`:return{id:stringValue(e.toolCallId)??stringValue(e.callId)??null,response:e.error instanceof Error?e.error.message:e.error,type:`tool_call_response`};default:return{type:e.type}}}function toolResponse(e){return isRecord(e)?(e.type===`text`||e.type===`error-text`||e.type===`json`||e.type===`error-json`)&&`value`in e?e.value:e.type===`execution-denied`?{denied:!0,reason:e.reason}:e:e}function stringValue(e){return typeof e==`string`?e:void 0}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{CONTENT_ATTRIBUTE_LIMIT,contentAttribute,genAiInputMessagesAttribute,genAiMemoryRecordsAttribute,genAiOutputMessagesAttribute,genAiSystemInstructionsAttribute,genAiToolDefinitionsAttribute,textContentAttribute,toolResultsContentAttribute};
@@ -1,2 +0,0 @@
1
- import{normalizeChannelAudience}from"#shared/channel-audience.js";import{applyLiveDeliveryAudienceCeiling,resolveForwardedTraceSeed}from"#shared/forwarded-trace-policy.js";import{contextStorage}from"#context/container.js";import{SessionTraceSeedKey}from"#context/keys.js";import{AGENT_SPAN_NAMES,agentInvocationSpanName,modelSpanName}from"#tracing/agent-span-contract.js";import{resolveInstrumentationEnvironment}from"#internal/application/dev-environment.js";import{withOperationConversation}from"#tracing/conversation-context.js";import{isSampledTrace,resolveTracePolicyDecision}from"#tracing/sampled-trace.js";import{ROOT_CONTEXT,SpanKind,context,trace}from"#compiled/@opentelemetry/api/index.js";import{markAgentTraceContext}from"#tracing/agent-trace-context.js";import{attemptIdempotencyKey}from"#instrumentation/lifecycle.js";import{withoutInstrumentationContent}from"#instrumentation/content.js";import{withErrorContent}from"#tracing/error-content-context.js";import{readInstrumentationDecision}from"#shared/instrumentation-decision.js";import{agentSpanNamingAttributes}from"#tracing/agent-span-naming.js";import{contentAttribute,genAiInputMessagesAttribute,genAiOutputMessagesAttribute,genAiSystemInstructionsAttribute,genAiToolDefinitionsAttribute,textContentAttribute,toolResultsContentAttribute}from"#tracing/agent-otel-content.js";import{recordAgentSpanError}from"#tracing/agent-span-error.js";import{withAgentToolContentPolicy}from"#tracing/agent-tool-span-context.js";import{agentTraceIdentityAttributes,traceSessionIdOf}from"#tracing/agent-otel-attributes.js";import{withChannelAudience}from"#tracing/channel-audience-context.js";import{suppressTracing}from"#tracing/suppress-tracing.js";import{instrumentationEventForTraceDecision}from"#instrumentation/content-policy.js";import{createAgentApprovalInstrumentation}from"#tracing/agent-approval-instrumentation.js";import{createAgentChannelDeliveryInstrumentation}from"#tracing/agent-channel-delivery-instrumentation.js";import{createAgentToolInstrumentation}from"#tracing/agent-tool-instrumentation.js";import*as runtimeAttributes from"#tracing/agent-otel-runtime-context.js";import{createAgentMemoryInstrumentation}from"#tracing/agent-memory-instrumentation.js";import{readGatewayCost,setAgentInvocationUsage,setAgentUsage,setGenAiUsage}from"#tracing/agent-otel-usage.js";import{createAgentOtelSessionContext}from"#tracing/agent-otel-session-context.js";import{rememberTurnInputMessages,rememberTurnOutputMessages}from"#tracing/agent-otel-turn-state.js";function createAgentOtelInstrumentation(e){let t=e.environment??resolveInstrumentationEnvironment(),n=e.recordInputs??!1,r=e.recordOutputs??!1,i=new WeakMap,a=new Map,o=new WeakMap,s=new WeakMap,c=createAgentToolInstrumentation({frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,recordInputs:n,recordOutputs:r,resolveTraceContext:async t=>(await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId))?.context,stateStore:e.stateStore,resolveFallback:e=>{let t=a.get(e.scope.attemptId)??e.scope,n=o.get(t);return n===void 0?void 0:{context:n.context,spanContext:n.span.spanContext()}},tracer:e.tracer}),l=createAgentApprovalInstrumentation({actionContextFor:c.dispatchContextFor,frameworkVersion:e.frameworkVersion,idGenerator:e.idGenerator,tracer:e.tracer}),u=createAgentMemoryInstrumentation({...e,environment:t}),{prepareSessionTrace:d,prepareTurnTrace:f}=createAgentOtelSessionContext({...e,environment:t}),projectEvent=async i=>{let a=await e.stateStore.getSession(sessionIdForEvent(i)),o=audienceForEvent(i,a?.channelAudience),s=`traceSeed`in i?i.traceSeed:void 0,c=contextStorage.getStore()?.get(SessionTraceSeedKey),l=resolveForwardedTraceSeed(c),u=resolveForwardedTraceSeed(s,l?.forwardedTracePolicy),decisionForTrace=e=>e===void 0?void 0:resolveTracePolicyDecision(isSampledTrace(e),{audience:o,environment:t}),d=u?.decision??l?.decision??readInstrumentationDecision(a?.decision)??decisionForTrace(s)??decisionForTrace(c)??decisionForTrace(a?.context);if(d===void 0)return withoutInstrumentationContent(i);let f=u===void 0||!(`traceSeed`in i)||i.traceSeed===void 0?i:{...i,traceSeed:{...i.traceSeed,decision:u.decision,traceFlags:u.traceFlags}};return instrumentationEventForTraceDecision(f,applyLiveDeliveryAudienceCeiling(d.action===`drop`?d:{action:`record`,recordInputs:n&&d.recordInputs,recordOutputs:r&&d.recordOutputs},o,u?.forwardedTracePolicy??l?.forwardedTracePolicy,t),{audience:o,environment:t},{applyAudienceCeiling:!1})},onSessionStarted=async e=>{await d(e)},onTurnStarted=async e=>{await f(e)},onStepStarted=async t=>{let n=await e.stateStore.getTurn(t.scope.sessionId,t.scope.turnId);if(n===void 0||!isSampledTrace(n.context))return;let r=await e.stateStore.getSession(t.scope.sessionId),i=withChannelAudience(contextFromSpanContext(n.context),t.scope.channelAudience),s=trace.getSpan(context.active())?.spanContext(),c=e.idGenerator.withSpanId(e.idGenerator.deriveSpanId(attemptIdempotencyKey(t.scope)),()=>e.tracer.startSpan(AGENT_SPAN_NAMES.step,{attributes:runtimeAttributes.agentStepAttributes({event:t,frameworkVersion:e.frameworkVersion,session:r,turn:n}),links:s===void 0||s.traceId===n.context.traceId?void 0:[{attributes:{"eve.link.type":`workflow.delivery`},context:s}]},i));c.addEvent(`step.started`);let l=trace.setSpan(i,c);o.set(t.scope,{context:l,span:c}),a.set(t.scope.attemptId,t.scope)},onStepTerminal=async e=>{let t=a.get(e.scope.attemptId)??e.scope;i.delete(t),drainOpenSpans({...e,scope:t}),c.drain(e.scope.attemptId,e.type===`step.attempt.failed`?{error:e.error}:void 0),e.type===`step.attempt.failed`&&await c.failForAttempt(t,e.error),a.delete(e.scope.attemptId);let n=o.get(t);n!==void 0&&(n.span.addEvent(e.type===`step.attempt.completed`?`step.completed`:`step.failed`),e.type===`step.attempt.failed`&&recordAgentSpanError(n.span,e.error),n.span.end(),o.delete(t))},onTurnTerminal=async t=>{await e.stateStore.updateTurn(t.sessionId,t.turnId,e=>({...e,terminal:t.type===`turn.failed`?{error:t.error,type:t.type}:{type:t.type}}))},onSessionTransition=async t=>{if(t.type===`session.failed`&&t.turnId!==void 0&&await e.stateStore.updateTurn(t.sessionId,t.turnId,e=>({...e,terminal:e.terminal??{error:t.error,type:`turn.failed`}})),t.turnId!==void 0){let n=await e.stateStore.getTurn(t.sessionId,t.turnId);if(n!==void 0){let r=await e.stateStore.getSession(t.sessionId);if(isSampledTrace(n.context)){let i=r?.agentName??n.subagentName,a=withChannelAudience(n.caller===void 0||n.caller.isRemote===!0?ROOT_CONTEXT:contextFromSpanContext(n.caller),r?.channelAudience),startSpan=()=>e.tracer.startSpan(agentInvocationSpanName(i),{attributes:runtimeAttributes.agentActivationAttributes({agentName:i,frameworkVersion:e.frameworkVersion,session:r,sessionId:t.sessionId,turnId:t.turnId,turn:n}),kind:SpanKind.INTERNAL,links:agentActivationLinks(n),root:n.caller===void 0||n.caller.isRemote===!0,startTime:n.startTimeMs},a),o=e.idGenerator.withSpanId(n.context.spanId,()=>e.idGenerator.withTraceId(n.context.traceId,startSpan));setAgentInvocationUsage(o,n.modelUsage),o.addEvent(`turn.started`,void 0,n.startTimeMs),n.terminal!==void 0&&(o.setAttribute(`agent.turn.outcome`,n.terminal.type===`turn.completed`?`completed`:n.terminal.type===`turn.cancelled`?`cancelled`:`failed`),o.addEvent(n.terminal.type),n.terminal.type===`turn.failed`&&recordAgentSpanError(o,n.terminal.error)),o.end()}await e.stateStore.deleteTurn(t.sessionId,t.turnId)}}(t.type===`session.completed`||t.type===`session.failed`)&&(await c.deleteForSession(t.sessionId),await e.stateStore.deleteSession(t.sessionId))},onModelCallStarted=t=>{let r=o.get(t.scope);if(r===void 0)return;r.span.setAttribute(`agent.model.id`,t.model.modelId);let i=e.tracer.startSpan(modelSpanName(t.model.modelId),{attributes:{"gen_ai.agent.name":t.scope.functionId,"gen_ai.operation.name":`chat`,"gen_ai.provider.name":t.model.provider,"gen_ai.request.model":t.model.modelId,...agentSpanNamingAttributes(modelSpanName(t.model.modelId),`chat`),...agentTraceIdentityAttributes({rootSessionId:t.scope.rootSessionId??t.scope.sessionId,traceSessionId:traceSessionIdOf(t.scope),sessionId:t.scope.sessionId}),...runtimeAttributes.runtimeContextAttributes(t.runtimeContext)},kind:SpanKind.CLIENT},r.context),a;if(n&&t.input!==void 0){a=genAiInputMessagesAttribute(t.input.messages),a!==void 0&&i.setAttribute(`gen_ai.input.messages`,a);let e=genAiSystemInstructionsAttribute(t.input.instructions);e!==void 0&&i.setAttribute(`gen_ai.system_instructions`,e);let n=genAiToolDefinitionsAttribute(t.input.tools);n!==void 0&&i.setAttribute(`gen_ai.tool.definitions`,n)}let c={context:trace.setSpan(r.context,i),span:i};return getExecutionContexts(t.scope).set(t.idempotencyKey,c.context),getSpanStates(s,t.scope).set(t.idempotencyKey,c),rememberTurnInputMessages(e.stateStore,t.scope,a)},onModelCallTerminal=async t=>{i.get(t.scope)?.delete(t.idempotencyKey);let n=takeSpanState(s,t.scope,t.idempotencyKey);if(n!==void 0){if(t.type===`model.call.failed`)recordAgentSpanError(n.span,t.error);else{await recordTurnUsage(t),setGenAiUsage(n.span,t.usage),t.responseId!==void 0&&n.span.setAttribute(`gen_ai.response.id`,t.responseId),t.responseModelId!==void 0&&n.span.setAttribute(`gen_ai.response.model`,t.responseModelId),n.span.setAttribute(`gen_ai.response.finish_reasons`,[t.finishReason]);let i=o.get(t.scope);if(i!==void 0&&setAgentUsage(i.span,t.usage),r){n.span.setAttribute(`ai.response.finish_reason`,t.finishReason);let r=t.content;if(r===void 0){n.span.end();return}let i=genAiOutputMessagesAttribute(r,t.finishReason);i!==void 0&&(n.span.setAttribute(`gen_ai.output.messages`,i),await rememberTurnOutputMessages(e.stateStore,t.scope,i));let a=textContentAttribute(r.filter(e=>e.type===`reasoning`).map(e=>e.text).filter(e=>e.trim().length>0).join(`
2
- `));a!==void 0&&n.span.setAttribute(`ai.response.reasoning`,a);let o=textContentAttribute(r.filter(e=>e.type===`text`).map(e=>e.text).join(``));o!==void 0&&n.span.setAttribute(`ai.response.text`,o);let s=r.filter(e=>e.type===`tool-call`).map(e=>({callId:e.callId,input:e.input,toolName:e.toolName}));if(s.length>0){let e=contentAttribute(s);e!==void 0&&n.span.setAttribute(`ai.response.tool_calls`,e)}let c=r.filter(e=>e.type===`tool-result`||e.type===`tool-error`).map(e=>e.type===`tool-result`?{callId:e.callId,input:e.input,output:e.output,toolName:e.toolName}:{callId:e.callId,error:errorText(e.error),input:e.input,toolName:e.toolName});if(c.length>0){let e=toolResultsContentAttribute(c);e!==void 0&&n.span.setAttribute(`ai.response.tool_results`,e)}}}n.span.end()}},recordTurnUsage=async t=>{(t.usage.inputTokens!==void 0||t.usage.outputTokens!==void 0)&&await e.stateStore.updateTurn(t.scope.sessionId,t.scope.turnId,e=>({...e,modelUsage:{inputTokens:t.usage.inputTokens===void 0?e.modelUsage?.inputTokens:(e.modelUsage?.inputTokens??0)+t.usage.inputTokens,outputTokens:t.usage.outputTokens===void 0?e.modelUsage?.outputTokens:(e.modelUsage?.outputTokens??0)+t.usage.outputTokens}}))},p=createAgentChannelDeliveryInstrumentation({recordInputs:n,stateStore:e.stateStore}),onStepMetadata=e=>{let t=o.get(e.scope);if(t===void 0)return;let n=readGatewayCost(e.providerMetadata);if(n!==void 0)for(let[e,r]of Object.entries(n))t.span.setAttribute(e,r)};return{hook:{events:{...p,...l,...u.events,"step.attempt.completed":onStepTerminal,"step.attempt.failed":onStepTerminal,"step.attempt.metadata":onStepMetadata,"step.attempt.started":onStepStarted,"model.call.completed":onModelCallTerminal,"model.call.failed":onModelCallTerminal,"model.call.started":onModelCallStarted,"session.completed":onSessionTransition,"session.failed":onSessionTransition,"session.started":onSessionStarted,"session.waiting":onSessionTransition,...c.events,"turn.cancelled":onTurnTerminal,"turn.completed":onTurnTerminal,"turn.failed":onTurnTerminal,"turn.started":onTurnStarted},name:`eve.otel`,projectEvent,tracePolicy:()=>({emit:!0,recordInputs:n,recordOutputs:r})},prepareSessionTrace:d,prepareTurnTrace:f,async runInContext(o,s){if(o.type===`memory.operation`)return u.runInContext(o,s);let l=a.get(o.scope.attemptId)??o.scope,d=i.get(l),f=o.type===`model.call`?d?.get(o.idempotencyKey):c.contextFor(o.scope.attemptId,o.idempotencyKey);if(f===void 0){let t=await e.stateStore.getTurn(o.scope.sessionId,o.scope.turnId);t!==void 0&&(f=withChannelAudience(contextFromSpanContext(t.context),o.scope.channelAudience),isSampledTrace(t.context)||(f=suppressTracing(f)))}let p=await e.stateStore.getSession(o.scope.sessionId),m=resolveForwardedTraceSeed(contextStorage.getStore()?.get(SessionTraceSeedKey)),h=m?.decision??p?.decision,g=h===void 0?void 0:applyLiveDeliveryAudienceCeiling(h,normalizeChannelAudience(o.scope.channelAudience),m?.forwardedTracePolicy,t),_={recordInputs:n&&g?.action===`record`&&g.recordInputs,recordOutputs:r&&g?.action===`record`&&g.recordOutputs},run=e=>{let t=e??f;if(t===void 0)return s();let n=withErrorContent(t,_.recordOutputs),r=o.type===`tool.call`?withAgentToolContentPolicy(n,_):n;return context.with(markAgentTraceContext(withOperationConversation(r,o.scope)),s)};return o.type===`tool.call`?c.runInContext({...o,input:_.recordInputs?o.input:void 0},run,_.recordOutputs):run(void 0)}};function getExecutionContexts(e){let t=i.get(e);return t===void 0&&(t=new Map,i.set(e,t)),t}function drainOpenSpans(e){for(let t of s.get(e.scope)?.values()??[])e.type===`step.attempt.failed`&&recordAgentSpanError(t.span,e.error),t.span.end();s.delete(e.scope)}}function agentActivationLinks(e){let t=[];return e.caller?.isRemote===!0&&t.push({context:e.caller,attributes:{"eve.link.type":`agent.dispatch`}}),e.channelDelivery?.requestTraceContext!==void 0&&t.push({context:e.channelDelivery.requestTraceContext,attributes:{"eve.link.type":`channel.request`}}),t.length===0?void 0:t}function sessionIdForEvent(e){return`scope`in e?e.scope.sessionId:e.sessionId}function audienceForEvent(e,t){return`delivery`in e?normalizeChannelAudience(e.delivery.channelAudience):`scope`in e&&e.scope.channelAudience!==void 0?normalizeChannelAudience(e.scope.channelAudience):e.type===`session.started`?normalizeChannelAudience(e.channelAudience):normalizeChannelAudience(t)}function getSpanStates(e,t){let n=e.get(t);return n===void 0&&(n=new Map,e.set(t,n)),n}function takeSpanState(e,t,n){let r=e.get(t),i=r?.get(n);if(r!==void 0)return r.delete(n),r.size===0&&e.delete(t),i}function contextFromSpanContext(e){return trace.setSpan(ROOT_CONTEXT,trace.wrapSpanContext(e))}const errorText=e=>e instanceof Error?e.message:e;export{createAgentOtelInstrumentation};
@@ -1,36 +0,0 @@
1
- import type { AgentSessionTraceState, AgentTurnTraceState } from "#tracing/agent-trace-state.js";
2
- import type { InstrumentationStepAttemptStartedEvent } from "#instrumentation/lifecycle.js";
3
- type SpanAttributePrimitive = string | number | boolean;
4
- type SpanAttributeValue = SpanAttributePrimitive | SpanAttributePrimitive[];
5
- export declare function agentActivationAttributes(input: {
6
- readonly agentName?: string;
7
- readonly frameworkVersion: string;
8
- readonly session?: AgentSessionTraceState;
9
- readonly sessionId: string;
10
- readonly turnId: string;
11
- readonly turn: AgentTurnTraceState;
12
- }): Record<string, string | number | boolean | undefined>;
13
- export declare function agentChannelClassificationAttributes(session: AgentSessionTraceState | undefined, turn: AgentTurnTraceState, sessionId: string): {
14
- readonly "agent.channel.kind": string | undefined;
15
- readonly "agent.session.origin": string | undefined;
16
- };
17
- export declare function agentStepAttributes(input: {
18
- readonly event: InstrumentationStepAttemptStartedEvent;
19
- readonly frameworkVersion: string;
20
- readonly session?: AgentSessionTraceState;
21
- readonly turn: AgentTurnTraceState;
22
- }): {
23
- "agent.channel.kind"?: string | undefined;
24
- "agent.session.origin"?: string | undefined;
25
- "agent.framework.name": string;
26
- "agent.framework.version": string;
27
- "agent.step.attempt": number;
28
- "agent.step.index": number;
29
- "agent.turn.id": string;
30
- "agent.name": string | undefined;
31
- "gen_ai.operation.name": string;
32
- };
33
- export declare function agentPrincipalAttributes(turn: AgentTurnTraceState): Record<string, string>;
34
- /** Flattens merged runtime context into AI SDK-compatible span attributes. */
35
- export declare function runtimeContextAttributes(runtimeContext: Readonly<Record<string, unknown>> | undefined): Record<string, SpanAttributeValue>;
36
- export {};
@@ -1 +0,0 @@
1
- import{normalizeInstrumentationChannelKind}from"#internal/instrumentation.js";import{agentInvocationSpanName}from"#tracing/agent-span-contract.js";import{agentSpanNamingAttributes}from"#tracing/agent-span-naming.js";import{agentTraceIdentityAttributes,traceSessionIdOf}from"#tracing/agent-otel-attributes.js";function agentActivationAttributes(e){let t=e.session?.decision?.action===`record`,n=t&&e.session?.decision?.recordInputs===!0,r=t&&e.session?.decision?.recordOutputs===!0,i=e.turn.parentLineage??e.session?.parentLineage,a=i!==void 0,o=!a||e.turn.traceSessionId===e.sessionId,s=agentChannelClassificationAttributes(e.session,e.turn,e.sessionId),c=a?void 0:e.session?.scheduleId;return{"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.name":e.agentName,"agent.channel.audience":e.session?.channelAudience,...agentPrincipalAttributes(e.turn),"agent.channel.delivery.id":e.turn.channelDelivery?.deliveryId,"agent.channel.delivery.input":e.turn.channelDelivery?.inputAttribute,...s,"agent.channel.name":e.turn.channelDelivery?.channelName,"agent.channel.request.id":e.turn.channelDelivery?.requestId,"agent.parent_call.id":i?.callId,"agent.parent_run.id":i?.sessionId,"agent.run.type":a?`subagent`:`session`,"agent.schedule.id":c,"agent.session.title":o&&n?e.session?.title:void 0,"agent.subagent.name":e.turn.subagentName,"agent.trace.content.input":n,"agent.trace.content.output":r,"agent.turn.id":e.turnId,"agent.turn.sequence":e.turn.sequence,"gen_ai.agent.name":e.agentName,"gen_ai.input.messages":e.turn.inputMessagesAttribute,"gen_ai.operation.name":`invoke_agent`,"gen_ai.output.messages":e.turn.outputMessagesAttribute,...agentSpanNamingAttributes(agentInvocationSpanName(e.agentName),`invoke_agent`),...agentTraceIdentityAttributes({rootSessionId:e.turn.rootSessionId,traceSessionId:e.turn.traceSessionId,sessionId:e.sessionId})}}function agentChannelClassificationAttributes(e,t,n){let r=(t.parentLineage??e?.parentLineage)===void 0||t.traceSessionId===n,i=t.channelDelivery?.channelKind??(r?e?.channelKind??(e?.channelType===void 0?void 0:normalizeInstrumentationChannelKind(e.channelType)):void 0);return{"agent.channel.kind":i,"agent.session.origin":!r||i===void 0?void 0:e?.scheduleId===void 0?`channel`:`schedule`}}function agentStepAttributes(e){let{event:t,session:n,turn:r}=e,i=agentChannelClassificationAttributes(n,r,t.scope.sessionId);return{"agent.framework.name":`eve`,"agent.framework.version":e.frameworkVersion,"agent.step.attempt":t.scope.attemptIndex,"agent.step.index":t.scope.stepIndex,"agent.turn.id":t.scope.turnId,"agent.name":t.scope.functionId,...i[`agent.channel.kind`]===`unknown`?void 0:i,"gen_ai.operation.name":`workflow`,...agentSpanNamingAttributes(`agent.step`,`workflow`),...agentTraceIdentityAttributes({rootSessionId:t.scope.rootSessionId??t.scope.sessionId,traceSessionId:traceSessionIdOf(t.scope),sessionId:t.scope.sessionId}),...runtimeContextAttributes(t.runtimeContext)}}function agentPrincipalAttributes(e){let t={};return setOptionalAttribute(t,`agent.principal.current.id`,e.currentPrincipal?.id),setOptionalAttribute(t,`agent.principal.current.type`,e.currentPrincipal?.type),setOptionalAttribute(t,`agent.principal.initiator.id`,e.initiatorPrincipal?.id),setOptionalAttribute(t,`agent.principal.initiator.type`,e.initiatorPrincipal?.type),t}function runtimeContextAttributes(e){let t={};if(e===void 0)return t;for(let[n,r]of Object.entries(e))flattenContextAttribute(t,`ai.settings.context.${n}`,r);return t}function flattenContextAttribute(e,t,n){if(n!=null){if(typeof n==`string`||typeof n==`number`||typeof n==`boolean`){e[t]=n;return}if(Array.isArray(n)){let r=n.filter(e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`);if(r.length!==n.length||new Set(r.map(e=>typeof e)).size!==1)return;e[t]=r;return}if(typeof n==`object`)for(let[r,i]of Object.entries(n))flattenContextAttribute(e,`${t}.${r}`,i)}}function setOptionalAttribute(e,t,n){n!==void 0&&(e[t]=n)}export{agentActivationAttributes,agentChannelClassificationAttributes,agentPrincipalAttributes,agentStepAttributes,runtimeContextAttributes};
@@ -1,22 +0,0 @@
1
- import { type InstrumentationSessionStartedEvent, type InstrumentationTraceSeed, type InstrumentationTurnStartedEvent } from "#instrumentation/lifecycle.js";
2
- import type { AgentSpanIdGenerator } from "#tracing/agent-span-id-generator.js";
3
- import type { TraceCapturePolicy } from "#tracing/otel-declaration.js";
4
- import type { AgentSessionTraceState, AgentTraceStateStore } from "#tracing/agent-trace-state.js";
5
- import { type AgentSamplingOperation } from "#tracing/agent-span-contract.js";
6
- import type { ConversationEnvironment } from "#shared/conversation-context.js";
7
- interface AgentOtelSessionContextInput {
8
- readonly environment: ConversationEnvironment;
9
- readonly frameworkVersion: string;
10
- readonly idGenerator: AgentSpanIdGenerator;
11
- readonly samplesTrace?: (traceId: string, operation?: AgentSamplingOperation) => boolean;
12
- readonly stateStore: AgentTraceStateStore;
13
- readonly tracePolicy?: TraceCapturePolicy;
14
- }
15
- type SessionMetadata = Omit<InstrumentationSessionStartedEvent, "idempotencyKey" | "type">;
16
- interface AgentOtelSessionContext {
17
- readonly ensureSessionContext: (event: SessionMetadata) => Promise<AgentSessionTraceState>;
18
- readonly prepareSessionTrace: (event: InstrumentationSessionStartedEvent) => Promise<InstrumentationTraceSeed>;
19
- readonly prepareTurnTrace: (event: InstrumentationTurnStartedEvent) => Promise<InstrumentationTraceSeed>;
20
- }
21
- export declare function createAgentOtelSessionContext(input: AgentOtelSessionContextInput): AgentOtelSessionContext;
22
- export {};
@@ -1 +0,0 @@
1
- import{normalizeChannelAudience}from"#shared/channel-audience.js";import{normalizeInstrumentationChannelKind}from"#internal/instrumentation.js";import{agentInvocationSpanName}from"#tracing/agent-span-contract.js";import{isSampledTrace,resolveTracePolicy,resolveTracePolicyDecision}from"#tracing/sampled-trace.js";import"#instrumentation/lifecycle.js";import{readInstrumentationDecision}from"#shared/instrumentation-decision.js";import{applyPrincipalTraceDecision}from"#instrumentation/principal-summary.js";import{traceSessionIdOf}from"#tracing/agent-otel-attributes.js";import{agentActivationAttributes}from"#tracing/agent-otel-runtime-context.js";function createAgentOtelSessionContext(e){let ensureSessionContext=async t=>{let n=await e.stateStore.getSession(t.sessionId);if(n===void 0){let r=normalizeChannelAudience(t.channelAudience),i=resolveSessionTraceDecision(t,r,e.environment,e.tracePolicy);n={agentName:t.agentName,channelAudience:r,channelKind:t.channelKind,channelType:t.channelType,decision:i,context:initialSessionContext(e,t,i),parentLineage:t.parentLineage,rootSessionId:t.rootSessionId,traceSessionId:traceSessionIdOf(t),scheduleId:t.scheduleId,title:t.title},await e.stateStore.setSession(t.sessionId,n)}return n};return{ensureSessionContext,prepareSessionTrace:async e=>{let t=await ensureSessionContext(e);return portableSpanContext(t.context,t.decision)},prepareTurnTrace:async t=>{let n=await e.stateStore.getTurn(t.sessionId,t.turnId);if(n!==void 0){let r=await e.stateStore.getSession(t.sessionId);return portableSpanContext(n.context,r?.decision)}let r=await ensureSessionContext(t),i=t.sequence===0,a=i?t.parentTraceContext:void 0,o=i?{...r.context,isRemote:!1}:freshTurnContext(e,t.idempotencyKey,r.decision);a!==void 0&&!(`isRemote`in a&&a.isRemote===!0)&&(o={...o,traceId:a.traceId});let s={caller:a===void 0?void 0:adoptedSpanContext(a),context:o,currentPrincipal:applyPrincipalTraceDecision(t.currentPrincipal,r.decision),initiatorPrincipal:applyPrincipalTraceDecision(t.initiatorPrincipal,r.decision),parentLineage:t.parentLineage??r.parentLineage,rootSessionId:t.rootSessionId,traceSessionId:traceSessionIdOf(t),sequence:t.sequence,startTimeMs:Date.now(),subagentName:(t.parentLineage??r.parentLineage)?.subagentName};if(isSampledTrace(s.context)&&(a===void 0||`isRemote`in a&&a.isRemote===!0)){let n=r.agentName??s.subagentName,i=e.samplesTrace?.(s.context.traceId,{name:agentInvocationSpanName(n),attributes:agentActivationAttributes({agentName:n,frameworkVersion:e.frameworkVersion,session:r,sessionId:t.sessionId,turnId:t.turnId,turn:s})})??!0;o={...o,traceFlags:+!!i}}return await e.stateStore.setTurn(t.sessionId,t.turnId,{...s,context:o}),portableSpanContext(o,r.decision)}}}function portableSpanContext(e,t){return{decision:t,spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function adoptedSpanContext(e){return{isRemote:`isRemote`in e&&e.isRemote===!0,spanId:e.spanId,traceFlags:e.traceFlags,traceId:e.traceId}}function initialSessionContext(e,t,n){let r=t.traceSeed;if(r!==void 0)return{...adoptedSpanContext(r),traceFlags:n.action===`drop`?0:r.traceFlags};let i=(t.parentTraceContext!==void 0&&`isRemote`in t.parentTraceContext&&t.parentTraceContext.isRemote===!0?void 0:t.parentTraceContext?.traceId)??e.idGenerator.deriveTraceId(`session:${t.sessionId}`),a=n.action===`record`;return{isRemote:!1,spanId:e.idGenerator.deriveSpanId(`session:${t.sessionId}`),traceFlags:+!!a,traceId:i}}function freshTurnContext(e,t,n){let r=e.idGenerator.deriveTraceId(`turn:${t}`),i=n?.action===`record`;return{isRemote:!1,spanId:e.idGenerator.deriveSpanId(`turn:${t}`),traceFlags:+!!i,traceId:r}}function resolveSessionTraceDecision(e,t,n,r){let i={audience:t,environment:n};return e.parentTraceContext!==void 0&&!isSampledTrace(e.parentTraceContext)?{action:`drop`}:e.traceSeed?.decision===void 0?e.traceSeed===void 0?e.parentTraceContext===void 0?e.agentName===void 0?r===void 0?resolveTracePolicyDecision(!0,i):{action:`drop`}:resolveTracePolicy(r,{agentName:e.agentName,audience:t,channel:{kind:normalizeInstrumentationChannelKind(e.channelKind??e.channelType)},environment:n,principalType:`unknown`}):resolveTracePolicyDecision(isSampledTrace(e.parentTraceContext),i):resolveTracePolicyDecision(isSampledTrace(e.traceSeed),i):readInstrumentationDecision(e.traceSeed.decision)??{action:`drop`}}export{createAgentOtelSessionContext};
@@ -1,6 +0,0 @@
1
- import type { InstrumentationAttemptScope } from "#instrumentation/lifecycle.js";
2
- import type { AgentTraceStateStore } from "#tracing/agent-trace-state.js";
3
- /** Keeps the first model input so the turn-level invoke_agent span represents its task. */
4
- export declare function rememberTurnInputMessages(store: AgentTraceStateStore, scope: InstrumentationAttemptScope, inputMessagesAttribute: string | undefined): void | PromiseLike<void>;
5
- /** Keeps the latest model output so the completed invoke_agent span represents its result. */
6
- export declare function rememberTurnOutputMessages(store: AgentTraceStateStore, scope: InstrumentationAttemptScope, outputMessagesAttribute: string | undefined): void | PromiseLike<void>;
@@ -1 +0,0 @@
1
- function rememberTurnInputMessages(e,t,n){if(n!==void 0)return e.updateTurn(t.sessionId,t.turnId,e=>({...e,inputMessagesAttribute:e.inputMessagesAttribute??n}))}function rememberTurnOutputMessages(e,t,n){if(n!==void 0)return e.updateTurn(t.sessionId,t.turnId,e=>({...e,outputMessagesAttribute:n}))}export{rememberTurnInputMessages,rememberTurnOutputMessages};
@@ -1,10 +0,0 @@
1
- import type { Span } from "#compiled/@opentelemetry/api/index.js";
2
- import type { InstrumentationUsage } from "#instrumentation/lifecycle.js";
3
- import type { AgentTurnTraceState } from "#tracing/agent-trace-state.js";
4
- /** Applies eve's structural token usage attributes to an agent span. */
5
- export declare function setAgentUsage(span: Span, usage: InstrumentationUsage): void;
6
- /** Applies standard GenAI token usage and retains eve's cost attribute. */
7
- export declare function setGenAiUsage(span: Span, usage: InstrumentationUsage): void;
8
- export declare function setAgentInvocationUsage(span: Span, modelUsage: AgentTurnTraceState["modelUsage"]): void;
9
- /** Projects Vercel AI Gateway cost metadata onto GenAI span attributes. */
10
- export declare function readGatewayCost(providerMetadata: Readonly<Record<string, unknown>>): Record<string, string | number> | undefined;
@@ -1 +0,0 @@
1
- import{AGENT_USAGE_ATTRIBUTES}from"#tracing/agent-span-contract.js";function setAgentUsage(e,t){t.costUsd!==void 0&&e.setAttribute(AGENT_USAGE_ATTRIBUTES.costUsd,t.costUsd),t.inputTokens!==void 0&&e.setAttribute(AGENT_USAGE_ATTRIBUTES.inputTokens,t.inputTokens),t.outputTokens!==void 0&&e.setAttribute(AGENT_USAGE_ATTRIBUTES.outputTokens,t.outputTokens);let n=t.inputTokenDetails;n?.cacheReadTokens!==void 0&&e.setAttribute(AGENT_USAGE_ATTRIBUTES.cacheReadTokens,n.cacheReadTokens),n?.cacheWriteTokens!==void 0&&e.setAttribute(AGENT_USAGE_ATTRIBUTES.cacheWriteTokens,n.cacheWriteTokens)}function setGenAiUsage(e,t){t.costUsd!==void 0&&e.setAttribute(AGENT_USAGE_ATTRIBUTES.costUsd,t.costUsd),t.inputTokens!==void 0&&e.setAttribute(`gen_ai.usage.input_tokens`,t.inputTokens),t.outputTokens!==void 0&&e.setAttribute(`gen_ai.usage.output_tokens`,t.outputTokens);let n=t.inputTokenDetails;n?.cacheReadTokens!==void 0&&e.setAttribute(`gen_ai.usage.cache_read.input_tokens`,n.cacheReadTokens),n?.cacheWriteTokens!==void 0&&e.setAttribute(`gen_ai.usage.cache_write.input_tokens`,n.cacheWriteTokens)}function setAgentInvocationUsage(e,t){t!==void 0&&setGenAiUsage(e,t)}function readGatewayCost(e){let t=e.gateway;if(!isRecord(t))return;let n={},r=readUsd(t.cost);r!==void 0&&(n[`gen_ai.usage.cost`]=r);let i=readUsd(t.gatewayCost);i!==void 0&&(n[`gen_ai.usage.gateway_cost`]=i);let a=readUsd(t.inputInferenceCost);a!==void 0&&(n[`gen_ai.usage.input_cost`]=a);let o=readUsd(t.outputInferenceCost);return o!==void 0&&(n[`gen_ai.usage.output_cost`]=o),typeof t.generationId==`string`&&t.generationId.length>0&&(n[`gen_ai.generation.id`]=t.generationId),Object.keys(n).length===0?void 0:n}function readUsd(e){if(typeof e!=`string`)return;let t=Number(e);return Number.isFinite(t)?t:void 0}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{readGatewayCost,setAgentInvocationUsage,setAgentUsage,setGenAiUsage};