@tangle-network/agent-eval 0.135.2 → 0.135.3

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 (31) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/analyst/index.js +1 -1
  3. package/dist/{analyst-LsnNpSkm.js → analyst-j5je5J7c.js} +2 -2
  4. package/dist/{analyst-LsnNpSkm.js.map → analyst-j5je5J7c.js.map} +1 -1
  5. package/dist/benchmarks/index.js +1 -1
  6. package/dist/{benchmarks-Mtu251Jz.js → benchmarks-Dfgm9ts5.js} +2 -2
  7. package/dist/{benchmarks-Mtu251Jz.js.map → benchmarks-Dfgm9ts5.js.map} +1 -1
  8. package/dist/campaign/index.js +1 -1
  9. package/dist/{campaign-RVIqtJh0.js → campaign-Dz8uQnhC.js} +2 -2
  10. package/dist/{campaign-RVIqtJh0.js.map → campaign-Dz8uQnhC.js.map} +1 -1
  11. package/dist/contract/index.js +3 -3
  12. package/dist/{default-registry-BAhV-lbE.js → default-registry-CHmdy2An.js} +2 -2
  13. package/dist/{default-registry-BAhV-lbE.js.map → default-registry-CHmdy2An.js.map} +1 -1
  14. package/dist/{extract-usage-2j25whHw.js → extract-usage-DIQpN-ww.js} +2 -2
  15. package/dist/{extract-usage-2j25whHw.js.map → extract-usage-DIQpN-ww.js.map} +1 -1
  16. package/dist/index.d.ts +2 -2
  17. package/dist/index.js +8 -8
  18. package/dist/openapi.json +1 -1
  19. package/dist/{replay-BI6CVKkp.d.ts → replay-BRfMIs81.d.ts} +39 -21
  20. package/dist/replay-BRfMIs81.d.ts.map +1 -0
  21. package/dist/{replay-CJfGLdx4.js → replay-C6wRg47C.js} +23 -41
  22. package/dist/replay-C6wRg47C.js.map +1 -0
  23. package/dist/{tools-BmuN627J.js → tools-D8yTtNSN.js} +132 -27
  24. package/dist/tools-D8yTtNSN.js.map +1 -0
  25. package/dist/traces.d.ts +2 -2
  26. package/dist/traces.js +5 -5
  27. package/docs/trace-analysis.md +24 -0
  28. package/package.json +1 -1
  29. package/dist/replay-BI6CVKkp.d.ts.map +0 -1
  30. package/dist/replay-CJfGLdx4.js.map +0 -1
  31. package/dist/tools-BmuN627J.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { a as NotFoundError } from "./errors-8YnH8WlF.js";
2
- import { INPUT_VALUE, LLM_MODEL_ATTR_KEYS, OUTPUT_VALUE, SPAN_KIND_ATTR_KEYS, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS } from "./trace-attributes.js";
1
+ import { a as NotFoundError, n as CaptureIntegrityError } from "./errors-8YnH8WlF.js";
2
+ import { INPUT_VALUE, LLM_MODEL_ATTR_KEYS, OPENINFERENCE_SPAN_KIND, OUTPUT_VALUE, SPAN_KIND_ATTR_KEYS, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS } from "./trace-attributes.js";
3
3
  import { AxJSRuntime, agent, f, fn } from "@ax-llm/ax";
4
4
  import { readFile, stat } from "node:fs/promises";
5
5
  //#region src/trace/otlp-attributes.ts
@@ -228,6 +228,41 @@ function compareSpanTime(a, b) {
228
228
  return (spanEpochMillis(a) ?? 0) - (spanEpochMillis(b) ?? 0);
229
229
  }
230
230
  //#endregion
231
+ //#region src/trace/otlp-flat.ts
232
+ function createOtlpFlatLine(input) {
233
+ return {
234
+ trace_id: input.traceId,
235
+ span_id: input.spanId,
236
+ parent_span_id: input.parentSpanId,
237
+ name: input.name,
238
+ kind: input.kind,
239
+ start_time: input.startTime,
240
+ end_time: input.endTime,
241
+ status: {
242
+ code: input.statusCode,
243
+ ...input.statusMessage !== void 0 ? { message: input.statusMessage } : {}
244
+ },
245
+ resource: input.resource,
246
+ attributes: input.attributes,
247
+ ...input.events && input.events.length > 0 ? { events: input.events } : {}
248
+ };
249
+ }
250
+ /** Map the canonical trace status while letting each caller choose its legacy default. */
251
+ function spanStatusToOtlp(status, error, defaultCode) {
252
+ if (status === "error" || error) return "STATUS_CODE_ERROR";
253
+ if (status === "ok") return "STATUS_CODE_OK";
254
+ return defaultCode;
255
+ }
256
+ /** Convert epoch milliseconds, returning `undefined` for invalid or out-of-range values. */
257
+ function epochMillisToIso(value) {
258
+ if (!Number.isFinite(value)) return void 0;
259
+ try {
260
+ return new Date(value).toISOString();
261
+ } catch {
262
+ return;
263
+ }
264
+ }
265
+ //#endregion
231
266
  //#region src/trace-analyst/store.ts
232
267
  /** Compile a regex with the same anchoring + flags semantics across
233
268
  * implementations. Throws on invalid pattern — callers should surface
@@ -299,25 +334,20 @@ const INDEX_YIELD_LINES = 5e3;
299
334
  function yieldToEventLoop() {
300
335
  return new Promise((resolve) => setImmediate(resolve));
301
336
  }
302
- var OtlpFileTraceStore = class {
303
- path;
337
+ var BufferedOtlpTraceStore = class {
304
338
  perAttributeViewBudget;
305
339
  perAttributeSpanBudget;
306
340
  perCallByteCeiling;
307
341
  perMatchTextBudget;
308
- maxFileBytes;
309
342
  indexPromise;
310
- /** Cached UTF-8 buffer of the file. We pin it once because every
311
- * read needs slice access and re-reading on each call balloons the
312
- * syscall count. */
343
+ /** Cached UTF-8 buffer. Every read needs slice access, so each source is
344
+ * materialised once. */
313
345
  bufferPromise;
314
346
  constructor(opts) {
315
- this.path = opts.path;
316
347
  this.perAttributeViewBudget = opts.perAttributeViewBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeViewBudget;
317
348
  this.perAttributeSpanBudget = opts.perAttributeSpanBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perAttributeSpanBudget;
318
349
  this.perCallByteCeiling = opts.perCallByteCeiling ?? DEFAULT_TRACE_ANALYST_BUDGETS.perCallByteCeiling;
319
350
  this.perMatchTextBudget = opts.perMatchTextBudget ?? DEFAULT_TRACE_ANALYST_BUDGETS.perMatchTextBudget;
320
- this.maxFileBytes = opts.maxFileBytes ?? 268435456;
321
351
  }
322
352
  async getOverview(filters) {
323
353
  const idx = await this.index();
@@ -497,23 +527,9 @@ var OtlpFileTraceStore = class {
497
527
  await this.index();
498
528
  }
499
529
  async buffer() {
500
- if (!this.bufferPromise) this.bufferPromise = this.readGuarded();
530
+ if (!this.bufferPromise) this.bufferPromise = this.readBuffer();
501
531
  return this.bufferPromise;
502
532
  }
503
- /** Stat-then-read so an oversized file fails loud BEFORE we allocate a
504
- * multi-hundred-MB Buffer and OOM the process. A missing file surfaces
505
- * as TraceFileMissingError; any other stat/read error propagates. */
506
- async readGuarded() {
507
- let stats;
508
- try {
509
- stats = await stat(this.path);
510
- } catch (err) {
511
- if (err?.code === "ENOENT") throw new TraceFileMissingError(this.path);
512
- throw err;
513
- }
514
- if (stats.size > this.maxFileBytes) throw new TraceFileTooLargeError(this.path, stats.size, this.maxFileBytes);
515
- return readFile(this.path);
516
- }
517
533
  async index() {
518
534
  if (!this.indexPromise) this.indexPromise = this.buildIndex();
519
535
  return this.indexPromise;
@@ -752,6 +768,95 @@ var OtlpFileTraceStore = class {
752
768
  };
753
769
  }
754
770
  };
