@tangle-network/agent-eval 0.117.1 → 0.118.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 (143) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/analyst/index.d.ts +2772 -21
  3. package/dist/analyst/index.js +7 -6
  4. package/dist/analyst/index.js.map +1 -1
  5. package/dist/belief-state/index.d.ts +706 -10
  6. package/dist/belief-state/index.js +2 -1
  7. package/dist/belief-state/index.js.map +1 -1
  8. package/dist/benchmarks/index.d.ts +958 -14
  9. package/dist/benchmarks/index.js +12 -10
  10. package/dist/builder-eval/index.d.ts +449 -4
  11. package/dist/builder-eval/index.js +4 -3
  12. package/dist/builder-eval/index.js.map +1 -1
  13. package/dist/campaign/index.d.ts +4275 -73
  14. package/dist/campaign/index.js +12 -10
  15. package/dist/{chunk-VF3XSYTI.js → chunk-33JA4TFA.js} +6 -6
  16. package/dist/{chunk-4JLWXDYA.js → chunk-3EHHMC6E.js} +2 -2
  17. package/dist/{chunk-CCZIVI3F.js → chunk-BFW56GTT.js} +2 -2
  18. package/dist/{chunk-YZPO4UHR.js → chunk-DP3BBMYJ.js} +100 -143
  19. package/dist/chunk-DP3BBMYJ.js.map +1 -0
  20. package/dist/{chunk-E4BUPP7Z.js → chunk-HKUCJ437.js} +38 -66
  21. package/dist/chunk-HKUCJ437.js.map +1 -0
  22. package/dist/{chunk-HZHNRYHK.js → chunk-K6N6XJJX.js} +2 -2
  23. package/dist/chunk-KSDQVPLR.js +286 -0
  24. package/dist/chunk-KSDQVPLR.js.map +1 -0
  25. package/dist/chunk-MA6HLL3S.js +65 -0
  26. package/dist/chunk-MA6HLL3S.js.map +1 -0
  27. package/dist/{chunk-MGEHEHSN.js → chunk-OIIMMLRB.js} +11 -11
  28. package/dist/{chunk-DXZRATT5.js → chunk-OYZAPX5G.js} +3 -3
  29. package/dist/chunk-PXE2VKMX.js +140 -0
  30. package/dist/chunk-PXE2VKMX.js.map +1 -0
  31. package/dist/{chunk-JSJZ4PJ6.js → chunk-Q442S5AS.js} +17 -17
  32. package/dist/{chunk-ODVOOEWQ.js → chunk-QBRSJK47.js} +2 -2
  33. package/dist/{chunk-S2F4J57L.js → chunk-QKEGNI5B.js} +77 -32
  34. package/dist/chunk-QKEGNI5B.js.map +1 -0
  35. package/dist/{chunk-5UF54T55.js → chunk-S3UZOQ5Y.js} +34 -7
  36. package/dist/chunk-S3UZOQ5Y.js.map +1 -0
  37. package/dist/{chunk-FQNLDL4D.js → chunk-SVH2ANFD.js} +136 -4
  38. package/dist/chunk-SVH2ANFD.js.map +1 -0
  39. package/dist/{chunk-GQCZRZ7L.js → chunk-U5CHZ5M3.js} +9 -9
  40. package/dist/{chunk-TVVP3ZZQ.js → chunk-VQMK5FMP.js} +2 -1
  41. package/dist/{chunk-TVVP3ZZQ.js.map → chunk-VQMK5FMP.js.map} +1 -1
  42. package/dist/chunk-WDHBCA3M.js +31 -0
  43. package/dist/chunk-WDHBCA3M.js.map +1 -0
  44. package/dist/{chunk-HQPHZGL6.js → chunk-YLMUS4MM.js} +9 -9
  45. package/dist/{chunk-LQUTGLOZ.js → chunk-ZET2UAYW.js} +15 -65
  46. package/dist/chunk-ZET2UAYW.js.map +1 -0
  47. package/dist/contract/index.d.ts +4012 -38
  48. package/dist/contract/index.js +56 -29
  49. package/dist/contract/index.js.map +1 -1
  50. package/dist/control.d.ts +1013 -9
  51. package/dist/control.js +4 -3
  52. package/dist/fuzz.d.ts +194 -4
  53. package/dist/fuzz.js +3 -3
  54. package/dist/hosted/index.d.ts +498 -17
  55. package/dist/index.d.ts +10982 -1286
  56. package/dist/index.js +97 -80
  57. package/dist/index.js.map +1 -1
  58. package/dist/matrix/index.d.ts +139 -4
  59. package/dist/meta-eval/index.d.ts +862 -15
  60. package/dist/meta-eval/index.js +2 -1
  61. package/dist/meta-eval/index.js.map +1 -1
  62. package/dist/multishot/index.d.ts +214 -14
  63. package/dist/openapi.json +1 -1
  64. package/dist/pipelines/index.d.ts +392 -7
  65. package/dist/pipelines/index.js +5 -3
  66. package/dist/pipelines/index.js.map +1 -1
  67. package/dist/reporting.d.ts +1277 -17
  68. package/dist/rl.d.ts +2359 -28
  69. package/dist/rl.js +6 -5
  70. package/dist/rl.js.map +1 -1
  71. package/dist/storyboard/index.d.ts +86 -1
  72. package/dist/trace-attributes.d.ts +16 -0
  73. package/dist/trace-attributes.js +32 -0
  74. package/dist/trace-attributes.js.map +1 -0
  75. package/dist/traces.d.ts +1970 -697
  76. package/dist/traces.js +49 -32
  77. package/dist/wire/index.d.ts +655 -9
  78. package/docs/insight-report.md +44 -0
  79. package/package.json +9 -3
  80. package/dist/adversarial-B7loGVVX.d.ts +0 -19
  81. package/dist/analyst-C8HHvfJp.d.ts +0 -88
  82. package/dist/analyze-runs--2x39HZ7.d.ts +0 -81
  83. package/dist/baseline-DKq3gJpP.d.ts +0 -141
  84. package/dist/calibration-C8MTS7cw.d.ts +0 -101
  85. package/dist/chunk-5UF54T55.js.map +0 -1
  86. package/dist/chunk-E4BUPP7Z.js.map +0 -1
  87. package/dist/chunk-FQNLDL4D.js.map +0 -1
  88. package/dist/chunk-LQUTGLOZ.js.map +0 -1
  89. package/dist/chunk-S2F4J57L.js.map +0 -1
  90. package/dist/chunk-YZPO4UHR.js.map +0 -1
  91. package/dist/code-agent-session-CjZsVd19.d.ts +0 -87
  92. package/dist/control-6vuGfmDH.d.ts +0 -258
  93. package/dist/cost-ledger-DWy3XdJc.d.ts +0 -183
  94. package/dist/dataset-NENEzRgk.d.ts +0 -115
  95. package/dist/default-registry-DaK8b3fv.d.ts +0 -155
  96. package/dist/emitter-CjD7vUwv.d.ts +0 -122
  97. package/dist/errors-oeQrLqXC.d.ts +0 -74
  98. package/dist/failure-cluster-DOAcSJ87.d.ts +0 -76
  99. package/dist/feedback-trajectory-BUnM58xL.d.ts +0 -348
  100. package/dist/gepa-eESocoDi.d.ts +0 -642
  101. package/dist/index-PdX4VnPA.d.ts +0 -423
  102. package/dist/insight-report-DY4nDW9Q.d.ts +0 -310
  103. package/dist/integrity-DqlBiLyK.d.ts +0 -81
  104. package/dist/judge-calibration-7C-IDmKr.d.ts +0 -145
  105. package/dist/kind-factory-ClZmO25A.d.ts +0 -171
  106. package/dist/llm-client-qoDd18Qz.d.ts +0 -289
  107. package/dist/multi-layer-verifier-BsqKuLyN.d.ts +0 -150
  108. package/dist/off-policy-DiwuKKg7.d.ts +0 -132
  109. package/dist/outcome-store-rnXLEqSn.d.ts +0 -63
  110. package/dist/policy-edit-wG9uFEFm.d.ts +0 -455
  111. package/dist/pre-registration-BWQhJ3vz.d.ts +0 -761
  112. package/dist/provenance-DpjwyseI.d.ts +0 -541
  113. package/dist/query-CF7PG61p.d.ts +0 -35
  114. package/dist/raw-provider-sink-C46HDghv.d.ts +0 -132
  115. package/dist/release-report-C8G2i5Xi.d.ts +0 -236
  116. package/dist/researcher-C8XyxQsu.d.ts +0 -387
  117. package/dist/rubric-predictive-validity-p49lLVrE.d.ts +0 -105
  118. package/dist/run-record-BDH49H2E.d.ts +0 -360
  119. package/dist/runtime-trajectory-DGBIUt4B.d.ts +0 -49
  120. package/dist/schema-B3Q3l9Z_.d.ts +0 -201
  121. package/dist/semantic-concept-judge-CXnPEJbf.d.ts +0 -723
  122. package/dist/sequential-5iSVfzl2.d.ts +0 -139
  123. package/dist/series-convergence-D5OWMBg6.d.ts +0 -33
  124. package/dist/statistics-KUnG73jH.d.ts +0 -494
  125. package/dist/storage-DrX3v_5B.d.ts +0 -50
  126. package/dist/store-C1YxJDEK.d.ts +0 -248
  127. package/dist/store-DGqD0Pyo.d.ts +0 -116
  128. package/dist/summary-report-C5bKFfm-.d.ts +0 -445
  129. package/dist/test-graded-scenario-B0ybnPY7.d.ts +0 -166
  130. package/dist/types-BSw1rOUB.d.ts +0 -634
  131. package/dist/types-BUxNaJ8c.d.ts +0 -108
  132. package/dist/types-BkfcQnxV.d.ts +0 -313
  133. package/dist/verdict-C9MlYujm.d.ts +0 -35
  134. /package/dist/{chunk-VF3XSYTI.js.map → chunk-33JA4TFA.js.map} +0 -0
  135. /package/dist/{chunk-4JLWXDYA.js.map → chunk-3EHHMC6E.js.map} +0 -0
  136. /package/dist/{chunk-CCZIVI3F.js.map → chunk-BFW56GTT.js.map} +0 -0
  137. /package/dist/{chunk-HZHNRYHK.js.map → chunk-K6N6XJJX.js.map} +0 -0
  138. /package/dist/{chunk-MGEHEHSN.js.map → chunk-OIIMMLRB.js.map} +0 -0
  139. /package/dist/{chunk-DXZRATT5.js.map → chunk-OYZAPX5G.js.map} +0 -0
  140. /package/dist/{chunk-JSJZ4PJ6.js.map → chunk-Q442S5AS.js.map} +0 -0
  141. /package/dist/{chunk-ODVOOEWQ.js.map → chunk-QBRSJK47.js.map} +0 -0
  142. /package/dist/{chunk-GQCZRZ7L.js.map → chunk-U5CHZ5M3.js.map} +0 -0
  143. /package/dist/{chunk-HQPHZGL6.js.map → chunk-YLMUS4MM.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/trace/otlp-attributes.ts","../src/trace-analyst/otlp-span.ts","../src/trace-analyst/types.ts","../src/trace-analyst/store-otlp.ts","../src/trace-analyst/store.ts","../src/trace-analyst/tools.ts"],"sourcesContent":["/** Canonical OpenInference-over-OTLP attribute vocabulary used at the trace boundary. */\n\nimport type { ToolSpan } from './schema'\n\nexport const OPENINFERENCE_SPAN_KIND = 'openinference.span.kind'\nexport const LLM_MODEL_NAME = 'llm.model_name'\nexport const LLM_INPUT_TOKENS = 'llm.token_count.prompt'\nexport const LLM_OUTPUT_TOKENS = 'llm.token_count.completion'\nexport const LLM_CACHED_TOKENS = 'llm.token_count.prompt_cache_hit'\nexport const LLM_COST_USD = 'llm.cost_usd'\nexport const TOOL_NAME = 'tool.name'\nexport const TOOL_ARGS_CAPTURED = 'tool.args_captured'\nexport const TOOL_LATENCY_MS = 'tool.latency_ms'\nexport const INPUT_VALUE = 'input.value'\nexport const OUTPUT_VALUE = 'output.value'\n\nconst TOOL_SPAN_ATTRIBUTE_KEYS = [\n TOOL_NAME,\n TOOL_ARGS_CAPTURED,\n TOOL_LATENCY_MS,\n INPUT_VALUE,\n OUTPUT_VALUE,\n] as const\n\nexport const SPAN_KIND_ATTR_KEYS = [OPENINFERENCE_SPAN_KIND, 'inference.observation_kind'] as const\n\nexport const LLM_MODEL_ATTR_KEYS = [\n LLM_MODEL_NAME,\n 'inference.llm.model_name',\n 'llm.model',\n 'gen_ai.request.model',\n 'gen_ai.response.model',\n] as const\n\nexport const LLM_INPUT_TOKEN_ATTR_KEYS = [\n LLM_INPUT_TOKENS,\n 'inference.llm.input_tokens',\n 'llm.input_tokens',\n 'gen_ai.usage.input_tokens',\n 'gen_ai.usage.prompt_tokens',\n] as const\n\nexport const LLM_OUTPUT_TOKEN_ATTR_KEYS = [\n LLM_OUTPUT_TOKENS,\n 'inference.llm.output_tokens',\n 'llm.output_tokens',\n 'gen_ai.usage.output_tokens',\n 'gen_ai.usage.completion_tokens',\n] as const\n\nexport const LLM_CACHED_TOKEN_ATTR_KEYS = [\n LLM_CACHED_TOKENS,\n 'inference.llm.cached_tokens',\n 'llm.cached_tokens',\n 'gen_ai.usage.cached_tokens',\n] as const\n\nexport const LLM_COST_ATTR_KEYS = [\n LLM_COST_USD,\n 'inference.llm.cost.total',\n 'llm.cost.total',\n 'gen_ai.usage.cost',\n] as const\n\nexport const TOOL_NAME_ATTR_KEYS = [TOOL_NAME, 'inference.tool.name'] as const\n\nexport type ToolSpanOtlpInput = Pick<\n ToolSpan,\n 'toolName' | 'args' | 'argsCaptured' | 'result' | 'latencyMs'\n>\n\nfunction toolSpanOtlpAttributes(\n span: ToolSpanOtlpInput,\n): Record<string, string | number | boolean> {\n const argsCaptured = span.argsCaptured !== false\n const attributes: Record<string, string | number | boolean> = {\n [TOOL_NAME]: span.toolName,\n [TOOL_ARGS_CAPTURED]: argsCaptured,\n }\n if (span.latencyMs !== undefined) attributes[TOOL_LATENCY_MS] = span.latencyMs\n if (argsCaptured) attributes[INPUT_VALUE] = stringifyTraceValue(span.args)\n if (span.result !== undefined) attributes[OUTPUT_VALUE] = stringifyTraceValue(span.result)\n return attributes\n}\n\nexport function applyToolSpanOtlpAttributes(\n attributes: Record<string, unknown>,\n span: ToolSpanOtlpInput,\n): void {\n for (const key of TOOL_SPAN_ATTRIBUTE_KEYS) delete attributes[key]\n Object.assign(attributes, toolSpanOtlpAttributes(span))\n}\n\nexport function traceSpanKindToOpenInferenceKind(kind: string): string {\n switch (kind) {\n case 'llm':\n return 'LLM'\n case 'tool':\n return 'TOOL'\n case 'retrieval':\n return 'CHAIN'\n case 'judge':\n return 'GUARDRAIL'\n case 'sandbox':\n return 'CHAIN'\n case 'agent':\n return 'AGENT'\n default:\n return 'SPAN'\n }\n}\n\nfunction stringifyTraceValue(value: unknown): string {\n if (value === undefined) return 'null'\n if (typeof value === 'string') return value\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n","/**\n * Canonical OTLP-flat-line readers shared by every consumer of the\n * OTLP-JSONL wire shape (one OTLP span per line; the form\n * `flattenOtlpExportToNdjson` produces and the form AppWorld / HALO\n * emit via their OpenInference OTLP exporter).\n *\n * `OtlpFileTraceStore` indexes spans with these; `otlpToRunRecords`\n * aggregates spans into `RunRecord`s with the same readers. One parser,\n * one vocabulary — a divergence between the analyst's view of a trace and\n * the RunRecord projected from it is a class of bug this consolidation\n * removes by construction.\n *\n * Vocabulary. The readers understand BOTH dialects that appear in the\n * wild:\n * - the substrate's own `llm.*` / `tool.*` / `span.kind` attributes\n * (`flattenSpanAttributes` in `trace/otel.ts`), and\n * - the OpenInference / inference-export attributes AppWorld / HALO\n * emit (`openinference.span.kind`, `inference.observation_kind`,\n * `inference.llm.input_tokens`, `llm.token_count.prompt`, …).\n *\n * Pure, no I/O.\n */\n\nimport {\n LLM_MODEL_ATTR_KEYS,\n SPAN_KIND_ATTR_KEYS,\n TOOL_NAME_ATTR_KEYS,\n} from '../trace/otlp-attributes'\nimport type { TraceAnalystSpanKind, TraceAnalystSpanStatus } from './types'\n\n/**\n * The structural fields a flat OTLP-JSONL line projects to. `attributes`\n * is the merged resource+span attribute map (span overrides resource);\n * the named fields are the pivots every reader of a trace needs without\n * paying the full attribute materialisation.\n */\nexport interface ProjectedOtlpSpan {\n trace_id: string\n span_id: string\n parent_span_id: string | null\n name: string\n kind: TraceAnalystSpanKind\n start_time: string\n end_time: string\n duration_ms: number\n status: TraceAnalystSpanStatus\n status_message: string | undefined\n service_name: string | null\n agent_name: string | null\n model_name: string | null\n tool_name: string | null\n /** Merged resource + span attributes, span winning on overlap. */\n attributes: Record<string, unknown>\n}\n\n/**\n * Project one parsed OTLP-JSONL object to `ProjectedOtlpSpan`, or `null`\n * when the line is missing the mandatory `trace_id` + `span_id`.\n */\nexport function projectOtlpFlatLine(raw: Record<string, unknown>): ProjectedOtlpSpan | null {\n const trace_id = stringField(raw, 'trace_id') ?? stringField(raw, 'traceId')\n const span_id = stringField(raw, 'span_id') ?? stringField(raw, 'spanId')\n if (!trace_id || !span_id) return null\n\n const parent_id = stringField(raw, 'parent_span_id') ?? stringField(raw, 'parentSpanId') ?? null\n const name = stringField(raw, 'name') ?? 'unknown'\n const start_time = stringField(raw, 'start_time') ?? stringField(raw, 'startTime') ?? ''\n const end_time = stringField(raw, 'end_time') ?? stringField(raw, 'endTime') ?? start_time\n\n const status = readOtlpStatus(raw)\n const attributes = extractOtlpAttributes(raw)\n\n const service_name =\n asString(attributes['service.name']) ??\n asString(attributes['resource.attributes.service.name']) ??\n null\n const agent_name =\n asString(attributes['agent.name']) ??\n asString(attributes['inference.agent.name']) ??\n asString(attributes['inference.agent_name']) ??\n null\n const model_name = firstStringAttr(attributes, LLM_MODEL_ATTR_KEYS)\n const tool_name = firstStringAttr(attributes, TOOL_NAME_ATTR_KEYS)\n\n const kind = inferOtlpKind(attributes)\n\n let duration_ms = 0\n if (start_time && end_time) {\n const a = spanEpochMillis(start_time)\n const b = spanEpochMillis(end_time)\n if (a !== null && b !== null) duration_ms = Math.max(0, b - a)\n }\n\n return {\n trace_id,\n span_id,\n parent_span_id: parent_id && parent_id.length > 0 ? parent_id : null,\n name,\n kind,\n start_time,\n end_time,\n duration_ms,\n status: status.code,\n status_message: status.message,\n service_name,\n agent_name,\n model_name,\n tool_name,\n attributes,\n }\n}\n\nexport function readOtlpStatus(raw: Record<string, unknown>): {\n code: TraceAnalystSpanStatus\n message: string | undefined\n} {\n const status = raw.status\n if (status && typeof status === 'object' && !Array.isArray(status)) {\n const codeRaw = (status as Record<string, unknown>).code\n const code: TraceAnalystSpanStatus =\n codeRaw === 'STATUS_CODE_OK' || codeRaw === 'OK'\n ? 'OK'\n : codeRaw === 'STATUS_CODE_ERROR' || codeRaw === 'ERROR'\n ? 'ERROR'\n : 'UNSET'\n const messageRaw = (status as Record<string, unknown>).message\n const message = typeof messageRaw === 'string' && messageRaw.length > 0 ? messageRaw : undefined\n return { code, message }\n }\n return { code: 'UNSET', message: undefined }\n}\n\nexport function inferOtlpKind(attrs: Record<string, unknown>): TraceAnalystSpanKind {\n const opik = firstStringAttr(attrs, SPAN_KIND_ATTR_KEYS)\n if (opik) {\n const upper = opik.toUpperCase()\n if (\n upper === 'AGENT' ||\n upper === 'LLM' ||\n upper === 'TOOL' ||\n upper === 'CHAIN' ||\n upper === 'GUARDRAIL' ||\n upper === 'SPAN'\n ) {\n return upper as TraceAnalystSpanKind\n }\n }\n return 'UNKNOWN'\n}\n\n/**\n * Flatten OTLP `attributes` + `resource.attributes` into a single\n * dotted-key map. Span attributes override resource attributes when keys\n * overlap. Nested objects/arrays are preserved as-is.\n */\nexport function extractOtlpAttributes(raw: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n const resource = raw.resource\n if (resource && typeof resource === 'object' && !Array.isArray(resource)) {\n const ra = (resource as Record<string, unknown>).attributes\n if (ra && typeof ra === 'object' && !Array.isArray(ra)) {\n for (const [k, v] of Object.entries(ra as Record<string, unknown>)) {\n out[k] = v\n }\n }\n }\n const spanAttrs = raw.attributes\n if (spanAttrs && typeof spanAttrs === 'object' && !Array.isArray(spanAttrs)) {\n for (const [k, v] of Object.entries(spanAttrs as Record<string, unknown>)) {\n out[k] = v\n }\n }\n return out\n}\n\nexport function stringField(raw: Record<string, unknown>, key: string): string | undefined {\n const v = raw[key]\n return typeof v === 'string' ? v : undefined\n}\n\nexport function asString(v: unknown): string | null {\n return typeof v === 'string' && v.length > 0 ? v : null\n}\n\n/** Read a numeric attribute, tolerating numeric strings; `null` if absent/NaN. */\nexport function asNumber(v: unknown): number | null {\n if (typeof v === 'number') return Number.isFinite(v) ? v : null\n if (typeof v === 'string' && v.length > 0) {\n const n = Number(v)\n return Number.isFinite(n) ? n : null\n }\n return null\n}\n\n/** First finite numeric value across a list of candidate attribute keys. */\nexport function firstNumberAttr(\n attrs: Record<string, unknown>,\n keys: readonly string[],\n): number | null {\n for (const k of keys) {\n const n = asNumber(attrs[k])\n if (n !== null) return n\n }\n return null\n}\n\n/** First non-empty string value across a list of candidate attribute keys. */\nexport function firstStringAttr(\n attrs: Record<string, unknown>,\n keys: readonly string[],\n): string | null {\n for (const k of keys) {\n const s = asString(attrs[k])\n if (s !== null) return s\n }\n return null\n}\n\n/**\n * Parse a span timestamp to epoch millis, or null when empty/unparseable. The\n * OTLP readers accept BOTH ISO-8601 and epoch-millis-string dialects, so raw\n * string comparison (`<`, `localeCompare`) mis-orders across dialects and\n * `Date.parse` returns NaN for a bare epoch-millis string.\n */\nexport function spanEpochMillis(ts: string | undefined | null): number | null {\n if (!ts) return null\n if (/^\\d+$/.test(ts)) return Number(ts)\n const n = Date.parse(ts)\n return Number.isNaN(n) ? null : n\n}\n\n/**\n * Order comparator for span timestamps across mixed ISO/epoch dialects.\n * Unparseable timestamps sort as epoch 0 (earliest), never NaN (which would\n * make the sort non-deterministic).\n */\nexport function compareSpanTime(a: string, b: string): number {\n return (spanEpochMillis(a) ?? 0) - (spanEpochMillis(b) ?? 0)\n}\n","/**\n * Shared types for the trace-analyst module.\n *\n * Wire format. The store interface speaks `OtlpSpanLike` rows — one JSONL\n * line per span, OTLP-shaped. We do NOT depend on a specific tracing\n * vendor at the type level. Adapter\n * layers map upstream shapes onto this interface.\n *\n * Design constraint. Every read operation that can return arbitrary\n * payload must carry a byte budget so the agent's tool result stays\n * bounded regardless of input trace size. Oversized responses\n * substitute a deterministic summary instead of bytes — see\n * `ViewTraceOversized`.\n */\n\n/** OTLP span kind (subset we actually use). */\nexport type TraceAnalystSpanKind =\n | 'AGENT'\n | 'LLM'\n | 'TOOL'\n | 'CHAIN'\n | 'GUARDRAIL'\n | 'SPAN'\n | 'UNKNOWN'\n\nexport type TraceAnalystSpanStatus = 'OK' | 'ERROR' | 'UNSET'\n\n/** Subset of OTLP span fields the analyst exposes to the agent. The\n * store's job is to project upstream's full span shape down to this\n * view — the analyst never sees vendor extensions directly. */\nexport interface TraceAnalystSpan {\n trace_id: string\n span_id: string\n parent_span_id: string | null\n name: string\n kind: TraceAnalystSpanKind\n start_time: string\n end_time: string\n duration_ms: number\n status: TraceAnalystSpanStatus\n status_message?: string\n service_name: string | null\n agent_name: string | null\n model_name: string | null\n tool_name: string | null\n /** Raw JSON-serialisable attribute map. May contain large strings;\n * callers must respect the per-attribute byte cap. */\n attributes: Record<string, unknown>\n}\n\nexport interface TraceAnalystTraceSummary {\n trace_id: string\n service_name: string | null\n agent_name: string | null\n span_count: number\n has_errors: boolean\n start_time: string\n end_time: string\n duration_ms: number\n raw_jsonl_bytes: number\n models: string[]\n tools: string[]\n}\n\nexport interface TraceAnalystFilters {\n /** Restrict to traces that contain at least one error span. */\n has_errors?: boolean\n /** Match if any span's `service.name` is in this list. */\n service_names?: string[]\n /** Match if any span's `agent.name` is in this list. */\n agent_names?: string[]\n /** Match if any LLM span's `llm.model_name` is in this list. */\n model_names?: string[]\n /** Match if any tool span's `tool.name` is in this list. */\n tool_names?: string[]\n /** ISO-8601 lower bound on the trace's earliest start time. */\n start_time_after?: string\n /** ISO-8601 upper bound on the trace's earliest start time. */\n start_time_before?: string\n /** Single regex applied to raw JSONL bytes for the trace. Opt-in;\n * expensive on large datasets. Use the indexed filters above first. */\n regex_pattern?: string\n}\n\n/** One distinct error signature across the dataset — the deterministic unit of\n * failure coverage. Signatures normalize volatile tokens (digits, hex/uuids,\n * paths, durations) out of the span `status_message` so semantically identical\n * failures collapse into one cluster. An analyst that accounts for every\n * cluster has, by construction, covered every distinct failure mode. */\nexport interface ErrorCluster {\n /** Normalized status_message — the cluster key. */\n signature: string\n /** A verbatim, un-normalized exemplar message (for exact-string citation). */\n status_message_sample: string\n /** The span name that most often carries this signature, if any. */\n span_name: string | null\n /** The tool that most often carries this signature, if any. */\n tool_name: string | null\n trace_count: number\n span_count: number\n /** trace_count / total error traces in the matched set (0..1). */\n prevalence: number\n /** Real trace ids carrying this signature (capped), passable to view/search. */\n exemplar_trace_ids: string[]\n /** Real span ids carrying this signature (capped). */\n exemplar_span_ids: string[]\n}\n\nexport interface DatasetOverview {\n total_traces: number\n raw_jsonl_bytes: number\n services: string[]\n agents: string[]\n models: string[]\n tool_names: string[]\n /** Up to 20 real trace ids the agent may pass to view/search tools. */\n sample_trace_ids: string[]\n errors: { trace_count: number; span_count: number }\n /** The COMPLETE deterministic error-signature population, sorted by\n * trace_count desc. This is the failure-coverage checklist: an analysis is\n * complete only when every cluster here is accounted for. Empty when the\n * matched set has no error spans. */\n error_clusters: ErrorCluster[]\n time_range: { earliest: string; latest: string } | null\n}\n\nexport interface QueryTracesPage {\n traces: TraceAnalystTraceSummary[]\n total: number\n has_more: boolean\n}\n\n/** Full-trace view. When the response would exceed the per-call byte\n * budget, `oversized` is populated INSTEAD of `spans` so the agent\n * knows to switch to `searchTrace` / `viewSpans`. */\nexport interface ViewTraceResult {\n trace_id: string\n spans?: TraceAnalystSpan[]\n oversized?: ViewTraceOversized\n}\n\nexport interface ViewTraceOversized {\n span_count: number\n /** Names with their counts, sorted desc. Capped at 20 entries. */\n top_span_names: Array<[string, number]>\n /** Largest single span body (bytes after attribute-cap projection). */\n span_response_bytes_max: number\n error_span_count: number\n}\n\nexport interface ViewSpansResult {\n trace_id: string\n spans: TraceAnalystSpan[]\n /** Number of requested span ids that were not found in the trace. */\n missing_span_ids: string[]\n /** Number of attribute fields truncated to fit the per-attribute cap. */\n truncated_attribute_count: number\n}\n\nexport interface SpanMatchRecord {\n trace_id: string\n span_id: string\n span_name: string\n span_kind: TraceAnalystSpanKind\n /** JSON pointer-style path to the matched value, e.g.\n * `attributes.\"llm.input_messages\"[2].content`. */\n attribute_path: string\n matched_text: string\n context_before: string\n context_after: string\n match_offset: number\n}\n\nexport interface SearchTraceResult {\n trace_id: string\n hits: SpanMatchRecord[]\n total_matches: number\n has_more: boolean\n}\n\nexport interface SearchSpanResult {\n trace_id: string\n span_id: string\n hits: SpanMatchRecord[]\n total_matches: number\n has_more: boolean\n}\n\n/** Tunable byte budgets for bounded RLM tool output. */\nexport interface TraceAnalystByteBudgets {\n /** Max bytes any single tool response may emit. Hard ceiling enforced\n * by the store; oversized → summary. Default 150_000. */\n perCallByteCeiling: number\n /** Per-attribute string truncation cap on `viewTrace` (discovery scan).\n * Default 4096. */\n perAttributeViewBudget: number\n /** Per-attribute string truncation cap on `viewSpans` (surgical reads).\n * Default 16384. */\n perAttributeSpanBudget: number\n /** Per-attribute cap on a single match record's `matched_text` and\n * context window. Default 1024. */\n perMatchTextBudget: number\n}\n\nexport const DEFAULT_TRACE_ANALYST_BUDGETS: TraceAnalystByteBudgets = {\n perCallByteCeiling: 150_000,\n perAttributeViewBudget: 4_096,\n perAttributeSpanBudget: 16_384,\n perMatchTextBudget: 1_024,\n}\n\n/** Marker substituted in place of truncated string payloads. Callers\n * parsing tool output can detect it deterministically. */\nexport const TRACE_ANALYST_TRUNCATION_MARKER_PREFIX = '[trace-analyst truncated:'\n","/**\n * `OtlpFileTraceStore` — read-only OTLP-JSONL trace store for the\n * trace-analyst.\n *\n * Wire shape. Each line of the input file is one OTLP-shaped span. The\n * store understands flattened OTLP JSONL plus the OpenInference vocab.\n * We project upstream's full\n * span shape down to `TraceAnalystSpan` lazily — full materialisation\n * only happens for the spans the agent actually requests.\n *\n * Indexing. On first read the store builds an in-memory index keyed\n * by `trace_id` carrying:\n * - byte offsets + lengths for each span line (for surgical reads\n * without re-parsing the whole file)\n * - a `TraceAnalystTraceSummary` rollup\n * - sets of services / agents / models / tools / has_errors\n * - byte size of the trace's JSONL slab\n *\n * Memory bound. The index keeps span metadata only — names, kinds,\n * offsets, status. Attribute payloads stay on disk until requested.\n * For a 50MB JSONL with 50k spans, the index is ~5MB.\n *\n * Concurrency. The store builds the index once on first read and\n * caches it. Subsequent reads reuse the index. The file is opened on\n * each read; we never hold a long-lived FD.\n */\n\nimport { readFile, stat } from 'node:fs/promises'\nimport { NotFoundError } from '../errors'\nimport {\n compareSpanTime,\n extractOtlpAttributes,\n projectOtlpFlatLine,\n spanEpochMillis,\n} from './otlp-span'\nimport { compileSearchRegex, type TraceAnalysisStore, truncateForBudget } from './store'\nimport {\n type DatasetOverview,\n DEFAULT_TRACE_ANALYST_BUDGETS,\n type ErrorCluster,\n type QueryTracesPage,\n type SearchSpanResult,\n type SearchTraceResult,\n type SpanMatchRecord,\n type TraceAnalystFilters,\n type TraceAnalystSpan,\n type TraceAnalystSpanKind,\n type TraceAnalystSpanStatus,\n type TraceAnalystTraceSummary,\n type ViewSpansResult,\n type ViewTraceOversized,\n type ViewTraceResult,\n} from './types'\n\n/** Lines indexed between event-loop yields. Bounded synchronous work per\n * tick keeps the index build from starving other tasks on large files\n * while staying coarse enough that the yields are cheap. */\nconst INDEX_YIELD_LINES = 5000\n\n/** Hand control back to the event loop without busy-waiting. */\nfunction yieldToEventLoop(): Promise<void> {\n return new Promise((resolve) => setImmediate(resolve))\n}\n\ninterface SpanIndexEntry {\n span_id: string\n parent_span_id: string | null\n name: string\n kind: TraceAnalystSpanKind\n start_time: string\n end_time: string\n duration_ms: number\n status: TraceAnalystSpanStatus\n status_message: string | undefined\n service_name: string | null\n agent_name: string | null\n model_name: string | null\n tool_name: string | null\n /** Byte offset in the raw JSONL file to the start of this span's line. */\n line_byte_offset: number\n /** Length of this line in bytes (excluding the trailing newline). */\n line_byte_length: number\n}\n\ninterface TraceIndexEntry {\n trace_id: string\n service_name: string | null\n agent_name: string | null\n span_count: number\n has_errors: boolean\n start_time: string\n end_time: string\n duration_ms: number\n raw_jsonl_bytes: number\n models: Set<string>\n tools: Set<string>\n spans: SpanIndexEntry[]\n /** Sorted by line offset for stable iteration. */\n}\n\ninterface DatasetIndex {\n byTrace: Map<string, TraceIndexEntry>\n totalRawBytes: number\n // Pre-computed sorted trace_ids for sample/query stability.\n sortedTraceIds: string[]\n}\n\nexport interface OtlpFileTraceStoreOptions {\n /** Path to the OTLP-JSONL file. */\n path: string\n /** Override the discovery (`viewTrace`) per-attribute byte cap. */\n perAttributeViewBudget?: number\n /** Override the surgical (`viewSpans`) per-attribute byte cap. */\n perAttributeSpanBudget?: number\n /** Override the per-call ceiling that triggers oversized summaries. */\n perCallByteCeiling?: number\n /** Override the per-match text budget. */\n perMatchTextBudget?: number\n /**\n * Hard ceiling on the trace file size in bytes. The store reads the\n * whole file into one Buffer and indexes it in memory, so an\n * unbounded file OOMs the process. Above this size the store fails\n * loud with `TraceFileTooLargeError` instead of degrading silently.\n * Default 256 MiB.\n */\n maxFileBytes?: number\n}\n\n/** Default ceiling for {@link OtlpFileTraceStoreOptions.maxFileBytes}. */\nexport const DEFAULT_MAX_TRACE_FILE_BYTES = 256 * 1024 * 1024\n\nexport class OtlpFileTraceStore implements TraceAnalysisStore {\n private readonly path: string\n private readonly perAttributeViewBudget: number\n private readonly perAttributeSpanBudget: number\n private readonly perCallByteCeiling: number\n private readonly perMatchTextBudget: number\n private readonly maxFileBytes: number\n private indexPromise?: Promise<DatasetIndex>\n /** Cached UTF-8 buffer of the file. We pin it once because every\n * read needs slice access and re-reading on each call balloons the\n * syscall count. */\n private bufferPromise?: Promise<Buffer>\n\n constructor(opts: OtlpFileTraceStoreOptions) {\n this.path = opts.path\n this.perAttributeViewBudget =\n opts.perAttributeViewBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeViewBudget\n this.perAttributeSpanBudget =\n opts.perAttributeSpanBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeSpanBudget\n this.perCallByteCeiling =\n opts.perCallByteCeiling ?? DEFAULT_TRACE_ANALYST_BUDGETS.perCallByteCeiling\n this.perMatchTextBudget =\n opts.perMatchTextBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perMatchTextBudget\n this.maxFileBytes = opts.maxFileBytes ?? DEFAULT_MAX_TRACE_FILE_BYTES\n }\n\n // ─── Public API ────────────────────────────────────────────────────\n\n async getOverview(filters?: TraceAnalystFilters): Promise<DatasetOverview> {\n const idx = await this.index()\n const matched = await this.matchedTraces(idx, filters)\n\n const services = new Set<string>()\n const agents = new Set<string>()\n const models = new Set<string>()\n const tools = new Set<string>()\n let rawBytes = 0\n let earliest: string | null = null\n let latest: string | null = null\n let errorTraceCount = 0\n let errorSpanCount = 0\n const clusters = new Map<string, ErrorClusterAccumulator>()\n\n for (const t of matched) {\n if (t.service_name) services.add(t.service_name)\n if (t.agent_name) agents.add(t.agent_name)\n for (const m of t.models) models.add(m)\n for (const tn of t.tools) tools.add(tn)\n rawBytes += t.raw_jsonl_bytes\n if (!earliest || compareSpanTime(t.start_time, earliest) < 0) earliest = t.start_time\n if (!latest || compareSpanTime(t.end_time, latest) > 0) latest = t.end_time\n if (t.has_errors) {\n errorTraceCount += 1\n for (const s of t.spans) {\n if (s.status !== 'ERROR') continue\n errorSpanCount += 1\n accumulateErrorCluster(clusters, t.trace_id, s)\n }\n }\n }\n\n const sample_trace_ids = matched.slice(0, 20).map((t) => t.trace_id)\n return {\n total_traces: matched.length,\n raw_jsonl_bytes: rawBytes,\n services: [...services].sort(),\n agents: [...agents].sort(),\n models: [...models].sort(),\n tool_names: [...tools].sort(),\n sample_trace_ids,\n errors: { trace_count: errorTraceCount, span_count: errorSpanCount },\n error_clusters: finalizeErrorClusters(clusters, errorTraceCount),\n time_range: earliest && latest ? { earliest, latest } : null,\n }\n }\n\n async queryTraces(opts: {\n filters?: TraceAnalystFilters\n limit: number\n offset?: number\n }): Promise<QueryTracesPage> {\n if (!Number.isInteger(opts.limit) || opts.limit < 1 || opts.limit > 200) {\n throw new RangeError(`queryTraces.limit must be 1..200, got ${opts.limit}`)\n }\n const offset = opts.offset ?? 0\n if (!Number.isInteger(offset) || offset < 0) {\n throw new RangeError(`queryTraces.offset must be >=0, got ${offset}`)\n }\n\n const idx = await this.index()\n const matched = await this.matchedTraces(idx, opts.filters)\n const slice = matched.slice(offset, offset + opts.limit)\n return {\n traces: slice.map((t) => this.toSummary(t)),\n total: matched.length,\n has_more: offset + slice.length < matched.length,\n }\n }\n\n async countTraces(filters?: TraceAnalystFilters): Promise<number> {\n const idx = await this.index()\n const matched = await this.matchedTraces(idx, filters)\n return matched.length\n }\n\n async viewTrace(opts: {\n trace_id: string\n per_attribute_byte_cap?: number\n }): Promise<ViewTraceResult> {\n const idx = await this.index()\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) {\n throw new TraceNotFoundError(opts.trace_id)\n }\n const cap = opts.per_attribute_byte_cap ?? this.perAttributeViewBudget\n\n // Probe size first — if the materialised payload would exceed\n // the per-call ceiling we return an oversized summary rather than\n // blowing the agent's context.\n const buf = await this.buffer()\n const spans: TraceAnalystSpan[] = []\n let runningBytes = 0\n let span_response_bytes_max = 0\n const counter: TruncationCounter = { value: 0 }\n for (const s of trace.spans) {\n const projected = this.projectSpan(buf, trace.trace_id, s, cap, counter)\n const bytes = Buffer.byteLength(JSON.stringify(projected), 'utf8')\n span_response_bytes_max = Math.max(span_response_bytes_max, bytes)\n runningBytes += bytes\n if (runningBytes > this.perCallByteCeiling) {\n return {\n trace_id: trace.trace_id,\n oversized: this.buildOversizedSummary(trace, span_response_bytes_max),\n }\n }\n spans.push(projected)\n }\n return { trace_id: trace.trace_id, spans }\n }\n\n async viewSpans(opts: {\n trace_id: string\n span_ids: readonly string[]\n per_attribute_byte_cap?: number\n }): Promise<ViewSpansResult> {\n const idx = await this.index()\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) throw new TraceNotFoundError(opts.trace_id)\n if (opts.span_ids.length === 0) {\n return {\n trace_id: trace.trace_id,\n spans: [],\n missing_span_ids: [],\n truncated_attribute_count: 0,\n }\n }\n if (opts.span_ids.length > 100) {\n throw new RangeError(`viewSpans.span_ids cap is 100, got ${opts.span_ids.length}`)\n }\n const cap = opts.per_attribute_byte_cap ?? this.perAttributeSpanBudget\n\n const wantSet = new Set(opts.span_ids)\n const found = trace.spans.filter((s) => wantSet.has(s.span_id))\n const missing = opts.span_ids.filter((id) => !found.some((f) => f.span_id === id))\n\n const buf = await this.buffer()\n const spans: TraceAnalystSpan[] = []\n const counter: TruncationCounter = { value: 0 }\n let runningBytes = 0\n for (const s of found) {\n const projected = this.projectSpan(buf, trace.trace_id, s, cap, counter)\n const bytes = Buffer.byteLength(JSON.stringify(projected), 'utf8')\n runningBytes += bytes\n if (runningBytes > this.perCallByteCeiling) {\n // Stop adding further spans rather than truncate mid-list.\n // Callers can refetch the rest with a smaller `span_ids`.\n break\n }\n spans.push(projected)\n }\n return {\n trace_id: trace.trace_id,\n spans,\n missing_span_ids: missing,\n truncated_attribute_count: counter.value,\n }\n }\n\n async searchTrace(opts: {\n trace_id: string\n regex_pattern: string\n max_matches?: number\n }): Promise<SearchTraceResult> {\n const max_matches = opts.max_matches ?? 50\n if (!Number.isInteger(max_matches) || max_matches < 1 || max_matches > 500) {\n throw new RangeError(`searchTrace.max_matches must be 1..500, got ${max_matches}`)\n }\n const idx = await this.index()\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) throw new TraceNotFoundError(opts.trace_id)\n const re = compileSearchRegex(opts.regex_pattern)\n\n const buf = await this.buffer()\n const hits: SpanMatchRecord[] = []\n let total = 0\n let capped = false\n for (const s of trace.spans) {\n const remaining = max_matches - hits.length\n const localHits = await this.scanSpanForMatches(\n buf,\n trace.trace_id,\n s,\n re,\n this.perMatchTextBudget,\n remaining,\n )\n total += localHits.total\n for (const h of localHits.records) {\n if (hits.length >= max_matches) break\n hits.push(h)\n }\n if (hits.length >= max_matches) {\n // Capped: we stopped scanning, so `total` is a lower bound on the\n // real match count — never report it as exact. has_more signals\n // \"more exist\"; total_matches mirrors hits so callers don't read a\n // fabricated number.\n capped = true\n break\n }\n }\n return {\n trace_id: trace.trace_id,\n hits,\n // Uncapped: every span scanned to completion, so `total` is exact.\n total_matches: capped ? hits.length : total,\n has_more: capped || total > hits.length,\n }\n }\n\n async searchSpan(opts: {\n trace_id: string\n span_id: string\n regex_pattern: string\n max_matches?: number\n }): Promise<SearchSpanResult> {\n const max_matches = opts.max_matches ?? 50\n if (!Number.isInteger(max_matches) || max_matches < 1 || max_matches > 500) {\n throw new RangeError(`searchSpan.max_matches must be 1..500, got ${max_matches}`)\n }\n const idx = await this.index()\n const trace = idx.byTrace.get(opts.trace_id)\n if (!trace) throw new TraceNotFoundError(opts.trace_id)\n const span = trace.spans.find((s) => s.span_id === opts.span_id)\n if (!span) {\n throw new SpanNotFoundError(opts.trace_id, opts.span_id)\n }\n const re = compileSearchRegex(opts.regex_pattern)\n const buf = await this.buffer()\n const localHits = await this.scanSpanForMatches(\n buf,\n trace.trace_id,\n span,\n re,\n this.perMatchTextBudget,\n max_matches,\n )\n return {\n trace_id: trace.trace_id,\n span_id: span.span_id,\n hits: localHits.records,\n total_matches: localHits.total,\n has_more: localHits.total > localHits.records.length,\n }\n }\n\n // ─── Index building ────────────────────────────────────────────────\n\n /** Force the index to materialise. Useful to amortise startup cost\n * before the first agent call. */\n async ensureIndexed(): Promise<void> {\n await this.index()\n }\n\n private async buffer(): Promise<Buffer> {\n if (!this.bufferPromise) {\n this.bufferPromise = this.readGuarded()\n }\n return this.bufferPromise\n }\n\n /** Stat-then-read so an oversized file fails loud BEFORE we allocate a\n * multi-hundred-MB Buffer and OOM the process. A missing file surfaces\n * as TraceFileMissingError; any other stat/read error propagates. */\n private async readGuarded(): Promise<Buffer> {\n let stats: Awaited<ReturnType<typeof stat>>\n try {\n stats = await stat(this.path)\n } catch (err) {\n if ((err as NodeJS.ErrnoException)?.code === 'ENOENT') {\n throw new TraceFileMissingError(this.path)\n }\n throw err\n }\n if (stats.size > this.maxFileBytes) {\n throw new TraceFileTooLargeError(this.path, stats.size, this.maxFileBytes)\n }\n return readFile(this.path)\n }\n\n private async index(): Promise<DatasetIndex> {\n if (!this.indexPromise) {\n this.indexPromise = this.buildIndex()\n }\n return this.indexPromise\n }\n\n private async buildIndex(): Promise<DatasetIndex> {\n // readGuarded surfaces missing/oversized files as typed errors.\n const buf = await this.buffer()\n\n const byTrace = new Map<string, TraceIndexEntry>()\n let cursor = 0\n let sinceYield = 0\n while (cursor < buf.length) {\n // Yield to the event loop every INDEX_YIELD_LINES lines so a huge\n // file doesn't monopolise the thread for the whole index build.\n if (++sinceYield >= INDEX_YIELD_LINES) {\n sinceYield = 0\n await yieldToEventLoop()\n }\n const newlineIndex = buf.indexOf(0x0a, cursor) // \\n\n const lineEnd = newlineIndex === -1 ? buf.length : newlineIndex\n const lineLength = lineEnd - cursor\n if (lineLength === 0) {\n cursor = lineEnd + 1\n continue\n }\n const lineSlice = buf.subarray(cursor, lineEnd).toString('utf8')\n const lineOffset = cursor\n cursor = lineEnd + 1\n\n let parsed: unknown\n try {\n parsed = JSON.parse(lineSlice)\n } catch {\n // Skip malformed lines silently. The agent shouldn't see them\n // but we don't want one bad line to nuke an entire dataset.\n continue\n }\n if (!parsed || typeof parsed !== 'object') continue\n const span = projectOtlpFlatLine(parsed as Record<string, unknown>)\n if (!span) continue\n\n let entry = byTrace.get(span.trace_id)\n if (!entry) {\n entry = {\n trace_id: span.trace_id,\n service_name: span.service_name,\n agent_name: span.agent_name,\n span_count: 0,\n has_errors: false,\n start_time: span.start_time,\n end_time: span.end_time,\n duration_ms: 0,\n raw_jsonl_bytes: 0,\n models: new Set(),\n tools: new Set(),\n spans: [],\n }\n byTrace.set(span.trace_id, entry)\n } else {\n // Pin the trace's service/agent to the first AGENT span we\n // Prefer the first agent/service fields that appear in the trace.\n if (!entry.service_name && span.service_name) entry.service_name = span.service_name\n if (!entry.agent_name && span.agent_name) entry.agent_name = span.agent_name\n }\n\n const indexEntry: SpanIndexEntry = {\n span_id: span.span_id,\n parent_span_id: span.parent_span_id,\n name: span.name,\n kind: span.kind,\n start_time: span.start_time,\n end_time: span.end_time,\n duration_ms: span.duration_ms,\n status: span.status,\n status_message: span.status_message,\n service_name: span.service_name,\n agent_name: span.agent_name,\n model_name: span.model_name,\n tool_name: span.tool_name,\n line_byte_offset: lineOffset,\n line_byte_length: lineLength,\n }\n entry.spans.push(indexEntry)\n entry.span_count += 1\n entry.raw_jsonl_bytes += lineLength + 1 // +1 newline byte\n if (span.status === 'ERROR') entry.has_errors = true\n if (compareSpanTime(span.start_time, entry.start_time) < 0) entry.start_time = span.start_time\n if (compareSpanTime(span.end_time, entry.end_time) > 0) entry.end_time = span.end_time\n if (span.model_name) entry.models.add(span.model_name)\n if (span.tool_name) entry.tools.add(span.tool_name)\n }\n\n // Compute trace duration once, sort spans by start time for\n // stable iteration.\n let totalRawBytes = 0\n for (const t of byTrace.values()) {\n totalRawBytes += t.raw_jsonl_bytes\n t.spans.sort(\n (a, b) =>\n compareSpanTime(a.start_time, b.start_time) || a.line_byte_offset - b.line_byte_offset,\n )\n // Duration is 0 unless BOTH bounds parse — a missing/garbage timestamp\n // yields 0, never a NaN (→ null in JSON) or a bogus epoch-from-zero span.\n const startMs = spanEpochMillis(t.start_time)\n const endMs = spanEpochMillis(t.end_time)\n t.duration_ms = startMs === null || endMs === null ? 0 : Math.max(0, endMs - startMs)\n }\n const sortedTraceIds = [...byTrace.keys()].sort()\n\n return { byTrace, totalRawBytes, sortedTraceIds }\n }\n\n // ─── Filter pipeline ───────────────────────────────────────────────\n\n private async matchedTraces(\n idx: DatasetIndex,\n filters: TraceAnalystFilters | undefined,\n ): Promise<TraceIndexEntry[]> {\n const traces = idx.sortedTraceIds.map((id) => idx.byTrace.get(id)).filter(isPresent)\n if (!filters) return traces\n\n const indexedFiltered = traces.filter((t) => {\n if (filters.has_errors !== undefined && t.has_errors !== filters.has_errors) return false\n if (filters.service_names && filters.service_names.length > 0) {\n if (!t.service_name || !filters.service_names.includes(t.service_name)) return false\n }\n if (filters.agent_names && filters.agent_names.length > 0) {\n if (!t.agent_name || !filters.agent_names.includes(t.agent_name)) return false\n }\n if (filters.model_names && filters.model_names.length > 0) {\n if (![...t.models].some((m) => filters.model_names!.includes(m))) return false\n }\n if (filters.tool_names && filters.tool_names.length > 0) {\n if (![...t.tools].some((tn) => filters.tool_names!.includes(tn))) return false\n }\n if (filters.start_time_after && t.start_time < filters.start_time_after) return false\n if (filters.start_time_before && t.start_time > filters.start_time_before) return false\n return true\n })\n\n if (!filters.regex_pattern) return indexedFiltered\n\n // Opt-in raw-bytes scan — only over the already-narrowed set.\n const re = compileSearchRegex(filters.regex_pattern)\n const buf = await this.buffer()\n const out: TraceIndexEntry[] = []\n for (const t of indexedFiltered) {\n let matched = false\n for (const s of t.spans) {\n const slice = buf.subarray(s.line_byte_offset, s.line_byte_offset + s.line_byte_length)\n // Buffer.toString allocates; tolerate it because regex_pattern\n // is opt-in. Future optimisation: byte-level fast-path for\n // ASCII-only patterns.\n if (re.test(slice.toString('utf8'))) {\n matched = true\n break\n }\n }\n if (matched) out.push(t)\n }\n return out\n }\n\n private toSummary(t: TraceIndexEntry): TraceAnalystTraceSummary {\n return {\n trace_id: t.trace_id,\n service_name: t.service_name,\n agent_name: t.agent_name,\n span_count: t.span_count,\n has_errors: t.has_errors,\n start_time: t.start_time,\n end_time: t.end_time,\n duration_ms: t.duration_ms,\n raw_jsonl_bytes: t.raw_jsonl_bytes,\n models: [...t.models].sort(),\n tools: [...t.tools].sort(),\n }\n }\n\n // ─── Span projection (lazy attribute reads) ────────────────────────\n\n private projectSpan(\n buf: Buffer,\n trace_id: string,\n s: SpanIndexEntry,\n perAttrCap: number,\n counter: TruncationCounter,\n ): TraceAnalystSpan {\n const slice = buf\n .subarray(s.line_byte_offset, s.line_byte_offset + s.line_byte_length)\n .toString('utf8')\n let raw: Record<string, unknown> = {}\n try {\n const parsed = JSON.parse(slice)\n if (parsed && typeof parsed === 'object') raw = parsed as Record<string, unknown>\n } catch {\n // Should not happen — index pre-validated.\n }\n const attrs = extractOtlpAttributes(raw)\n const projected: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(attrs)) {\n if (typeof v === 'string') {\n const trunc = truncateForBudget(v, perAttrCap)\n if (trunc !== v) counter.value += 1\n projected[k] = trunc\n } else if (Array.isArray(v) || (v && typeof v === 'object')) {\n const json = JSON.stringify(v)\n const trunc = truncateForBudget(json, perAttrCap)\n if (trunc !== json) {\n counter.value += 1\n projected[k] = trunc\n } else {\n projected[k] = v\n }\n } else {\n projected[k] = v\n }\n }\n return {\n trace_id,\n span_id: s.span_id,\n parent_span_id: s.parent_span_id,\n name: s.name,\n kind: s.kind,\n start_time: s.start_time,\n end_time: s.end_time,\n duration_ms: s.duration_ms,\n status: s.status,\n status_message: s.status_message,\n service_name: s.service_name,\n agent_name: s.agent_name,\n model_name: s.model_name,\n tool_name: s.tool_name,\n attributes: projected,\n }\n }\n\n private buildOversizedSummary(\n t: TraceIndexEntry,\n span_response_bytes_max: number,\n ): ViewTraceOversized {\n const counts = new Map<string, number>()\n let errorCount = 0\n for (const s of t.spans) {\n counts.set(s.name, (counts.get(s.name) ?? 0) + 1)\n if (s.status === 'ERROR') errorCount += 1\n }\n const top = [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 20)\n return {\n span_count: t.span_count,\n top_span_names: top,\n span_response_bytes_max,\n error_span_count: errorCount,\n }\n }\n\n private async scanSpanForMatches(\n buf: Buffer,\n trace_id: string,\n s: SpanIndexEntry,\n re: RegExp,\n textBudget: number,\n recordCap: number,\n ): Promise<{ records: SpanMatchRecord[]; total: number; hasMore: boolean }> {\n // We scan against the original raw JSONL slice for each span and\n // record byte positions; the matched_text + context window is\n // truncated to `textBudget` bytes per record so total tool output\n // stays bounded even if hits cluster.\n const slice = buf\n .subarray(s.line_byte_offset, s.line_byte_offset + s.line_byte_length)\n .toString('utf8')\n const records: SpanMatchRecord[] = []\n const globalRe = new RegExp(re.source, re.flags.includes('g') ? re.flags : `${re.flags}g`)\n let total = 0\n let hasMore = false\n let m: RegExpExecArray | null = globalRe.exec(slice)\n while (m !== null) {\n total += 1\n if (m.index === globalRe.lastIndex) globalRe.lastIndex += 1 // zero-width guard\n if (records.length >= recordCap) {\n hasMore = true\n break\n }\n const before = slice.slice(Math.max(0, m.index - textBudget / 2), m.index)\n const after = slice.slice(\n m.index + m[0].length,\n m.index + m[0].length + Math.floor(textBudget / 2),\n )\n records.push({\n trace_id,\n span_id: s.span_id,\n span_name: s.name,\n span_kind: s.kind,\n attribute_path: bestAttributePathForOffset(slice, m.index) ?? 'span.raw',\n matched_text: truncateForBudget(m[0], textBudget),\n context_before: truncateForBudget(before, textBudget),\n context_after: truncateForBudget(after, textBudget),\n match_offset: m.index,\n })\n m = globalRe.exec(slice)\n }\n return { records, total, hasMore }\n }\n}\n\n// ─── Errors ──────────────────────────────────────────────────────────\n\nexport class TraceFileMissingError extends NotFoundError {\n constructor(path: string) {\n super(`trace file not found: ${path}`)\n }\n}\nexport class TraceFileTooLargeError extends Error {\n readonly path: string\n readonly size_bytes: number\n readonly max_bytes: number\n constructor(path: string, size_bytes: number, max_bytes: number) {\n super(\n `trace file ${path} is ${size_bytes} bytes, over the ${max_bytes}-byte limit; ` +\n 'raise OtlpFileTraceStoreOptions.maxFileBytes or pre-split the file',\n )\n this.path = path\n this.size_bytes = size_bytes\n this.max_bytes = max_bytes\n }\n}\nexport class TraceNotFoundError extends NotFoundError {\n readonly trace_id: string\n constructor(trace_id: string) {\n super(`trace not found: ${trace_id}`)\n this.trace_id = trace_id\n }\n}\nexport class SpanNotFoundError extends NotFoundError {\n readonly trace_id: string\n readonly span_id: string\n constructor(trace_id: string, span_id: string) {\n super(`span ${span_id} not found in trace ${trace_id}`)\n this.trace_id = trace_id\n this.span_id = span_id\n }\n}\n\n// ─── OTLP shape readers ──────────────────────────────────────────────\n//\n// The per-line projection lives in `./otlp-span` so the index here and\n// `otlpToRunRecords` read the same vocabulary off the same parser.\n\nfunction isPresent<T>(v: T | undefined): v is T {\n return v !== undefined\n}\n\n// Per-call truncation counter. Each public read that projects spans\n// owns one of these and threads it through projectSpan; a store-keyed\n// counter would let two concurrent reads on the same store report each\n// other's truncation counts.\ninterface TruncationCounter {\n value: number\n}\n\n/** A `\"` at `idx` is a real JSON delimiter only when the run of `\\`\n * immediately preceding it is even-length; an odd run means the quote\n * is escaped (`\\\"`) and is part of a string value, not a boundary. */\nfunction isUnescapedQuote(slice: string, idx: number): boolean {\n if (slice[idx] !== '\"') return false\n let backslashes = 0\n let b = idx - 1\n while (b >= 0 && slice[b] === '\\\\') {\n backslashes += 1\n b -= 1\n }\n return backslashes % 2 === 0\n}\n\n/** Scan backwards from `from` (inclusive) for the nearest UNescaped `\"`.\n * Returns its index, or -1 when none is found. */\nfunction prevUnescapedQuote(slice: string, from: number): number {\n for (let i = from; i >= 0; i -= 1) {\n if (slice[i] === '\"' && isUnescapedQuote(slice, i)) return i\n }\n return -1\n}\n\n/**\n * Best-effort: locate the JSON path for the substring at `offset` in\n * a single span's JSONL slice. The slice is '...,\"key\":\"value...\"' — we\n * walk back from `offset` to the value-opening quote, past the `:`, to\n * the key's closing then opening quote, skipping `\\\"`-escaped quotes that\n * live inside string values. Returns `null` when the offset doesn't fall\n * inside a recognisable string field.\n */\nfunction bestAttributePathForOffset(slice: string, offset: number): string | null {\n // Value-opening quote: nearest unescaped '\"' at or before the offset.\n const valueQuote = prevUnescapedQuote(slice, Math.min(offset, slice.length - 1))\n if (valueQuote < 1) return null\n // The ':' separating key and value sits before the value quote.\n let j = valueQuote - 1\n while (j >= 0 && slice[j] !== ':') j -= 1\n if (j < 1) return null\n // Key closing quote, then key opening quote — both unescaped.\n const keyClose = prevUnescapedQuote(slice, j - 1)\n if (keyClose < 1) return null\n const keyOpen = prevUnescapedQuote(slice, keyClose - 1)\n if (keyOpen < 0) return null\n return slice.slice(keyOpen + 1, keyClose)\n}\n\n// ─── Error-cluster extraction ────────────────────────────────────────\n//\n// Deterministic failure-coverage population. The error-span loop in\n// getOverview already visits every ERROR span; bucketing them by a\n// normalized status_message signature turns \"N error spans\" into \"K\n// distinct failure modes\" — the checklist an analyst must close. No LLM.\n\nconst ERROR_CLUSTER_MAX = 50\nconst ERROR_CLUSTER_EXEMPLARS = 5\nconst SIGNATURE_MAX_CHARS = 160\n\ninterface ErrorClusterAccumulator {\n signature: string\n sample: string\n traceIds: Set<string>\n spanIds: string[]\n spanCount: number\n spanNames: Map<string, number>\n toolNames: Map<string, number>\n}\n\n/** Collapse volatile tokens so semantically identical failures share a key:\n * hex/uuid ids → <id>, numbers → #, quoted/abs paths → <path>, durations →\n * <dur>, whitespace collapsed. Empty/absent messages fall back to the span\n * name so a no-message error still forms a real cluster. */\nfunction normalizeErrorSignature(message: string | undefined, spanName: string): string {\n const raw = (message ?? '').trim()\n const base = raw.length > 0 ? raw : `(${spanName || 'error'} — no message)`\n const norm = base\n .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '<id>')\n .replace(/\\b[0-9a-f]{12,}\\b/gi, '<id>')\n .replace(/(?:\\/[\\w.\\-@]+){2,}/g, '<path>')\n .replace(/\\b\\d+(?:\\.\\d+)?(ms|s|m|h|kb|mb|gb)?\\b/gi, (_m, u) => (u ? `#${u}` : '#'))\n .replace(/\\s+/g, ' ')\n .trim()\n return norm.length > SIGNATURE_MAX_CHARS ? `${norm.slice(0, SIGNATURE_MAX_CHARS)}…` : norm\n}\n\nfunction bump(map: Map<string, number>, key: string | null): void {\n if (!key) return\n map.set(key, (map.get(key) ?? 0) + 1)\n}\n\nfunction topKey(map: Map<string, number>): string | null {\n let best: string | null = null\n let bestN = 0\n for (const [k, n] of map)\n if (n > bestN) {\n best = k\n bestN = n\n }\n return best\n}\n\nfunction accumulateErrorCluster(\n clusters: Map<string, ErrorClusterAccumulator>,\n traceId: string,\n span: SpanIndexEntry,\n): void {\n const signature = normalizeErrorSignature(span.status_message, span.name)\n let acc = clusters.get(signature)\n if (!acc) {\n acc = {\n signature,\n sample: (span.status_message ?? span.name ?? '').slice(0, 500),\n traceIds: new Set(),\n spanIds: [],\n spanCount: 0,\n spanNames: new Map(),\n toolNames: new Map(),\n }\n clusters.set(signature, acc)\n }\n acc.traceIds.add(traceId)\n acc.spanCount += 1\n if (acc.spanIds.length < ERROR_CLUSTER_EXEMPLARS && !acc.spanIds.includes(span.span_id)) {\n acc.spanIds.push(span.span_id)\n }\n bump(acc.spanNames, span.name)\n bump(acc.toolNames, span.tool_name)\n}\n\nfunction finalizeErrorClusters(\n clusters: Map<string, ErrorClusterAccumulator>,\n errorTraceCount: number,\n): ErrorCluster[] {\n const out = [...clusters.values()].map(\n (acc): ErrorCluster => ({\n signature: acc.signature,\n status_message_sample: acc.sample,\n span_name: topKey(acc.spanNames),\n tool_name: topKey(acc.toolNames),\n trace_count: acc.traceIds.size,\n span_count: acc.spanCount,\n prevalence: errorTraceCount > 0 ? acc.traceIds.size / errorTraceCount : 0,\n exemplar_trace_ids: [...acc.traceIds].slice(0, ERROR_CLUSTER_EXEMPLARS),\n exemplar_span_ids: acc.spanIds.slice(0, ERROR_CLUSTER_EXEMPLARS),\n }),\n )\n out.sort((a, b) => b.trace_count - a.trace_count || b.span_count - a.span_count)\n return out.slice(0, ERROR_CLUSTER_MAX)\n}\n","/**\n * `TraceAnalysisStore` — read-side interface the trace-analyst calls\n * through. Six operations, all bounded:\n *\n * - `getOverview(filters?)` — dataset rollup + sample trace ids.\n * - `queryTraces(filters?, limit, offset)` — paginated summaries.\n * - `countTraces(filters?)` — cheap count without materialisation.\n * - `viewTrace(trace_id, perAttrCap)` — full span list, oversized → summary.\n * - `viewSpans(trace_id, span_ids, perAttrCap)` — surgical span fetch.\n * - `searchTrace(trace_id, regex, max_matches)` — bounded regex hits.\n * - `searchSpan(trace_id, span_id, regex, max_matches)` — single-span search.\n *\n * Multiple implementations ship in the core (`OtlpFileTraceStore`).\n * Downstream callers can supply their own — e.g. a DuckDB-backed\n * adapter or an in-memory adapter for tests — by implementing this\n * interface.\n *\n * Filters compose with AND semantics. Empty/undefined fields impose\n * no constraint. `regex_pattern` is the only opt-in raw-bytes scan —\n * implementations may skip it via `count`/`overview` when not set.\n */\n\nimport type {\n DatasetOverview,\n QueryTracesPage,\n SearchSpanResult,\n SearchTraceResult,\n TraceAnalystFilters,\n ViewSpansResult,\n ViewTraceResult,\n} from './types'\n\nexport interface TraceAnalysisStore {\n getOverview(filters?: TraceAnalystFilters): Promise<DatasetOverview>\n\n queryTraces(opts: {\n filters?: TraceAnalystFilters\n limit: number\n offset?: number\n }): Promise<QueryTracesPage>\n\n countTraces(filters?: TraceAnalystFilters): Promise<number>\n\n viewTrace(opts: {\n trace_id: string\n /** Override per-attribute byte cap. Defaults to discovery budget. */\n per_attribute_byte_cap?: number\n }): Promise<ViewTraceResult>\n\n viewSpans(opts: {\n trace_id: string\n span_ids: readonly string[]\n /** Override per-attribute byte cap. Defaults to surgical budget. */\n per_attribute_byte_cap?: number\n }): Promise<ViewSpansResult>\n\n searchTrace(opts: {\n trace_id: string\n regex_pattern: string\n /** Hard cap on matches returned. Default 50. */\n max_matches?: number\n }): Promise<SearchTraceResult>\n\n searchSpan(opts: {\n trace_id: string\n span_id: string\n regex_pattern: string\n max_matches?: number\n }): Promise<SearchSpanResult>\n}\n\n/** Compile a regex with the same anchoring + flags semantics across\n * implementations. Throws on invalid pattern — callers should surface\n * that to the agent so it can refine instead of looping. */\nexport function compileSearchRegex(pattern: string): RegExp {\n let source = pattern\n let flags = 'm'\n if (source.startsWith('(?i)')) {\n source = source.slice(4)\n flags += 'i'\n }\n return new RegExp(source, flags)\n}\n\n/** Truncate string payload deterministically for tool responses.\n * Marker is parseable so downstream consumers can detect truncation\n * and decide whether to fetch surgically. */\nexport function truncateForBudget(value: string, byteCap: number): string {\n // We measure UTF-8 byte length conservatively via Buffer.byteLength;\n // for predictability the truncation point is in CHARS, never inside\n // a code point.\n const original = Buffer.byteLength(value, 'utf8')\n if (original <= byteCap) return value\n\n // Step back from the cap until we're at a valid char boundary.\n // Slice by char count proportional to byte ratio, then re-measure.\n const ratio = byteCap / original\n let cut = Math.max(0, Math.floor(value.length * ratio))\n while (cut > 0 && Buffer.byteLength(value.slice(0, cut), 'utf8') > byteCap) {\n cut -= 1\n }\n return `${value.slice(0, cut)}\\n[trace-analyst truncated: original ${original} bytes]`\n}\n","/**\n * Trace-analyst tool surface — six namespaced AxFunctions the analyst\n * agent calls from generated JS code via `traces.<name>(...)`.\n *\n * Discovery → narrow → deep-read protocol. Tool names + ordering\n * support RLM discovery:\n *\n * 1. `getDatasetOverview` (cheap) — first call, sizes the dataset\n * 2. `queryTraces` — paginated summaries with `raw_jsonl_bytes`\n * 3. `countTraces` — cheap pre-flight before regex\n * 4. `viewTrace` — full span list, oversized → summary\n * 5. `viewSpans` — surgical 16KB-cap reads\n * 6. `searchTrace` / `searchSpan` — bounded regex hits\n *\n * Failure mode. Tool handlers throw on bad input (invalid trace ids,\n * out-of-range pagination, malformed regex). Ax converts thrown errors\n * into actor-visible `[ERROR]` strings so the analyst can adjust on\n * the next turn instead of looping.\n */\n\nimport type { AxFunction } from '@ax-llm/ax'\nimport { f, fn } from '@ax-llm/ax'\n\nimport type { TraceAnalysisStore } from './store'\nimport type { TraceAnalystFilters } from './types'\n\nconst NAMESPACE = 'traces'\n\ninterface BuildTraceAnalystToolsOpts {\n store: TraceAnalysisStore\n /** Override the default sample-trace-id slot count (20). Mostly for tests. */\n sampleTraceLimit?: number\n}\n\nconst filtersField = f\n .json('Filter set. ALL fields are AND-composed. Leave empty to scan everything.')\n .optional()\n\n/**\n * Build the trace-analyst function set. Pass the result into\n * `agent(...).functions.local`.\n */\nexport function buildTraceAnalystTools(opts: BuildTraceAnalystToolsOpts): AxFunction[] {\n const { store } = opts\n\n const getDatasetOverview = fn('getDatasetOverview')\n .description(\n 'Dataset rollup: total traces, raw_jsonl_bytes, services, agents, ' +\n 'models, tools, and sample_trace_ids (real ids passable to ' +\n 'view/search). Always call this FIRST without a regex_pattern.',\n )\n .namespace(NAMESPACE)\n .arg('filters', filtersField)\n .returns(f.json('DatasetOverview'))\n .handler(async ({ filters }) => store.getOverview(parseFilters(filters)))\n .build()\n\n const queryTraces = fn('queryTraces')\n .description(\n 'Paginated trace summaries. Each summary carries raw_jsonl_bytes — ' +\n 'use it to size traces BEFORE calling viewTrace. Narrow with indexed ' +\n 'filters before adding regex_pattern.',\n )\n .namespace(NAMESPACE)\n .arg('filters', filtersField)\n .arg('limit', f.number('Page size, 1..200'))\n .arg('offset', f.number('Page offset; default 0').optional())\n .returns(f.json('QueryTracesPage'))\n .handler(async ({ filters, limit, offset }) =>\n store.queryTraces({\n filters: parseFilters(filters),\n limit: assertPageLimit(limit),\n offset: assertOffset(offset),\n }),\n )\n .build()\n\n const countTraces = fn('countTraces')\n .description(\n 'Count traces matching `filters`. Use as a cheap pre-flight ' +\n 'before opting into a regex_pattern scan.',\n )\n .namespace(NAMESPACE)\n .arg('filters', filtersField)\n .returns(f.number('count'))\n .handler(async ({ filters }) => store.countTraces(parseFilters(filters)))\n .build()\n\n const viewTrace = fn('viewTrace')\n .description(\n 'Return ALL spans for a single trace, with each attribute capped at ' +\n '~4KB. If the response would exceed the per-call ceiling the result ' +\n 'carries `oversized` instead of `spans` — DO NOT retry with the same ' +\n 'trace_id; switch to searchTrace / viewSpans.',\n )\n .namespace(NAMESPACE)\n .arg('trace_id', f.string('Real trace id from a prior overview/query'))\n .returns(f.json('ViewTraceResult'))\n .handler(async ({ trace_id }) =>\n store.viewTrace({ trace_id: assertString(trace_id, 'trace_id') }),\n )\n .build()\n\n const viewSpans = fn('viewSpans')\n .description(\n 'Surgical read of specific spans within a trace, with each ' +\n 'attribute capped at ~16KB (4× the discovery cap). Use after ' +\n 'searchTrace narrows to specific span_ids.',\n )\n .namespace(NAMESPACE)\n .arg('trace_id', f.string('Real trace id'))\n .arg('span_ids', f.string('Span ids to fetch').array())\n .returns(f.json('ViewSpansResult'))\n .handler(async ({ trace_id, span_ids }) =>\n store.viewSpans({\n trace_id: assertString(trace_id, 'trace_id'),\n span_ids: assertStringArray(span_ids, 'span_ids'),\n }),\n )\n .build()\n\n const searchTrace = fn('searchTrace')\n .description(\n 'Regex search across all spans of one trace. Returns ' +\n '`{trace_id, hits: SpanMatchRecord[], total_matches, has_more}`. ' +\n '**Iterate `result.hits`, NOT `result.matches`** — the field is ' +\n '`hits`. Each hit has `{span_id, span_name, span_kind, ' +\n 'attribute_path, matched_text, context_before, context_after, ' +\n 'match_offset}`. Bounded regardless of trace size by max_matches ' +\n '(1..500, default 50). If has_more=true, REFINE the regex rather ' +\n 'than blindly raising max_matches.',\n )\n .namespace(NAMESPACE)\n .arg('trace_id', f.string('Real trace id'))\n .arg('regex_pattern', f.string('JS-compatible regex, multiline'))\n .arg('max_matches', f.number('Max records returned, 1..500; default 50').optional())\n .returns(f.json('SearchTraceResult'))\n .handler(async ({ trace_id, regex_pattern, max_matches }) =>\n store.searchTrace({\n trace_id: assertString(trace_id, 'trace_id'),\n regex_pattern: assertRegex(regex_pattern),\n max_matches: assertMaxMatches(max_matches),\n }),\n )\n .build()\n\n const searchSpan = fn('searchSpan')\n .description(\n 'Regex search inside a single span. Use when viewSpans returned ' +\n 'a 16KB-truncated payload and you need to narrow further. ' +\n 'Returns `{trace_id, span_id, hits: SpanMatchRecord[], ' +\n 'total_matches, has_more}` — iterate `result.hits`, NOT ' +\n '`result.matches`.',\n )\n .namespace(NAMESPACE)\n .arg('trace_id', f.string('Real trace id'))\n .arg('span_id', f.string('Real span id within trace'))\n .arg('regex_pattern', f.string('JS-compatible regex, multiline'))\n .arg('max_matches', f.number('Max records, 1..500; default 50').optional())\n .returns(f.json('SearchSpanResult'))\n .handler(async ({ trace_id, span_id, regex_pattern, max_matches }) =>\n store.searchSpan({\n trace_id: assertString(trace_id, 'trace_id'),\n span_id: assertString(span_id, 'span_id'),\n regex_pattern: assertRegex(regex_pattern),\n max_matches: assertMaxMatches(max_matches),\n }),\n )\n .build()\n\n return [\n getDatasetOverview,\n queryTraces,\n countTraces,\n viewTrace,\n viewSpans,\n searchTrace,\n searchSpan,\n ]\n}\n\n/**\n * Convenience: same shape as `buildTraceAnalystTools` but returns the\n * grouped form expected when registering trace tools alongside other\n * agent function modules. */\nexport function traceAnalystFunctionGroup(opts: BuildTraceAnalystToolsOpts): {\n namespace: string\n title: string\n selectionCriteria: string\n description: string\n functions: AxFunction[]\n} {\n return {\n namespace: NAMESPACE,\n title: 'Trace Analysis',\n selectionCriteria: 'Use for any inspection of OTLP-shaped trace data.',\n description:\n 'Discovery → narrow → deep-read tools over a JSONL trace dataset. ' +\n 'Always call getDatasetOverview first.',\n functions: buildTraceAnalystTools(opts),\n }\n}\n\n// ─── Argument validation ─────────────────────────────────────────────\n\nfunction parseFilters(input: unknown): TraceAnalystFilters | undefined {\n if (input == null) return undefined\n if (typeof input !== 'object' || Array.isArray(input)) {\n throw new TypeError(`filters must be an object, got ${typeof input}`)\n }\n const f = input as Record<string, unknown>\n const out: TraceAnalystFilters = {}\n if (typeof f.has_errors === 'boolean') out.has_errors = f.has_errors\n out.service_names = stringArrayOrUndefined(f.service_names, 'service_names')\n out.agent_names = stringArrayOrUndefined(f.agent_names, 'agent_names')\n out.model_names = stringArrayOrUndefined(f.model_names, 'model_names')\n out.tool_names = stringArrayOrUndefined(f.tool_names, 'tool_names')\n if (typeof f.start_time_after === 'string') out.start_time_after = f.start_time_after\n if (typeof f.start_time_before === 'string') out.start_time_before = f.start_time_before\n if (typeof f.regex_pattern === 'string') {\n if (f.regex_pattern.length === 0) {\n throw new TypeError('filters.regex_pattern cannot be empty')\n }\n out.regex_pattern = f.regex_pattern\n }\n return out\n}\n\nfunction stringArrayOrUndefined(v: unknown, label: string): string[] | undefined {\n if (v === undefined || v === null) return undefined\n if (!Array.isArray(v)) throw new TypeError(`${label} must be an array of strings`)\n if (v.some((x) => typeof x !== 'string')) {\n throw new TypeError(`${label} entries must be strings`)\n }\n return v as string[]\n}\n\nfunction assertPageLimit(limit: unknown): number {\n if (typeof limit !== 'number' || !Number.isInteger(limit) || limit < 1 || limit > 200) {\n throw new RangeError(`limit must be an integer 1..200`)\n }\n return limit\n}\nfunction assertOffset(offset: unknown): number | undefined {\n if (offset === undefined) return undefined\n if (typeof offset !== 'number' || !Number.isInteger(offset) || offset < 0) {\n throw new RangeError(`offset must be a non-negative integer`)\n }\n return offset\n}\nfunction assertRegex(pattern: unknown): string {\n if (typeof pattern !== 'string' || pattern.length === 0) {\n throw new TypeError(`regex_pattern must be a non-empty string`)\n }\n // Compile-and-discard to fail fast — store will recompile, but we\n // want a deterministic error from the agent's side rather than\n // a downstream exception.\n // eslint-disable-next-line no-new\n new RegExp(pattern, 'm')\n return pattern\n}\nfunction assertMaxMatches(n: unknown): number | undefined {\n if (n === undefined) return undefined\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 1 || n > 500) {\n throw new RangeError(`max_matches must be an integer 1..500`)\n }\n return n\n}\n\nfunction assertString(v: unknown, label: string): string {\n if (typeof v !== 'string' || v.length === 0) {\n throw new TypeError(`${label} must be a non-empty string`)\n }\n return v\n}\n\nfunction assertStringArray(v: unknown, label: string): string[] {\n if (!Array.isArray(v)) throw new TypeError(`${label} must be an array of strings`)\n if (v.some((x) => typeof x !== 'string')) {\n throw new TypeError(`${label} entries must be strings`)\n }\n return v as string[]\n}\n"],"mappings":"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","names":["f","f"]}