771
+ var OtlpFileTraceStore = class extends BufferedOtlpTraceStore {
772
+ path;
773
+ maxFileBytes;
774
+ constructor(opts) {
775
+ super(opts);
776
+ this.path = opts.path;
777
+ this.maxFileBytes = opts.maxFileBytes ?? 268435456;
778
+ }
779
+ /** Stat-then-read so an oversized file fails loud before allocating the
780
+ * source buffer. Missing files remain distinct from malformed traces. */
781
+ async readBuffer() {
782
+ let stats;
783
+ try {
784
+ stats = await stat(this.path);
785
+ } catch (err) {
786
+ if (err?.code === "ENOENT") throw new TraceFileMissingError(this.path);
787
+ throw err;
788
+ }
789
+ if (stats.size > this.maxFileBytes) throw new TraceFileTooLargeError(this.path, stats.size, this.maxFileBytes);
790
+ return readFile(this.path);
791
+ }
792
+ };
793
+ var OtlpBufferTraceStore = class extends BufferedOtlpTraceStore {
794
+ source;
795
+ constructor(source, opts) {
796
+ super(opts);
797
+ this.source = source;
798
+ }
799
+ async readBuffer() {
800
+ return this.source;
801
+ }
802
+ };
803
+ /** Missing tool spans cannot distinguish a tool-free run from broken capture. */
804
+ var ToolTraceMissingError = class extends CaptureIntegrityError {
805
+ constructor() {
806
+ super("toolSpansToTraceAnalysisStore: no tool spans supplied; trace evidence is missing");
807
+ }
808
+ };
809
+ /**
810
+ * Snapshot canonical tool spans into the bounded read interface used by trace analysts.
811
+ * One `runId` becomes one trace; arguments, results, source attributes, errors, and timing
812
+ * remain queryable through the same OTLP projection as file-backed traces.
813
+ */
814
+ function toolSpansToTraceAnalysisStore(spans, opts = {}) {
815
+ if (!spans || spans.length === 0) throw new ToolTraceMissingError();
816
+ const seen = /* @__PURE__ */ new Set();
817
+ const lines = spans.map((span, index) => {
818
+ assertToolSpanIdentity(span, index);
819
+ const identity = `${span.runId}\u0000${span.spanId}`;
820
+ if (seen.has(identity)) throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: duplicate span '${span.spanId}' in run '${span.runId}'`);
821
+ seen.add(identity);
822
+ const attributes = { ...span.attributes ?? {} };
823
+ applyToolSpanOtlpAttributes(attributes, span);
824
+ attributes[OPENINFERENCE_SPAN_KIND] = "TOOL";
825
+ const endedAt = span.endedAt ?? span.startedAt + (span.latencyMs ?? 0);
826
+ const line = createOtlpFlatLine({
827
+ traceId: span.runId,
828
+ spanId: span.spanId,
829
+ parentSpanId: span.parentSpanId ?? null,
830
+ name: span.name,
831
+ kind: "SPAN_KIND_INTERNAL",
832
+ startTime: toolSpanTimeIso(span.startedAt, span.spanId, "startedAt"),
833
+ endTime: toolSpanTimeIso(endedAt, span.spanId, "endedAt"),
834
+ statusCode: spanStatusToOtlp(span.status, span.error, "STATUS_CODE_UNSET"),
835
+ statusMessage: span.error,
836
+ resource: { attributes: {} },
837
+ attributes
838
+ });
839
+ try {
840
+ return JSON.stringify(line);
841
+ } catch (cause) {
842
+ throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span '${span.spanId}' in run '${span.runId}' is not JSON-serializable`, { cause });
843
+ }
844
+ });
845
+ return new OtlpBufferTraceStore(Buffer.from(`${lines.join("\n")}\n`, "utf8"), opts);
846
+ }
847
+ function assertToolSpanIdentity(span, index) {
848
+ if (span.kind !== "tool") throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span at index ${index} has kind '${String(span.kind)}', not 'tool'`);
849
+ if (!span.runId || !span.spanId || !span.name || !span.toolName) throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span at index ${index} is missing runId, spanId, name, or toolName`);
850
+ if (!Number.isFinite(span.startedAt)) throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid startedAt`);
851
+ if (span.endedAt !== void 0 && !Number.isFinite(span.endedAt)) throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid endedAt`);
852
+ if (span.endedAt !== void 0 && span.endedAt < span.startedAt) throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span '${span.spanId}' ends before it starts`);
853
+ if (span.latencyMs !== void 0 && (!Number.isFinite(span.latencyMs) || span.latencyMs < 0)) throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid latencyMs`);
854
+ }
855
+ function toolSpanTimeIso(value, spanId, field) {
856
+ const iso = epochMillisToIso(value);
857
+ if (iso) return iso;
858
+ throw new CaptureIntegrityError(`toolSpansToTraceAnalysisStore: span '${spanId}' has invalid ${field}`);
859
+ }
755
860
  var TraceFileMissingError = class extends NotFoundError {
756
861
  constructor(path) {
757
862
  super(`trace file not found: ${path}`);
@@ -1080,6 +1185,6 @@ function assertStringArray(v, label) {
1080
1185
  return v;
1081
1186
  }
1082
1187
  //#endregion
1083
- export { traceSpanKindToOpenInferenceKind as S, spanEpochMillis as _, SpanNotFoundError as a, classifyOtlpSpanRole as b, DEFAULT_TRACE_ANALYST_BUDGETS as c, compareSpanTime as d, extractOtlpAttributes as f, readOtlpStatus as g, projectOtlpFlatLine as h, OtlpFileTraceStore as i, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX as l, inferOtlpKind as m, traceAnalystFunctionGroup as n, TraceFileMissingError as o, firstStringAttr as p, runTraceAnalysisLoop as r, TraceNotFoundError as s, buildTraceAnalystTools as t, asString as u, stringField as v, isOtlpModelCall as x, applyToolSpanOtlpAttributes as y };
1188
+ export { stringField as C, traceSpanKindToOpenInferenceKind as D, isOtlpModelCall as E, spanEpochMillis as S, classifyOtlpSpanRole as T, extractOtlpAttributes as _, SpanNotFoundError as a, projectOtlpFlatLine as b, TraceNotFoundError as c, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX as d, createOtlpFlatLine as f, compareSpanTime as g, asString as h, OtlpFileTraceStore as i, toolSpansToTraceAnalysisStore as l, spanStatusToOtlp as m, traceAnalystFunctionGroup as n, ToolTraceMissingError as o, epochMillisToIso as p, runTraceAnalysisLoop as r, TraceFileMissingError as s, buildTraceAnalystTools as t, DEFAULT_TRACE_ANALYST_BUDGETS as u, firstStringAttr as v, applyToolSpanOtlpAttributes as w, readOtlpStatus as x, inferOtlpKind as y };
1084
1189
 
1085
- //# sourceMappingURL=tools-BmuN627J.js.map
1190
+ //# sourceMappingURL=tools-D8yTtNSN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools-D8yTtNSN.js","names":[],"sources":["../src/trace/otlp-attributes.ts","../src/trace-analyst/otlp-span.ts","../src/trace/otlp-flat.ts","../src/trace-analyst/store.ts","../src/trace-analyst/types.ts","../src/trace-analyst/store-otlp.ts","../src/trace-analyst/loop.ts","../src/trace-analyst/tools.ts"],"sourcesContent":["/** Canonical OpenInference-over-OTLP attribute vocabulary used at the trace boundary. */\n\nimport {\n INPUT_VALUE,\n LLM_MODEL_ATTR_KEYS,\n OUTPUT_VALUE,\n SPAN_KIND_ATTR_KEYS,\n TOOL_ARGS_CAPTURED,\n TOOL_LATENCY_MS,\n TOOL_NAME,\n TOOL_NAME_ATTR_KEYS,\n} from './attribute-vocabulary'\nimport type { ToolSpan } from './schema'\n\nexport * from './attribute-vocabulary'\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 type ToolSpanOtlpInput = Pick<\n ToolSpan,\n 'toolName' | 'args' | 'argsCaptured' | 'result' | 'latencyMs'\n>\n\nexport type OtlpSpanRole =\n | 'AGENT'\n | 'CHAIN'\n | 'EVALUATOR'\n | 'GUARDRAIL'\n | 'LLM'\n | 'SPAN'\n | 'TOOL'\n | 'UNKNOWN'\n\nexport interface OtlpSpanRoleInput {\n name: string\n attributes: Record<string, unknown>\n kind?: string | null\n}\n\nconst EXPLICIT_SPAN_ROLES = new Set<OtlpSpanRole>([\n 'AGENT',\n 'CHAIN',\n 'EVALUATOR',\n 'GUARDRAIL',\n 'LLM',\n 'SPAN',\n 'TOOL',\n])\n\n/**\n * Classify a span once for both measurement and error accounting.\n * An explicit OpenInference kind wins; untyped spans use the same tool and\n * model signals in online and offline intake.\n */\nexport function classifyOtlpSpanRole(input: OtlpSpanRoleInput): OtlpSpanRole {\n const explicitKind = input.kind ?? firstStringAttribute(input.attributes, SPAN_KIND_ATTR_KEYS)\n if (explicitKind) {\n const normalized = explicitKind.toUpperCase() as OtlpSpanRole\n if (EXPLICIT_SPAN_ROLES.has(normalized)) return normalized\n }\n\n if (\n firstStringAttribute(input.attributes, TOOL_NAME_ATTR_KEYS) !== undefined ||\n /^(?:function|tool)[.:/]/i.test(input.name)\n ) {\n return 'TOOL'\n }\n\n const spanType = input.attributes['span.type']\n if (\n (typeof spanType === 'string' && spanType.toLowerCase() === 'llm_request') ||\n /(?:^|[.:/_-])(?:chat[._-]?completions?|llm)(?:$|[.:/_-])/i.test(input.name) ||\n firstStringAttribute(input.attributes, LLM_MODEL_ATTR_KEYS) !== undefined ||\n typeof input.attributes['gen_ai.operation.name'] === 'string'\n ) {\n return 'LLM'\n }\n\n return 'UNKNOWN'\n}\n\nexport function isOtlpModelCall(input: OtlpSpanRoleInput): boolean {\n return classifyOtlpSpanRole(input) === 'LLM'\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 'EVALUATOR'\n case 'sandbox':\n return 'CHAIN'\n case 'agent':\n return 'AGENT'\n default:\n return 'SPAN'\n }\n}\n\nfunction firstStringAttribute(\n attributes: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined {\n for (const key of keys) {\n const value = attributes[key]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return undefined\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 rawParentId = stringField(raw, 'parent_span_id') ?? stringField(raw, 'parentSpanId') ?? null\n const parent_id = normalizeParentSpanId(trace_id, span_id, rawParentId)\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\nfunction normalizeParentSpanId(\n traceId: string,\n spanId: string,\n parentId: string | null,\n): string | null {\n if (!parentId) return null\n const prefix = `${traceId}:`\n return spanId.startsWith(prefix) && !parentId.startsWith(prefix)\n ? `${prefix}${parentId}`\n : parentId\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 === 'EVALUATOR' ||\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/** 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","/** Canonical flattened OTLP span shape shared by trace producers and readers. */\n\nimport type { SpanStatus } from './schema'\n\nexport type OtlpStatusCode = 'STATUS_CODE_OK' | 'STATUS_CODE_ERROR' | 'STATUS_CODE_UNSET'\n\nexport interface OtlpFlatLine {\n trace_id: string\n span_id: string\n parent_span_id: string | null\n name: string\n kind: string\n start_time: string\n end_time: string\n status: {\n code: OtlpStatusCode\n message?: string\n }\n resource: { attributes: Record<string, unknown> }\n attributes: Record<string, unknown>\n events?: Array<{ name: string; timeUnixNano?: string; attributes?: Record<string, unknown> }>\n}\n\nexport interface CreateOtlpFlatLineInput {\n traceId: string\n spanId: string\n parentSpanId: string | null\n name: string\n kind: string\n startTime: string\n endTime: string\n statusCode: OtlpStatusCode\n statusMessage?: string\n resource: OtlpFlatLine['resource']\n attributes: Record<string, unknown>\n events?: OtlpFlatLine['events']\n}\n\nexport function createOtlpFlatLine(input: CreateOtlpFlatLineInput): OtlpFlatLine {\n return {\n trace_id: input.traceId,\n span_id: input.spanId,\n parent_span_id: input.parentSpanId,\n name: input.name,\n kind: input.kind,\n start_time: input.startTime,\n end_time: input.endTime,\n status: {\n code: input.statusCode,\n ...(input.statusMessage !== undefined ? { message: input.statusMessage } : {}),\n },\n resource: input.resource,\n attributes: input.attributes,\n ...(input.events && input.events.length > 0 ? { events: input.events } : {}),\n }\n}\n\n/** Map the canonical trace status while letting each caller choose its legacy default. */\nexport function spanStatusToOtlp(\n status: SpanStatus | undefined,\n error: string | undefined,\n defaultCode: OtlpStatusCode,\n): OtlpStatusCode {\n if (status === 'error' || error) return 'STATUS_CODE_ERROR'\n if (status === 'ok') return 'STATUS_CODE_OK'\n return defaultCode\n}\n\n/** Convert epoch milliseconds, returning `undefined` for invalid or out-of-range values. */\nexport function epochMillisToIso(value: number): string | undefined {\n if (!Number.isFinite(value)) return undefined\n try {\n return new Date(value).toISOString()\n } catch {\n return undefined\n }\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 * 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 | 'EVALUATOR'\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 { CaptureIntegrityError, NotFoundError } from '../errors'\nimport { applyToolSpanOtlpAttributes, OPENINFERENCE_SPAN_KIND } from '../trace/otlp-attributes'\nimport { createOtlpFlatLine, epochMillisToIso, spanStatusToOtlp } from '../trace/otlp-flat'\nimport type { ToolSpan } from '../trace/schema'\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 ToolSpansToTraceAnalysisStoreOptions {\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\ntype BufferedOtlpTraceStoreOptions = ToolSpansToTraceAnalysisStoreOptions\n\nexport interface OtlpFileTraceStoreOptions extends BufferedOtlpTraceStoreOptions {\n /** Path to the OTLP-JSONL file. */\n path: string\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\nabstract class BufferedOtlpTraceStore implements TraceAnalysisStore {\n private readonly perAttributeViewBudget: number\n private readonly perAttributeSpanBudget: number\n private readonly perCallByteCeiling: number\n private readonly perMatchTextBudget: number\n private indexPromise?: Promise<DatasetIndex>\n /** Cached UTF-8 buffer. Every read needs slice access, so each source is\n * materialised once. */\n private bufferPromise?: Promise<Buffer>\n\n constructor(opts: BufferedOtlpTraceStoreOptions) {\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 }\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.readBuffer()\n }\n return this.bufferPromise\n }\n\n protected abstract readBuffer(): Promise<Buffer>\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\nexport class OtlpFileTraceStore extends BufferedOtlpTraceStore {\n private readonly path: string\n private readonly maxFileBytes: number\n\n constructor(opts: OtlpFileTraceStoreOptions) {\n super(opts)\n this.path = opts.path\n this.maxFileBytes = opts.maxFileBytes ?? DEFAULT_MAX_TRACE_FILE_BYTES\n }\n\n /** Stat-then-read so an oversized file fails loud before allocating the\n * source buffer. Missing files remain distinct from malformed traces. */\n protected async readBuffer(): 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\nclass OtlpBufferTraceStore extends BufferedOtlpTraceStore {\n constructor(\n private readonly source: Buffer,\n opts: BufferedOtlpTraceStoreOptions,\n ) {\n super(opts)\n }\n\n protected async readBuffer(): Promise<Buffer> {\n return this.source\n }\n}\n\n/** Missing tool spans cannot distinguish a tool-free run from broken capture. */\nexport class ToolTraceMissingError extends CaptureIntegrityError {\n constructor() {\n super('toolSpansToTraceAnalysisStore: no tool spans supplied; trace evidence is missing')\n }\n}\n\n/**\n * Snapshot canonical tool spans into the bounded read interface used by trace analysts.\n * One `runId` becomes one trace; arguments, results, source attributes, errors, and timing\n * remain queryable through the same OTLP projection as file-backed traces.\n */\nexport function toolSpansToTraceAnalysisStore(\n spans: readonly ToolSpan[] | null | undefined,\n opts: ToolSpansToTraceAnalysisStoreOptions = {},\n): TraceAnalysisStore {\n if (!spans || spans.length === 0) throw new ToolTraceMissingError()\n\n const seen = new Set<string>()\n const lines = spans.map((span, index) => {\n assertToolSpanIdentity(span, index)\n const identity = `${span.runId}\\u0000${span.spanId}`\n if (seen.has(identity)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: duplicate span '${span.spanId}' in run '${span.runId}'`,\n )\n }\n seen.add(identity)\n\n const attributes = { ...(span.attributes ?? {}) }\n applyToolSpanOtlpAttributes(attributes, span)\n attributes[OPENINFERENCE_SPAN_KIND] = 'TOOL'\n\n const endedAt = span.endedAt ?? span.startedAt + (span.latencyMs ?? 0)\n const line = createOtlpFlatLine({\n traceId: span.runId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId ?? null,\n name: span.name,\n kind: 'SPAN_KIND_INTERNAL',\n startTime: toolSpanTimeIso(span.startedAt, span.spanId, 'startedAt'),\n endTime: toolSpanTimeIso(endedAt, span.spanId, 'endedAt'),\n statusCode: spanStatusToOtlp(span.status, span.error, 'STATUS_CODE_UNSET'),\n statusMessage: span.error,\n resource: { attributes: {} },\n attributes,\n })\n try {\n return JSON.stringify(line)\n } catch (cause) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' in run '${span.runId}' is not JSON-serializable`,\n { cause },\n )\n }\n })\n\n return new OtlpBufferTraceStore(Buffer.from(`${lines.join('\\n')}\\n`, 'utf8'), opts)\n}\n\nfunction assertToolSpanIdentity(span: ToolSpan, index: number): void {\n if (span.kind !== 'tool') {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span at index ${index} has kind '${String(span.kind)}', not 'tool'`,\n )\n }\n if (!span.runId || !span.spanId || !span.name || !span.toolName) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span at index ${index} is missing runId, spanId, name, or toolName`,\n )\n }\n if (!Number.isFinite(span.startedAt)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid startedAt`,\n )\n }\n if (span.endedAt !== undefined && !Number.isFinite(span.endedAt)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid endedAt`,\n )\n }\n if (span.endedAt !== undefined && span.endedAt < span.startedAt) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' ends before it starts`,\n )\n }\n if (span.latencyMs !== undefined && (!Number.isFinite(span.latencyMs) || span.latencyMs < 0)) {\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${span.spanId}' has invalid latencyMs`,\n )\n }\n}\n\nfunction toolSpanTimeIso(value: number, spanId: string, field: string): string {\n const iso = epochMillisToIso(value)\n if (iso) return iso\n throw new CaptureIntegrityError(\n `toolSpansToTraceAnalysisStore: span '${spanId}' has invalid ${field}`,\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","import {\n type AxAgentActorTurnCallback,\n type AxAIService,\n type AxFunction,\n AxJSRuntime,\n agent,\n} from '@ax-llm/ax'\nimport { TraceFileMissingError } from './store-otlp'\n\nexport const TRACE_ANALYSIS_FINAL_TASK = 'Submit the completed trace analysis.'\n\nconst TRACE_ANALYSIS_COMPLETION_INSTRUCTION = `This host consumes your executor result directly; there is no downstream responder for this run. Ignore generic executor guidance that says a responder will format the answer. You must produce the final report and findings yourself.\n\nReturn exactly one executable JavaScript program per turn. Never emit multiple JavaScript or code fences; put every tool call and the final call in that one program.\n\nWhen the analysis is complete, call \\`await final(${JSON.stringify(TRACE_ANALYSIS_FINAL_TASK)}, { report, findings })\\` exactly once. Do not return a one-argument string from \\`final(...)\\`.`\n\nexport class TraceAnalysisTurnLimitError extends Error {\n readonly analystId: string\n readonly maxTurns: number\n\n constructor(analystId: string, maxTurns: number, cause: unknown) {\n super(\n `Trace analyst '${analystId}' reached maxTurns=${maxTurns} without a structured final result`,\n { cause },\n )\n this.name = 'TraceAnalysisTurnLimitError'\n this.analystId = analystId\n this.maxTurns = maxTurns\n }\n}\n\nexport interface TraceAnalysisLoopResult<TFinding> {\n report: string\n findings: TFinding[]\n usage: readonly unknown[]\n chatLog: readonly unknown[]\n turnCount: number\n}\n\ninterface TraceAnalysisLoopOptions {\n id: string\n description: string\n prompt: string\n question: string\n ai: AxAIService\n model?: string\n tools: readonly AxFunction[]\n maxSubqueries: number\n maxParallelSubqueries: number\n maxTurns: number\n maxRuntimeChars: number\n signal?: AbortSignal\n onTurn?: AxAgentActorTurnCallback\n}\n\nexport function runTraceAnalysisLoop(\n options: TraceAnalysisLoopOptions & { findingType: 'string' },\n): Promise<TraceAnalysisLoopResult<string>>\nexport function runTraceAnalysisLoop(\n options: TraceAnalysisLoopOptions & { findingType: 'object' },\n): Promise<TraceAnalysisLoopResult<Record<string, unknown>>>\nexport async function runTraceAnalysisLoop(\n options: TraceAnalysisLoopOptions & { findingType: 'string' | 'object' },\n): Promise<TraceAnalysisLoopResult<string | Record<string, unknown>>> {\n validateLoopLimits(options)\n\n const config = {\n agentIdentity: { name: options.id, description: options.description },\n contextFields: [] as const,\n runtime: new AxJSRuntime({\n permissions: [],\n blockDynamicImport: true,\n allowedModules: [],\n freezeIntrinsics: true,\n blockShadowRealm: true,\n preventGlobalThisExtensions: false,\n }),\n maxSubAgentCalls: options.maxSubqueries,\n maxTurns: options.maxTurns,\n maxRuntimeChars: options.maxRuntimeChars,\n maxBatchedLlmQueryConcurrency: options.maxParallelSubqueries,\n promptLevel: 'detailed' as const,\n contextPolicy: { preset: 'full' as const, budget: 'balanced' as const },\n functions: options.tools,\n executorOptions: {\n description: `${options.prompt.trim()}\\n\\n${TRACE_ANALYSIS_COMPLETION_INSTRUCTION}`,\n ...(options.model ? { model: options.model } : {}),\n showThoughts: false,\n thinkingTokenBudget: 'none' as const,\n },\n ...(options.onTurn ? { actorTurnCallback: options.onTurn } : {}),\n bubbleErrors: [TraceFileMissingError],\n }\n const analyst =\n options.findingType === 'string'\n ? agent('question:string -> report:string, findings:string[]', config)\n : agent('question:string -> report:string, findings:json[]', config)\n\n const state = await analyst.executor.run(\n options.ai,\n { question: options.question },\n options.signal ? { abortSignal: options.signal } : undefined,\n )\n\n let completed: CompletedTraceAnalysis<string | Record<string, unknown>>\n try {\n completed =\n options.findingType === 'string'\n ? readTraceAnalysisCompletion(state.executorResult, 'string')\n : readTraceAnalysisCompletion(state.executorResult, 'object')\n } catch (error) {\n if (state.turnCount >= options.maxTurns) {\n throw new TraceAnalysisTurnLimitError(options.id, options.maxTurns, error)\n }\n throw new Error(`Trace analyst '${options.id}' stopped without a structured final result`, {\n cause: error,\n })\n }\n\n return {\n ...completed,\n usage: analyst.executor.getUsage(),\n chatLog: analyst.executor.getChatLog(),\n turnCount: state.turnCount,\n }\n}\n\ninterface CompletedTraceAnalysis<TFinding> {\n report: string\n findings: TFinding[]\n}\n\nexport function readTraceAnalysisCompletion(\n value: unknown,\n findingType: 'string',\n): CompletedTraceAnalysis<string>\nexport function readTraceAnalysisCompletion(\n value: unknown,\n findingType: 'object',\n): CompletedTraceAnalysis<Record<string, unknown>>\nexport function readTraceAnalysisCompletion(\n value: unknown,\n findingType: 'string' | 'object',\n): CompletedTraceAnalysis<string | Record<string, unknown>> {\n if (!value || typeof value !== 'object') {\n throw new Error('Trace analyst did not return a structured final result')\n }\n const completion = value as { type?: unknown; args?: unknown }\n if (\n completion.type !== 'final' ||\n !Array.isArray(completion.args) ||\n completion.args.length !== 2 ||\n completion.args[0] !== TRACE_ANALYSIS_FINAL_TASK\n ) {\n throw new Error('Trace analyst did not return a structured final result')\n }\n\n const payload = completion.args[1]\n if (!payload || typeof payload !== 'object') {\n throw new Error('Trace analyst final result must contain report and findings')\n }\n const { report, findings } = payload as { report?: unknown; findings?: unknown }\n if (typeof report !== 'string' || !Array.isArray(findings)) {\n throw new Error('Trace analyst final result must contain report and findings')\n }\n if (findingType === 'string') {\n if (findings.some((finding) => typeof finding !== 'string')) {\n throw new Error('Trace analyst final result must contain string findings')\n }\n return { report, findings: findings as string[] }\n }\n if (\n findings.some((finding) => !finding || typeof finding !== 'object' || Array.isArray(finding))\n ) {\n throw new Error('Trace analyst final result must contain object findings')\n }\n return { report, findings: findings as Record<string, unknown>[] }\n}\n\nfunction validateLoopLimits(options: TraceAnalysisLoopOptions): void {\n if (!Number.isSafeInteger(options.maxSubqueries) || options.maxSubqueries < 0) {\n throw new TypeError('maxSubqueries must be a non-negative integer')\n }\n if (!Number.isSafeInteger(options.maxParallelSubqueries) || options.maxParallelSubqueries < 1) {\n throw new TypeError('maxParallelSubqueries must be a positive integer')\n }\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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"}
package/dist/traces.d.ts CHANGED
@@ -4,9 +4,9 @@ import { a as NoopRawProviderSink, c as RawProviderEvent, d as defaultProviderRe
4
4
  import { a as RunFilter, i as InMemoryTraceStore, n as FileSystemTraceStore, o as SpanFilter, r as FileSystemTraceStoreOptions, s as TraceStore, t as EventFilter } from "./store-CT9YIIve.js";
5
5
  import { a as TraceEmitterOptions, i as TraceEmitter, n as RunCompleteHookContext, o as llmSpanFromProvider, r as SpanHandle, t as RunCompleteHook } from "./emitter-DGQGoLyj.js";
6
6
  import { a as RunIntegrityReport, i as RunIntegrityIssueCode, n as RunIntegrityExpectations, o as assertRunCaptured, r as RunIntegrityIssue, s as throwIfRunIncomplete, t as RunIntegrityError } from "./integrity-rmVhXWA7.js";
7
- import { $ as TraceAnalystHookOptions, A as readOtlpStatus, B as TraceInsightQuestion, C as otlpToTraceRunRecords, Ct as traceSpanKindToOpenInferenceKind, D as firstStringAttr, Dt as OtlpSpan, E as extractOtlpAttributes, Et as OtlpResourceSpans, F as TraceInsightContext, G as buildTraceInsightPrompt, H as TraceInsightSuite, I as TraceInsightFinding, J as domainEvidencePattern, K as defaultTraceInsightPanel, L as TraceInsightPanelRole, M as FlattenOtlpOptions, N as OtlpFlatLine, O as inferOtlpKind, Ot as exportRunAsOtlp, P as flattenOtlpExportToNdjson, Q as tokenizeDomainWords, R as TraceInsightPromptInput, S as otlpToRunRecords, St as isOtlpModelCall, T as asString, Tt as OtlpExport, U as TraceInsightTask, V as TraceInsightReadiness, W as buildTraceInsightContext, X as planTraceInsightQuestions, Y as inferDomainKeywords, Z as scoreTraceInsightReadiness, _ as OtlpToRunRecordsOptions, _t as OtlpSpanRole, a as ReplayFetchOptions, at as DEFAULT_REDACTION_RULES, b as otlpRowsToRunRecords, bt as applyToolSpanOtlpAttributes, c as buildTraceAnalystTools, ct as RedactionRule, d as OtlpFileTraceStoreOptions, dt as createOtelTracingStore, et as traceAnalystOnRunComplete, f as SpanNotFoundError, ft as otelRunCompleteHook, g as TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, gt as createOtelExporter, h as TRACE_ANALYST_ACTOR_DESCRIPTION, ht as OtelExporter, i as ReplayCacheStats, it as convertTraceStoresToOtlp, j as stringField, k as projectOtlpFlatLine, l as traceAnalystFunctionGroup, lt as redactString, m as TraceNotFoundError, mt as OtelExportConfig, n as ReplayCacheEntry, nt as TraceStoreToOtlpOptions, o as createReplayFetch, ot as REDACTION_VERSION, p as TraceFileMissingError, pt as ExportableSpan, q as describeTraceInsightScope, r as ReplayCacheMissError, rt as TracesToOtlpResult, s as iterateRawCalls, st as RedactionReport, t as ReplayCache, tt as TraceStoreSource, u as OtlpFileTraceStore, ut as redactValue, v as OtlpTraceRunRecord, vt as OtlpSpanRoleInput, w as ProjectedOtlpSpan, wt as OTEL_AGENT_EVAL_SCOPE, x as otlpRowsToTraceRunRecords, xt as classifyOtlpSpanRole, y as TraceAggregate, yt as ToolSpanOtlpInput, z as TraceInsightQualityGate } from "./replay-BI6CVKkp.js";
7
+ import { $ as planTraceInsightQuestions, A as firstStringAttr, At as OtlpSpan, B as TraceInsightPanelRole, C as otlpRowsToRunRecords, Ct as applyToolSpanOtlpAttributes, D as ProjectedOtlpSpan, Dt as OTEL_AGENT_EVAL_SCOPE, E as otlpToTraceRunRecords, Et as traceSpanKindToOpenInferenceKind, F as FlattenOtlpOptions, G as TraceInsightSuite, H as TraceInsightQualityGate, I as flattenOtlpExportToNdjson, J as buildTraceInsightPrompt, K as TraceInsightTask, L as OtlpFlatLine, M as projectOtlpFlatLine, N as readOtlpStatus, O as asString, Ot as OtlpExport, P as stringField, Q as inferDomainKeywords, R as TraceInsightContext, S as TraceAggregate, St as ToolSpanOtlpInput, T as otlpToRunRecords, Tt as isOtlpModelCall, U as TraceInsightQuestion, V as TraceInsightPromptInput, W as TraceInsightReadiness, X as describeTraceInsightScope, Y as defaultTraceInsightPanel, Z as domainEvidencePattern, _ as toolSpansToTraceAnalysisStore, _t as OtelExportConfig, a as ReplayFetchOptions, at as TraceStoreToOtlpOptions, b as OtlpToRunRecordsOptions, bt as OtlpSpanRole, c as buildTraceAnalystTools, ct as DEFAULT_REDACTION_RULES, d as OtlpFileTraceStoreOptions, dt as RedactionRule, et as scoreTraceInsightReadiness, f as SpanNotFoundError, ft as redactString, g as TraceNotFoundError, gt as ExportableSpan, h as TraceFileMissingError, ht as otelRunCompleteHook, i as ReplayCacheStats, it as TraceStoreSource, j as inferOtlpKind, jt as exportRunAsOtlp, k as extractOtlpAttributes, kt as OtlpResourceSpans, l as traceAnalystFunctionGroup, lt as REDACTION_VERSION, m as ToolTraceMissingError, mt as createOtelTracingStore, n as ReplayCacheEntry, nt as TraceAnalystHookOptions, o as createReplayFetch, ot as TracesToOtlpResult, p as ToolSpansToTraceAnalysisStoreOptions, pt as redactValue, q as buildTraceInsightContext, r as ReplayCacheMissError, rt as traceAnalystOnRunComplete, s as iterateRawCalls, st as convertTraceStoresToOtlp, t as ReplayCache, tt as tokenizeDomainWords, u as OtlpFileTraceStore, ut as RedactionReport, v as TRACE_ANALYST_ACTOR_DESCRIPTION, vt as OtelExporter, w as otlpRowsToTraceRunRecords, wt as classifyOtlpSpanRole, x as OtlpTraceRunRecord, xt as OtlpSpanRoleInput, y as TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, yt as createOtelExporter, z as TraceInsightFinding } from "./replay-BRfMIs81.js";
8
8
  import { C as TOOL_LATENCY_MS, D as asNumber, E as applyLlmSpanOtlpAttributes, O as contextInputTokens, S as TOOL_ARGS_CAPTURED, T as TOOL_NAME_ATTR_KEYS, _ as LlmSpanOtlpInput, a as LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, b as RUN_COST_ATTR_KEYS, c as LLM_COST_USD, d as LLM_MODEL_ATTR_KEYS, f as LLM_MODEL_NAME, g as LLM_REASONING_TOKEN_ATTR_KEYS, h as LLM_REASONING_TOKENS, i as LLM_CACHE_WRITE_TOKENS, k as firstNumberAttr, l as LLM_INPUT_TOKENS, m as LLM_OUTPUT_TOKEN_ATTR_KEYS, n as LLM_CACHED_TOKENS, o as LLM_CONTEXT_TOKENS, p as LLM_OUTPUT_TOKENS, r as LLM_CACHED_TOKEN_ATTR_KEYS, s as LLM_COST_ATTR_KEYS, t as INPUT_VALUE, u as LLM_INPUT_TOKEN_ATTR_KEYS, v as OPENINFERENCE_SPAN_KIND, w as TOOL_NAME, x as SPAN_KIND_ATTR_KEYS, y as OUTPUT_VALUE } from "./attribute-vocabulary-DLJ6303h.js";
9
9
  import { a as judgeSpans, c as runsForScenario, i as hasCapturedToolArgs, l as toolSpans, n as argHash, o as llmSpans, r as groupBy, s as runFailureClass, t as aggregateLlm } from "./query-CJ_DX8vl.js";
10
10
  import { _ as ViewTraceOversized, a as QueryTracesPage, c as SpanMatchRecord, d as TraceAnalystFilters, f as TraceAnalystSpan, g as ViewSpansResult, h as TraceAnalystTraceSummary, i as ErrorCluster, l as TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, m as TraceAnalystSpanStatus, n as DEFAULT_TRACE_ANALYST_BUDGETS, o as SearchSpanResult, p as TraceAnalystSpanKind, r as DatasetOverview, s as SearchTraceResult, t as TraceAnalysisStore, u as TraceAnalystByteBudgets, v as ViewTraceResult } from "./store-CxJry_cs.js";
11
11
  import { a as analyzeTraces, i as AnalyzeTracesTurnSnapshot, n as AnalyzeTracesOptions, r as AnalyzeTracesResult, t as AnalyzeTracesInput } from "./analyst-BkTS3C58.js";
12
- export { type AnalyzeTracesInput, type AnalyzeTracesOptions, type AnalyzeTracesResult, type AnalyzeTracesTurnSnapshot, Artifact, BudgetLedgerEntry, BudgetSpec, CaptureFetchContext, CaptureFetchOptions, DEFAULT_REDACTION_RULES, DEFAULT_TRACE_ANALYST_BUDGETS, type DatasetOverview, type ErrorCluster, EventFilter, EventKind, ExportableSpan, ExtractUsageFromSseOptions, ExtractedUsage, FAILURE_CLASSES, FailureClass, FileSystemRawProviderSink, FileSystemRawProviderSinkOptions, FileSystemTraceStore, FileSystemTraceStoreOptions, type FlattenOtlpOptions, GenericSpan, INPUT_VALUE, InMemoryRawProviderSink, InMemoryRawProviderSinkOptions, InMemoryTraceStore, JudgeSpan, LLM_CACHED_TOKENS, LLM_CACHED_TOKEN_ATTR_KEYS, LLM_CACHE_WRITE_TOKENS, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, LLM_CONTEXT_TOKENS, LLM_COST_ATTR_KEYS, LLM_COST_USD, LLM_INPUT_TOKENS, LLM_INPUT_TOKEN_ATTR_KEYS, LLM_MODEL_ATTR_KEYS, LLM_MODEL_NAME, LLM_OUTPUT_TOKENS, LLM_OUTPUT_TOKEN_ATTR_KEYS, LLM_REASONING_TOKENS, LLM_REASONING_TOKEN_ATTR_KEYS, LlmSpan, LlmSpanOtlpInput, Message, NoopRawProviderSink, OPENINFERENCE_SPAN_KIND, OTEL_AGENT_EVAL_SCOPE, OUTPUT_VALUE, OtelExportConfig, OtelExporter, OtlpExport, OtlpFileTraceStore, type OtlpFileTraceStoreOptions, type OtlpFlatLine, OtlpResourceSpans, OtlpSpan, OtlpSpanRole, OtlpSpanRoleInput, type OtlpToRunRecordsOptions, type OtlpTraceRunRecord, type ProjectedOtlpSpan, ProviderRedactor, type QueryTracesPage, REDACTION_VERSION, RUN_COST_ATTR_KEYS, RawProviderDirection, RawProviderEvent, RawProviderSink, RawProviderSinkFilter, RedactionReport, RedactionRule, ReplayCache, ReplayCacheEntry, ReplayCacheMissError, ReplayCacheStats, ReplayFetchOptions, RetrievalSpan, Run, RunCompleteHook, RunCompleteHookContext, RunFilter, RunIntegrityError, RunIntegrityExpectations, RunIntegrityIssue, RunIntegrityIssueCode, RunIntegrityReport, RunLayer, RunOutcome, RunStatus, SPAN_KIND_ATTR_KEYS, SandboxSpan, type SearchSpanResult, type SearchTraceResult, Span, SpanBase, SpanFilter, SpanHandle, SpanKind, type SpanMatchRecord, SpanNotFoundError, SpanStatus, SseUsageMode, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS, TRACE_ANALYST_ACTOR_DESCRIPTION, TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, TRACE_SCHEMA_VERSION, ToolSpan, ToolSpanOtlpInput, type TraceAggregate, type TraceAnalysisStore, type TraceAnalystByteBudgets, type TraceAnalystFilters, type TraceAnalystHookOptions, type TraceAnalystSpan, type TraceAnalystSpanKind, type TraceAnalystSpanStatus, type TraceAnalystTraceSummary, TraceEmitter, TraceEmitterOptions, TraceEvent, TraceFileMissingError, type TraceInsightContext, type TraceInsightFinding, type TraceInsightPanelRole, type TraceInsightPromptInput, type TraceInsightQualityGate, type TraceInsightQuestion, type TraceInsightReadiness, type TraceInsightSuite, type TraceInsightTask, TraceNotFoundError, TraceStore, TraceStoreSource, TraceStoreToOtlpOptions, TracesToOtlpResult, type ViewSpansResult, type ViewTraceOversized, type ViewTraceResult, aggregateLlm, analyzeTraces, applyLlmSpanOtlpAttributes, applyToolSpanOtlpAttributes, argHash, asNumber, asString, assertRunCaptured, buildTraceAnalystTools, buildTraceInsightContext, buildTraceInsightPrompt, captureFetchToRawSink, classifyOtlpSpanRole, contextInputTokens, convertTraceStoresToOtlp, createOtelExporter, createOtelTracingStore, createReplayFetch, defaultProviderRedactor, defaultTraceInsightPanel, describeTraceInsightScope, domainEvidencePattern, exportRunAsOtlp, extractOtlpAttributes, extractUsage, extractUsageFromResponse, extractUsageFromSse, firstNumberAttr, firstStringAttr, flattenOtlpExportToNdjson, groupBy, hasCapturedToolArgs, inferDomainKeywords, inferOtlpKind, isJudgeSpan, isLlmSpan, isOtlpModelCall, isRetrievalSpan, isSandboxSpan, isToolSpan, iterateRawCalls, judgeSpans, llmSpanFromProvider, llmSpans, otelRunCompleteHook, otlpRowsToRunRecords, otlpRowsToTraceRunRecords, otlpToRunRecords, otlpToTraceRunRecords, planTraceInsightQuestions, projectOtlpFlatLine, providerFromBaseUrl, readOtlpStatus, redactString, redactValue, runFailureClass, runsForScenario, scoreTraceInsightReadiness, stringField, throwIfRunIncomplete, tokenizeDomainWords, toolSpans, traceAnalystFunctionGroup, traceAnalystOnRunComplete, traceSpanKindToOpenInferenceKind };
12
+ export { type AnalyzeTracesInput, type AnalyzeTracesOptions, type AnalyzeTracesResult, type AnalyzeTracesTurnSnapshot, Artifact, BudgetLedgerEntry, BudgetSpec, CaptureFetchContext, CaptureFetchOptions, DEFAULT_REDACTION_RULES, DEFAULT_TRACE_ANALYST_BUDGETS, type DatasetOverview, type ErrorCluster, EventFilter, EventKind, ExportableSpan, ExtractUsageFromSseOptions, ExtractedUsage, FAILURE_CLASSES, FailureClass, FileSystemRawProviderSink, FileSystemRawProviderSinkOptions, FileSystemTraceStore, FileSystemTraceStoreOptions, type FlattenOtlpOptions, GenericSpan, INPUT_VALUE, InMemoryRawProviderSink, InMemoryRawProviderSinkOptions, InMemoryTraceStore, JudgeSpan, LLM_CACHED_TOKENS, LLM_CACHED_TOKEN_ATTR_KEYS, LLM_CACHE_WRITE_TOKENS, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, LLM_CONTEXT_TOKENS, LLM_COST_ATTR_KEYS, LLM_COST_USD, LLM_INPUT_TOKENS, LLM_INPUT_TOKEN_ATTR_KEYS, LLM_MODEL_ATTR_KEYS, LLM_MODEL_NAME, LLM_OUTPUT_TOKENS, LLM_OUTPUT_TOKEN_ATTR_KEYS, LLM_REASONING_TOKENS, LLM_REASONING_TOKEN_ATTR_KEYS, LlmSpan, LlmSpanOtlpInput, Message, NoopRawProviderSink, OPENINFERENCE_SPAN_KIND, OTEL_AGENT_EVAL_SCOPE, OUTPUT_VALUE, OtelExportConfig, OtelExporter, OtlpExport, OtlpFileTraceStore, type OtlpFileTraceStoreOptions, type OtlpFlatLine, OtlpResourceSpans, OtlpSpan, OtlpSpanRole, OtlpSpanRoleInput, type OtlpToRunRecordsOptions, type OtlpTraceRunRecord, type ProjectedOtlpSpan, ProviderRedactor, type QueryTracesPage, REDACTION_VERSION, RUN_COST_ATTR_KEYS, RawProviderDirection, RawProviderEvent, RawProviderSink, RawProviderSinkFilter, RedactionReport, RedactionRule, ReplayCache, ReplayCacheEntry, ReplayCacheMissError, ReplayCacheStats, ReplayFetchOptions, RetrievalSpan, Run, RunCompleteHook, RunCompleteHookContext, RunFilter, RunIntegrityError, RunIntegrityExpectations, RunIntegrityIssue, RunIntegrityIssueCode, RunIntegrityReport, RunLayer, RunOutcome, RunStatus, SPAN_KIND_ATTR_KEYS, SandboxSpan, type SearchSpanResult, type SearchTraceResult, Span, SpanBase, SpanFilter, SpanHandle, SpanKind, type SpanMatchRecord, SpanNotFoundError, SpanStatus, SseUsageMode, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS, TRACE_ANALYST_ACTOR_DESCRIPTION, TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, TRACE_SCHEMA_VERSION, ToolSpan, ToolSpanOtlpInput, type ToolSpansToTraceAnalysisStoreOptions, ToolTraceMissingError, type TraceAggregate, type TraceAnalysisStore, type TraceAnalystByteBudgets, type TraceAnalystFilters, type TraceAnalystHookOptions, type TraceAnalystSpan, type TraceAnalystSpanKind, type TraceAnalystSpanStatus, type TraceAnalystTraceSummary, TraceEmitter, TraceEmitterOptions, TraceEvent, TraceFileMissingError, type TraceInsightContext, type TraceInsightFinding, type TraceInsightPanelRole, type TraceInsightPromptInput, type TraceInsightQualityGate, type TraceInsightQuestion, type TraceInsightReadiness, type TraceInsightSuite, type TraceInsightTask, TraceNotFoundError, TraceStore, TraceStoreSource, TraceStoreToOtlpOptions, TracesToOtlpResult, type ViewSpansResult, type ViewTraceOversized, type ViewTraceResult, aggregateLlm, analyzeTraces, applyLlmSpanOtlpAttributes, applyToolSpanOtlpAttributes, argHash, asNumber, asString, assertRunCaptured, buildTraceAnalystTools, buildTraceInsightContext, buildTraceInsightPrompt, captureFetchToRawSink, classifyOtlpSpanRole, contextInputTokens, convertTraceStoresToOtlp, createOtelExporter, createOtelTracingStore, createReplayFetch, defaultProviderRedactor, defaultTraceInsightPanel, describeTraceInsightScope, domainEvidencePattern, exportRunAsOtlp, extractOtlpAttributes, extractUsage, extractUsageFromResponse, extractUsageFromSse, firstNumberAttr, firstStringAttr, flattenOtlpExportToNdjson, groupBy, hasCapturedToolArgs, inferDomainKeywords, inferOtlpKind, isJudgeSpan, isLlmSpan, isOtlpModelCall, isRetrievalSpan, isSandboxSpan, isToolSpan, iterateRawCalls, judgeSpans, llmSpanFromProvider, llmSpans, otelRunCompleteHook, otlpRowsToRunRecords, otlpRowsToTraceRunRecords, otlpToRunRecords, otlpToTraceRunRecords, planTraceInsightQuestions, projectOtlpFlatLine, providerFromBaseUrl, readOtlpStatus, redactString, redactValue, runFailureClass, runsForScenario, scoreTraceInsightReadiness, stringField, throwIfRunIncomplete, tokenizeDomainWords, toolSpans, toolSpansToTraceAnalysisStore, traceAnalystFunctionGroup, traceAnalystOnRunComplete, traceSpanKindToOpenInferenceKind };
package/dist/traces.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { a as providerFromBaseUrl, i as defaultProviderRedactor, n as InMemoryRawProviderSink, r as NoopRawProviderSink, t as FileSystemRawProviderSink } from "./raw-provider-sink-BQd7mzyT.js";
2
2
  import { INPUT_VALUE, LLM_CACHED_TOKENS, LLM_CACHED_TOKEN_ATTR_KEYS, LLM_CACHE_WRITE_TOKENS, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, LLM_CONTEXT_TOKENS, LLM_COST_ATTR_KEYS, LLM_COST_USD, LLM_INPUT_TOKENS, LLM_INPUT_TOKEN_ATTR_KEYS, LLM_MODEL_ATTR_KEYS, LLM_MODEL_NAME, LLM_OUTPUT_TOKENS, LLM_OUTPUT_TOKEN_ATTR_KEYS, LLM_REASONING_TOKENS, LLM_REASONING_TOKEN_ATTR_KEYS, OPENINFERENCE_SPAN_KIND, OUTPUT_VALUE, RUN_COST_ATTR_KEYS, SPAN_KIND_ATTR_KEYS, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS, applyLlmSpanOtlpAttributes, asNumber, contextInputTokens, firstNumberAttr } from "./trace-attributes.js";
3
- import { S as traceSpanKindToOpenInferenceKind, a as SpanNotFoundError, b as classifyOtlpSpanRole, c as DEFAULT_TRACE_ANALYST_BUDGETS, f as extractOtlpAttributes, g as readOtlpStatus, h as projectOtlpFlatLine, i as OtlpFileTraceStore, l as TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, m as inferOtlpKind, n as traceAnalystFunctionGroup, o as TraceFileMissingError, p as firstStringAttr, s as TraceNotFoundError, t as buildTraceAnalystTools, u as asString, v as stringField, x as isOtlpModelCall, y as applyToolSpanOtlpAttributes } from "./tools-BmuN627J.js";
3
+ import { C as stringField, D as traceSpanKindToOpenInferenceKind, E as isOtlpModelCall, T as classifyOtlpSpanRole, _ as extractOtlpAttributes, a as SpanNotFoundError, b as projectOtlpFlatLine, c as TraceNotFoundError, d as TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, h as asString, i as OtlpFileTraceStore, l as toolSpansToTraceAnalysisStore, n as traceAnalystFunctionGroup, o as ToolTraceMissingError, s as TraceFileMissingError, t as buildTraceAnalystTools, u as DEFAULT_TRACE_ANALYST_BUDGETS, v as firstStringAttr, w as applyToolSpanOtlpAttributes, x as readOtlpStatus, y as inferOtlpKind } from "./tools-D8yTtNSN.js";
4
4
  import { n as llmSpanFromProvider, t as TraceEmitter } from "./emitter-CPBAhxum.js";
5
5
  import { a as isRetrievalSpan, i as isLlmSpan, n as TRACE_SCHEMA_VERSION, o as isSandboxSpan, r as isJudgeSpan, s as isToolSpan, t as FAILURE_CLASSES } from "./schema-CRhEY1SO.js";
6
- import { n as TRACE_ANALYST_ACTOR_DESCRIPTION, r as TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, t as analyzeTraces } from "./analyst-LsnNpSkm.js";
7
- import { C as planTraceInsightQuestions, E as traceAnalystOnRunComplete, S as inferDomainKeywords, T as tokenizeDomainWords, _ as buildTraceInsightContext, a as convertTraceStoresToOtlp, b as describeTraceInsightScope, c as otelRunCompleteHook, d as captureFetchToRawSink, f as otlpRowsToRunRecords, g as flattenOtlpExportToNdjson, h as otlpToTraceRunRecords, i as iterateRawCalls, l as OTEL_AGENT_EVAL_SCOPE, m as otlpToRunRecords, n as ReplayCacheMissError, o as createOtelExporter, p as otlpRowsToTraceRunRecords, r as createReplayFetch, s as createOtelTracingStore, t as ReplayCache, u as exportRunAsOtlp, v as buildTraceInsightPrompt, w as scoreTraceInsightReadiness, x as domainEvidencePattern, y as defaultTraceInsightPanel } from "./replay-CJfGLdx4.js";
8
- import { n as extractUsageFromResponse, r as extractUsageFromSse, t as extractUsage } from "./extract-usage-2j25whHw.js";
6
+ import { n as TRACE_ANALYST_ACTOR_DESCRIPTION, r as TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, t as analyzeTraces } from "./analyst-j5je5J7c.js";
7
+ import { C as planTraceInsightQuestions, E as traceAnalystOnRunComplete, S as inferDomainKeywords, T as tokenizeDomainWords, _ as buildTraceInsightContext, a as convertTraceStoresToOtlp, b as describeTraceInsightScope, c as otelRunCompleteHook, d as captureFetchToRawSink, f as otlpRowsToRunRecords, g as flattenOtlpExportToNdjson, h as otlpToTraceRunRecords, i as iterateRawCalls, l as OTEL_AGENT_EVAL_SCOPE, m as otlpToRunRecords, n as ReplayCacheMissError, o as createOtelExporter, p as otlpRowsToTraceRunRecords, r as createReplayFetch, s as createOtelTracingStore, t as ReplayCache, u as exportRunAsOtlp, v as buildTraceInsightPrompt, w as scoreTraceInsightReadiness, x as domainEvidencePattern, y as defaultTraceInsightPanel } from "./replay-C6wRg47C.js";
8
+ import { n as extractUsageFromResponse, r as extractUsageFromSse, t as extractUsage } from "./extract-usage-DIQpN-ww.js";
9
9
  import { a as judgeSpans, c as runsForScenario, i as hasCapturedToolArgs, l as toolSpans, n as argHash, o as llmSpans, r as groupBy, s as runFailureClass, t as aggregateLlm } from "./query-Di7eEQ79.js";
10
10
  import { a as InMemoryTraceStore, i as FileSystemTraceStore, n as assertRunCaptured, r as throwIfRunIncomplete, t as RunIntegrityError } from "./integrity-BzRbCHzi.js";
11
11
  import { i as redactValue, n as REDACTION_VERSION, r as redactString, t as DEFAULT_REDACTION_RULES } from "./redact-7Aq1ukl-.js";
12
- export { DEFAULT_REDACTION_RULES, DEFAULT_TRACE_ANALYST_BUDGETS, FAILURE_CLASSES, FileSystemRawProviderSink, FileSystemTraceStore, INPUT_VALUE, InMemoryRawProviderSink, InMemoryTraceStore, LLM_CACHED_TOKENS, LLM_CACHED_TOKEN_ATTR_KEYS, LLM_CACHE_WRITE_TOKENS, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, LLM_CONTEXT_TOKENS, LLM_COST_ATTR_KEYS, LLM_COST_USD, LLM_INPUT_TOKENS, LLM_INPUT_TOKEN_ATTR_KEYS, LLM_MODEL_ATTR_KEYS, LLM_MODEL_NAME, LLM_OUTPUT_TOKENS, LLM_OUTPUT_TOKEN_ATTR_KEYS, LLM_REASONING_TOKENS, LLM_REASONING_TOKEN_ATTR_KEYS, NoopRawProviderSink, OPENINFERENCE_SPAN_KIND, OTEL_AGENT_EVAL_SCOPE, OUTPUT_VALUE, OtlpFileTraceStore, REDACTION_VERSION, RUN_COST_ATTR_KEYS, ReplayCache, ReplayCacheMissError, RunIntegrityError, SPAN_KIND_ATTR_KEYS, SpanNotFoundError, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS, TRACE_ANALYST_ACTOR_DESCRIPTION, TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, TRACE_SCHEMA_VERSION, TraceEmitter, TraceFileMissingError, TraceNotFoundError, aggregateLlm, analyzeTraces, applyLlmSpanOtlpAttributes, applyToolSpanOtlpAttributes, argHash, asNumber, asString, assertRunCaptured, buildTraceAnalystTools, buildTraceInsightContext, buildTraceInsightPrompt, captureFetchToRawSink, classifyOtlpSpanRole, contextInputTokens, convertTraceStoresToOtlp, createOtelExporter, createOtelTracingStore, createReplayFetch, defaultProviderRedactor, defaultTraceInsightPanel, describeTraceInsightScope, domainEvidencePattern, exportRunAsOtlp, extractOtlpAttributes, extractUsage, extractUsageFromResponse, extractUsageFromSse, firstNumberAttr, firstStringAttr, flattenOtlpExportToNdjson, groupBy, hasCapturedToolArgs, inferDomainKeywords, inferOtlpKind, isJudgeSpan, isLlmSpan, isOtlpModelCall, isRetrievalSpan, isSandboxSpan, isToolSpan, iterateRawCalls, judgeSpans, llmSpanFromProvider, llmSpans, otelRunCompleteHook, otlpRowsToRunRecords, otlpRowsToTraceRunRecords, otlpToRunRecords, otlpToTraceRunRecords, planTraceInsightQuestions, projectOtlpFlatLine, providerFromBaseUrl, readOtlpStatus, redactString, redactValue, runFailureClass, runsForScenario, scoreTraceInsightReadiness, stringField, throwIfRunIncomplete, tokenizeDomainWords, toolSpans, traceAnalystFunctionGroup, traceAnalystOnRunComplete, traceSpanKindToOpenInferenceKind };
12
+ export { DEFAULT_REDACTION_RULES, DEFAULT_TRACE_ANALYST_BUDGETS, FAILURE_CLASSES, FileSystemRawProviderSink, FileSystemTraceStore, INPUT_VALUE, InMemoryRawProviderSink, InMemoryTraceStore, LLM_CACHED_TOKENS, LLM_CACHED_TOKEN_ATTR_KEYS, LLM_CACHE_WRITE_TOKENS, LLM_CACHE_WRITE_TOKEN_ATTR_KEYS, LLM_CONTEXT_TOKENS, LLM_COST_ATTR_KEYS, LLM_COST_USD, LLM_INPUT_TOKENS, LLM_INPUT_TOKEN_ATTR_KEYS, LLM_MODEL_ATTR_KEYS, LLM_MODEL_NAME, LLM_OUTPUT_TOKENS, LLM_OUTPUT_TOKEN_ATTR_KEYS, LLM_REASONING_TOKENS, LLM_REASONING_TOKEN_ATTR_KEYS, NoopRawProviderSink, OPENINFERENCE_SPAN_KIND, OTEL_AGENT_EVAL_SCOPE, OUTPUT_VALUE, OtlpFileTraceStore, REDACTION_VERSION, RUN_COST_ATTR_KEYS, ReplayCache, ReplayCacheMissError, RunIntegrityError, SPAN_KIND_ATTR_KEYS, SpanNotFoundError, TOOL_ARGS_CAPTURED, TOOL_LATENCY_MS, TOOL_NAME, TOOL_NAME_ATTR_KEYS, TRACE_ANALYST_ACTOR_DESCRIPTION, TRACE_ANALYST_ACTOR_DESCRIPTION_VERSION, TRACE_ANALYST_TRUNCATION_MARKER_PREFIX, TRACE_SCHEMA_VERSION, ToolTraceMissingError, TraceEmitter, TraceFileMissingError, TraceNotFoundError, aggregateLlm, analyzeTraces, applyLlmSpanOtlpAttributes, applyToolSpanOtlpAttributes, argHash, asNumber, asString, assertRunCaptured, buildTraceAnalystTools, buildTraceInsightContext, buildTraceInsightPrompt, captureFetchToRawSink, classifyOtlpSpanRole, contextInputTokens, convertTraceStoresToOtlp, createOtelExporter, createOtelTracingStore, createReplayFetch, defaultProviderRedactor, defaultTraceInsightPanel, describeTraceInsightScope, domainEvidencePattern, exportRunAsOtlp, extractOtlpAttributes, extractUsage, extractUsageFromResponse, extractUsageFromSse, firstNumberAttr, firstStringAttr, flattenOtlpExportToNdjson, groupBy, hasCapturedToolArgs, inferDomainKeywords, inferOtlpKind, isJudgeSpan, isLlmSpan, isOtlpModelCall, isRetrievalSpan, isSandboxSpan, isToolSpan, iterateRawCalls, judgeSpans, llmSpanFromProvider, llmSpans, otelRunCompleteHook, otlpRowsToRunRecords, otlpRowsToTraceRunRecords, otlpToRunRecords, otlpToTraceRunRecords, planTraceInsightQuestions, projectOtlpFlatLine, providerFromBaseUrl, readOtlpStatus, redactString, redactValue, runFailureClass, runsForScenario, scoreTraceInsightReadiness, stringField, throwIfRunIncomplete, tokenizeDomainWords, toolSpans, toolSpansToTraceAnalysisStore, traceAnalystFunctionGroup, traceAnalystOnRunComplete, traceSpanKindToOpenInferenceKind };
@@ -48,6 +48,30 @@ console.log(result.findings)
48
48
  Products can pass any `TraceAnalysisStore`; they do not need to use the file store in production.
49
49
  The analyst runs one Ax executor loop and accepts only an explicit structured `final(task, { report, findings })` result; max-turn fallback text fails loud.
50
50
 
51
+ ### Analyze captured tool spans in memory
52
+
53
+ Use `toolSpansToTraceAnalysisStore()` when a live worker already returns canonical `ToolSpan[]` records.
54
+ The function snapshots the records immediately, groups them by `runId`, and exposes the same bounded reads and searches as the file-backed store.
55
+
56
+ ```ts
57
+ import {
58
+ analyzeTraces,
59
+ toolSpansToTraceAnalysisStore,
60
+ type ToolSpan,
61
+ ToolTraceMissingError,
62
+ } from '@tangle-network/agent-eval/traces'
63
+
64
+ declare const capturedToolSpans: ToolSpan[] | undefined
65
+
66
+ if (!capturedToolSpans?.length) throw new ToolTraceMissingError()
67
+ const source = toolSpansToTraceAnalysisStore(capturedToolSpans)
68
+ const result = await analyzeTraces({ question: 'Why are tools failing?' }, { source, ai, model })
69
+ ```
70
+
71
+ `undefined`, `null`, and an empty array throw `ToolTraceMissingError` with code `capture_integrity`.
72
+ An empty tool list cannot distinguish a real tool-free run from broken capture, so the adapter never reports it as a clean trace set.
73
+ Use a complete OTLP trace source when proving that a run executed successfully without tools.
74
+
51
75
  ## Deterministic failure coverage (no LLM)
52
76
 
53
77
  Before (or alongside) the LLM analyst, `OtlpFileTraceStore.getOverview()` returns a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-eval",
3
- "version": "0.135.2",
3
+ "version": "0.135.3",
4
4
  "description": "Evaluate and improve AI agents from runs, traces, judges, and feedback. Compare candidates, cluster failures, measure lift, and gate releases.",
5
5
  "homepage": "https://github.com/tangle-network/agent-eval#readme",
6
6
  "repository": {