agent-inspect 6.31.6 → 6.31.7

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 (35) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +1 -1
  3. package/docs/AI-SDK-ADOPTION.md +62 -34
  4. package/package.json +1 -1
  5. package/packages/cli/dist/{chunk-YXDNWHNJ.mjs → chunk-QV73NM25.mjs} +97 -25
  6. package/packages/cli/dist/chunk-QV73NM25.mjs.map +1 -0
  7. package/packages/cli/dist/index.cjs +414 -81
  8. package/packages/cli/dist/index.cjs.map +1 -1
  9. package/packages/cli/dist/index.mjs +322 -62
  10. package/packages/cli/dist/index.mjs.map +1 -1
  11. package/packages/cli/dist/{src-H22KNWAZ.mjs → src-KFOBXFPN.mjs} +3 -3
  12. package/packages/cli/dist/{src-H22KNWAZ.mjs.map → src-KFOBXFPN.mjs.map} +1 -1
  13. package/packages/core/dist/advanced.cjs +94 -22
  14. package/packages/core/dist/advanced.cjs.map +1 -1
  15. package/packages/core/dist/advanced.mjs +4 -4
  16. package/packages/core/dist/{chunk-OSGNGRHF.mjs → chunk-3RV3JILQ.mjs} +34 -16
  17. package/packages/core/dist/chunk-3RV3JILQ.mjs.map +1 -0
  18. package/packages/core/dist/{chunk-EXGQLMVB.mjs → chunk-7YYS742B.mjs} +49 -12
  19. package/packages/core/dist/chunk-7YYS742B.mjs.map +1 -0
  20. package/packages/core/dist/{chunk-Q5SLKV2Y.mjs → chunk-QLYUWKK7.mjs} +19 -2
  21. package/packages/core/dist/chunk-QLYUWKK7.mjs.map +1 -0
  22. package/packages/core/dist/exporters.cjs +224 -47
  23. package/packages/core/dist/exporters.cjs.map +1 -1
  24. package/packages/core/dist/exporters.mjs +178 -38
  25. package/packages/core/dist/exporters.mjs.map +1 -1
  26. package/packages/core/dist/persisted.cjs +17 -0
  27. package/packages/core/dist/persisted.cjs.map +1 -1
  28. package/packages/core/dist/persisted.mjs +2 -2
  29. package/packages/core/dist/readers.cjs +48 -13
  30. package/packages/core/dist/readers.cjs.map +1 -1
  31. package/packages/core/dist/readers.mjs +2 -2
  32. package/packages/cli/dist/chunk-YXDNWHNJ.mjs.map +0 -1
  33. package/packages/core/dist/chunk-EXGQLMVB.mjs.map +0 -1
  34. package/packages/core/dist/chunk-OSGNGRHF.mjs.map +0 -1
  35. package/packages/core/dist/chunk-Q5SLKV2Y.mjs.map +0 -1
@@ -2690,16 +2690,51 @@ function buildRunTimeline(events, options = {}) {
2690
2690
  const computeDepth = (stepId) => {
2691
2691
  const cached2 = depthCache.get(stepId);
2692
2692
  if (cached2 !== void 0) return cached2;
2693
- const node = steps.get(stepId);
2694
- if (!node) return 0;
2695
- const parent = node.parentId;
2696
- if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
2697
- depthCache.set(stepId, 0);
2698
- return 0;
2693
+ const ancestry = [];
2694
+ const ancestryIndexes = /* @__PURE__ */ new Map();
2695
+ let currentStepId = stepId;
2696
+ let resolvedDepth;
2697
+ while (resolvedDepth === void 0) {
2698
+ const cachedDepth = depthCache.get(currentStepId);
2699
+ if (cachedDepth !== void 0) {
2700
+ resolvedDepth = cachedDepth;
2701
+ continue;
2702
+ }
2703
+ const cycleStart = ancestryIndexes.get(currentStepId);
2704
+ if (cycleStart !== void 0) {
2705
+ const cycleStepIds = ancestry.splice(cycleStart);
2706
+ for (const cycleStepId of cycleStepIds) {
2707
+ depthCache.set(cycleStepId, ROOT_TIMELINE_DEPTH);
2708
+ }
2709
+ resolvedDepth = ROOT_TIMELINE_DEPTH;
2710
+ continue;
2711
+ }
2712
+ const currentStep = steps.get(currentStepId);
2713
+ if (!currentStep) {
2714
+ resolvedDepth = ROOT_TIMELINE_DEPTH;
2715
+ continue;
2716
+ }
2717
+ ancestryIndexes.set(currentStepId, ancestry.length);
2718
+ ancestry.push(currentStepId);
2719
+ const parentId = currentStep.parentId;
2720
+ if (typeof parentId !== "string" || parentId.trim() === "" || !steps.has(parentId)) {
2721
+ ancestry.pop();
2722
+ depthCache.set(currentStepId, ROOT_TIMELINE_DEPTH);
2723
+ resolvedDepth = ROOT_TIMELINE_DEPTH;
2724
+ continue;
2725
+ }
2726
+ currentStepId = parentId;
2699
2727
  }
2700
- const d = Math.min(1e3, computeDepth(parent) + 1);
2701
- depthCache.set(stepId, d);
2702
- return d;
2728
+ ancestry.reverse();
2729
+ for (const ancestorStepId of ancestry) {
2730
+ resolvedDepth = Math.min(MAX_TIMELINE_DEPTH, resolvedDepth + 1);
2731
+ depthCache.set(ancestorStepId, resolvedDepth);
2732
+ }
2733
+ const resolvedStepDepth = depthCache.get(stepId);
2734
+ if (resolvedStepDepth === void 0) {
2735
+ throw new Error(`Failed to resolve timeline depth for step "${stepId}"`);
2736
+ }
2737
+ return resolvedStepDepth;
2703
2738
  };
2704
2739
  const entries = [];
2705
2740
  for (const [stepId, s] of steps.entries()) {
@@ -2787,10 +2822,13 @@ function renderTimeline(timeline, options = {}) {
2787
2822
  }
2788
2823
  return lines.join("\n");
2789
2824
  }
2825
+ var ROOT_TIMELINE_DEPTH, MAX_TIMELINE_DEPTH;
2790
2826
  var init_timeline = __esm({
2791
2827
  "packages/core/src/timeline.ts"() {
2792
2828
  init_stats();
2793
2829
  init_utils();
2830
+ ROOT_TIMELINE_DEPTH = 0;
2831
+ MAX_TIMELINE_DEPTH = 1e3;
2794
2832
  }
2795
2833
  });
2796
2834
 
@@ -12540,6 +12578,23 @@ function persistedInspectEventToInspectEvent(event) {
12540
12578
  if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0) {
12541
12579
  out.durationMs = event.durationMs;
12542
12580
  }
12581
+ if (event.startedAt !== void 0) {
12582
+ const started = parseIsoToMs3(event.startedAt);
12583
+ if (!started.invalidTimestamp) {
12584
+ attrs.startedAtMs = started.ms;
12585
+ out.timestamp = started.ms;
12586
+ }
12587
+ }
12588
+ if (event.endedAt !== void 0) {
12589
+ const ended = parseIsoToMs3(event.endedAt);
12590
+ if (!ended.invalidTimestamp) {
12591
+ attrs.endedAtMs = ended.ms;
12592
+ if (out.durationMs === void 0 && typeof attrs.startedAtMs === "number" && ended.ms >= attrs.startedAtMs) {
12593
+ out.durationMs = ended.ms - attrs.startedAtMs;
12594
+ }
12595
+ }
12596
+ }
12597
+ out.attributes = compactAttributes3(attrs);
12543
12598
  return out;
12544
12599
  }
12545
12600
  function persistedInspectEventsToInspectEvents(events, options) {
@@ -13461,20 +13516,38 @@ function extractOtlpDocument(root) {
13461
13516
  function mapOtlpStatus(status) {
13462
13517
  if (!isRecord11(status)) return void 0;
13463
13518
  const rawCode = status.code;
13464
- if (typeof rawCode !== "string") return void 0;
13465
- switch (rawCode.toUpperCase()) {
13466
- case "STATUS_CODE_OK":
13467
- case "OK":
13468
- return "ok";
13469
- case "STATUS_CODE_ERROR":
13470
- case "ERROR":
13471
- return "error";
13472
- case "STATUS_CODE_UNSET":
13473
- case "UNSET":
13474
- return "unknown";
13475
- default:
13476
- return "unknown";
13519
+ if (typeof rawCode === "number" && Number.isFinite(rawCode)) {
13520
+ switch (rawCode) {
13521
+ case 0:
13522
+ return "unknown";
13523
+ case 1:
13524
+ return "ok";
13525
+ case 2:
13526
+ return "error";
13527
+ default:
13528
+ return "unknown";
13529
+ }
13530
+ }
13531
+ if (typeof rawCode === "string") {
13532
+ const trimmed = rawCode.trim();
13533
+ if (/^\d+$/.test(trimmed)) {
13534
+ return mapOtlpStatus({ code: Number(trimmed) });
13535
+ }
13536
+ switch (trimmed.toUpperCase()) {
13537
+ case "STATUS_CODE_OK":
13538
+ case "OK":
13539
+ return "ok";
13540
+ case "STATUS_CODE_ERROR":
13541
+ case "ERROR":
13542
+ return "error";
13543
+ case "STATUS_CODE_UNSET":
13544
+ case "UNSET":
13545
+ return "unknown";
13546
+ default:
13547
+ return "unknown";
13548
+ }
13477
13549
  }
13550
+ return void 0;
13478
13551
  }
13479
13552
  function readOtlpKind(attributes, pathPrefix) {
13480
13553
  const warnings = [];
@@ -16162,7 +16235,7 @@ var init_src = __esm({
16162
16235
  });
16163
16236
 
16164
16237
  // package.json
16165
- var version = "6.31.6";
16238
+ var version = "6.31.7";
16166
16239
 
16167
16240
  // packages/cli/src/list.ts
16168
16241
  init_advanced();
@@ -16511,7 +16584,7 @@ function mapReaderFormat(format) {
16511
16584
  function isMissingFileError(error) {
16512
16585
  return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
16513
16586
  }
16514
- async function readRunTraceEvents(runId, traceDir) {
16587
+ async function readRunPersistedEvents(runId, traceDir) {
16515
16588
  const filePath = getTraceFilePath(runId, traceDir);
16516
16589
  try {
16517
16590
  await promises.access(filePath);
@@ -16519,16 +16592,24 @@ async function readRunTraceEvents(runId, traceDir) {
16519
16592
  { type: "file", path: filePath },
16520
16593
  { format: "agent-inspect-jsonl" }
16521
16594
  );
16522
- const events = persistedInspectEventsToTraceEvents(result.events);
16523
16595
  return {
16524
- events,
16525
- format: events.length > 0 ? mapReaderFormat(result.format) : "empty"
16596
+ events: result.events,
16597
+ format: result.events.length > 0 ? mapReaderFormat(result.format) : "empty"
16526
16598
  };
16527
16599
  } catch (error) {
16528
16600
  if (isMissingFileError(error)) return void 0;
16529
16601
  throw error;
16530
16602
  }
16531
16603
  }
16604
+ async function readRunTraceEvents(runId, traceDir) {
16605
+ const persisted = await readRunPersistedEvents(runId, traceDir);
16606
+ if (persisted === void 0) return void 0;
16607
+ const events = persistedInspectEventsToTraceEvents(persisted.events);
16608
+ return {
16609
+ events,
16610
+ format: events.length > 0 ? persisted.format : "empty"
16611
+ };
16612
+ }
16532
16613
 
16533
16614
  // packages/cli/src/view.ts
16534
16615
  function isModuleNotFound(e) {
@@ -18760,6 +18841,10 @@ function exportOpenInference(tree, options) {
18760
18841
 
18761
18842
  // packages/core/src/exporters/otlp-json-exporter.ts
18762
18843
  init_helpers();
18844
+ var OTLP_STATUS_CODE_UNSET = 0;
18845
+ var OTLP_STATUS_CODE_OK = 1;
18846
+ var OTLP_STATUS_CODE_ERROR = 2;
18847
+ var OTLP_SPAN_KIND_INTERNAL = 1;
18763
18848
  function hexFrom2(seed, byteLen) {
18764
18849
  return crypto__default.default.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
18765
18850
  }
@@ -18772,7 +18857,19 @@ function stringAttr2(key, value) {
18772
18857
  return { key, value: { stringValue: value } };
18773
18858
  }
18774
18859
  function intAttr(key, value) {
18775
- return { key, value: { intValue: String(value) } };
18860
+ return { key, value: { intValue: String(Math.trunc(value)) } };
18861
+ }
18862
+ function doubleAttr(key, value) {
18863
+ return { key, value: { doubleValue: value } };
18864
+ }
18865
+ function boolAttr(key, value) {
18866
+ return { key, value: { boolValue: value } };
18867
+ }
18868
+ function numberAttr(key, value) {
18869
+ if (Number.isFinite(value) && !Number.isInteger(value)) {
18870
+ return doubleAttr(key, value);
18871
+ }
18872
+ return intAttr(key, value);
18776
18873
  }
18777
18874
  function genAiOperationName(kind) {
18778
18875
  switch (kind) {
@@ -18786,10 +18883,27 @@ function genAiOperationName(kind) {
18786
18883
  return void 0;
18787
18884
  }
18788
18885
  }
18886
+ function resolveSpanTimes(ev) {
18887
+ const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
18888
+ const endedAtMs = typeof ev.attributes?.endedAtMs === "number" && Number.isFinite(ev.attributes.endedAtMs) ? ev.attributes.endedAtMs : void 0;
18889
+ const startMs = startedAtMs ?? ev.timestamp;
18890
+ const startNs = String(unixNano2(startMs));
18891
+ if (endedAtMs !== void 0) {
18892
+ return { startNs, endNs: String(unixNano2(endedAtMs)) };
18893
+ }
18894
+ if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
18895
+ return {
18896
+ startNs,
18897
+ endNs: String(unixNano2(startMs) + unixNano2(ev.durationMs))
18898
+ };
18899
+ }
18900
+ return { startNs };
18901
+ }
18789
18902
  function exportOtlpJson(tree, options) {
18790
18903
  const warnings = [
18791
18904
  "OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
18792
- "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload."
18905
+ "Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
18906
+ "Status and span kind use OTLP numeric enums (StatusCode 0/1/2, SpanKind INTERNAL=1)."
18793
18907
  ];
18794
18908
  const traceId = hexFrom2(`trace:${tree.runId}`, 16);
18795
18909
  const includeAttributes = options?.includeAttributes ?? false;
@@ -18801,11 +18915,7 @@ function exportOtlpJson(tree, options) {
18801
18915
  const ev = n.event;
18802
18916
  const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
18803
18917
  const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
18804
- const startNs = String(unixNano2(ev.timestamp));
18805
- let endNs;
18806
- if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
18807
- endNs = String(unixNano2(ev.timestamp) + unixNano2(ev.durationMs));
18808
- }
18918
+ const { startNs, endNs } = resolveSpanTimes(ev);
18809
18919
  const attrs = [
18810
18920
  stringAttr2("agent_inspect.kind", ev.kind),
18811
18921
  stringAttr2("agent_inspect.confidence", ev.confidence),
@@ -18835,29 +18945,28 @@ function exportOtlpJson(tree, options) {
18835
18945
  if (includeAttributes && meta2 && typeof meta2 === "object") {
18836
18946
  for (const [k, v] of Object.entries(meta2)) {
18837
18947
  if (k === "tokens" || k === "model") continue;
18838
- if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
18839
- attrs.push(
18840
- stringAttr2(
18841
- `agent_inspect.preview.${k}`,
18842
- typeof v === "string" ? v.slice(0, maxLen) : String(v)
18843
- )
18844
- );
18948
+ if (typeof v === "string") {
18949
+ attrs.push(stringAttr2(`agent_inspect.preview.${k}`, v.slice(0, maxLen)));
18950
+ } else if (typeof v === "number" && Number.isFinite(v)) {
18951
+ attrs.push(numberAttr(`agent_inspect.preview.${k}`, v));
18952
+ } else if (typeof v === "boolean") {
18953
+ attrs.push(boolAttr(`agent_inspect.preview.${k}`, v));
18845
18954
  }
18846
18955
  }
18847
18956
  }
18848
- let statusCode = "STATUS_CODE_UNSET";
18957
+ let statusCode = OTLP_STATUS_CODE_UNSET;
18849
18958
  let statusMessage;
18850
18959
  if (ev.status === "error") {
18851
- statusCode = "STATUS_CODE_ERROR";
18960
+ statusCode = OTLP_STATUS_CODE_ERROR;
18852
18961
  statusMessage = meta2 && typeof meta2.error === "object" && meta2.error !== null ? String(meta2.error.message ?? "error").slice(0, maxLen) : "error";
18853
18962
  } else if (ev.status === "ok") {
18854
- statusCode = "STATUS_CODE_OK";
18963
+ statusCode = OTLP_STATUS_CODE_OK;
18855
18964
  }
18856
18965
  const spanJson = {
18857
18966
  traceId,
18858
18967
  spanId,
18859
18968
  name: ev.name,
18860
- kind: "SPAN_KIND_INTERNAL",
18969
+ kind: OTLP_SPAN_KIND_INTERNAL,
18861
18970
  startTimeUnixNano: startNs,
18862
18971
  attributes: attrs,
18863
18972
  status: {
@@ -18899,6 +19008,136 @@ function exportOtlpJson(tree, options) {
18899
19008
 
18900
19009
  // packages/core/src/exporters/validation.ts
18901
19010
  var EXPERIMENTAL = "Experimental compatibility export \u2014 verify against your target tooling before relying on it.";
19011
+ function pushPath(errors, path44, message) {
19012
+ errors.push(`${path44}: ${message}`);
19013
+ }
19014
+ function isRecord16(value) {
19015
+ return value !== null && typeof value === "object" && !Array.isArray(value);
19016
+ }
19017
+ function validateOtlpJson(content) {
19018
+ const errors = [];
19019
+ const warnings = [
19020
+ EXPERIMENTAL,
19021
+ "OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation.",
19022
+ "protocol-valid \u2260 profile-complete \u2260 fixture-complete \u2014 nested path diagnostics report protocol shape only."
19023
+ ];
19024
+ let parsed;
19025
+ try {
19026
+ parsed = JSON.parse(content);
19027
+ } catch {
19028
+ pushPath(errors, "$", "OTLP JSON export is not valid JSON");
19029
+ return { ok: false, format: "otlp-json", errors, warnings };
19030
+ }
19031
+ if (!isRecord16(parsed)) {
19032
+ pushPath(errors, "$", "OTLP JSON export must be an object");
19033
+ return { ok: false, format: "otlp-json", errors, warnings };
19034
+ }
19035
+ if (!Array.isArray(parsed.resourceSpans)) {
19036
+ pushPath(errors, "$.resourceSpans", "must be an array");
19037
+ return { ok: false, format: "otlp-json", errors, warnings };
19038
+ }
19039
+ parsed.resourceSpans.forEach((resourceSpan, rsi) => {
19040
+ const rsPath = `$.resourceSpans[${rsi}]`;
19041
+ if (!isRecord16(resourceSpan)) {
19042
+ pushPath(errors, rsPath, "must be an object");
19043
+ return;
19044
+ }
19045
+ if (!Array.isArray(resourceSpan.scopeSpans)) {
19046
+ pushPath(errors, `${rsPath}.scopeSpans`, "must be an array");
19047
+ return;
19048
+ }
19049
+ resourceSpan.scopeSpans.forEach((scopeSpan, ssi) => {
19050
+ const ssPath = `${rsPath}.scopeSpans[${ssi}]`;
19051
+ if (!isRecord16(scopeSpan)) {
19052
+ pushPath(errors, ssPath, "must be an object");
19053
+ return;
19054
+ }
19055
+ if (!Array.isArray(scopeSpan.spans)) {
19056
+ pushPath(errors, `${ssPath}.spans`, "must be an array");
19057
+ return;
19058
+ }
19059
+ scopeSpan.spans.forEach((span, spi) => {
19060
+ const spanPath = `${ssPath}.spans[${spi}]`;
19061
+ if (!isRecord16(span)) {
19062
+ pushPath(errors, spanPath, "must be an object");
19063
+ return;
19064
+ }
19065
+ if (typeof span.traceId !== "string" || span.traceId.length === 0) {
19066
+ pushPath(errors, `${spanPath}.traceId`, "must be a non-empty string");
19067
+ }
19068
+ if (typeof span.spanId !== "string" || span.spanId.length === 0) {
19069
+ pushPath(errors, `${spanPath}.spanId`, "must be a non-empty string");
19070
+ }
19071
+ if (typeof span.name !== "string") {
19072
+ pushPath(errors, `${spanPath}.name`, "must be a string");
19073
+ }
19074
+ if (typeof span.startTimeUnixNano !== "string" || !/^\d+$/.test(span.startTimeUnixNano)) {
19075
+ pushPath(
19076
+ errors,
19077
+ `${spanPath}.startTimeUnixNano`,
19078
+ "must be a decimal-string 64-bit integer"
19079
+ );
19080
+ }
19081
+ if (span.endTimeUnixNano !== void 0 && (typeof span.endTimeUnixNano !== "string" || !/^\d+$/.test(span.endTimeUnixNano))) {
19082
+ pushPath(
19083
+ errors,
19084
+ `${spanPath}.endTimeUnixNano`,
19085
+ "must be a decimal-string 64-bit integer when present"
19086
+ );
19087
+ }
19088
+ if (typeof span.kind === "number") {
19089
+ if (!Number.isInteger(span.kind)) {
19090
+ pushPath(errors, `${spanPath}.kind`, "must be an integer SpanKind enum");
19091
+ }
19092
+ } else if (typeof span.kind === "string") {
19093
+ warnings.push(
19094
+ `${spanPath}.kind: string SpanKind enum is legacy; prefer numeric (INTERNAL=1)`
19095
+ );
19096
+ } else if (span.kind !== void 0) {
19097
+ pushPath(
19098
+ errors,
19099
+ `${spanPath}.kind`,
19100
+ "must be numeric SpanKind or historical string enum"
19101
+ );
19102
+ }
19103
+ if (!isRecord16(span.status)) {
19104
+ pushPath(errors, `${spanPath}.status`, "must be an object");
19105
+ } else {
19106
+ const code = span.status.code;
19107
+ if (typeof code === "number") {
19108
+ if (![0, 1, 2].includes(code)) {
19109
+ pushPath(
19110
+ errors,
19111
+ `${spanPath}.status.code`,
19112
+ "must be numeric StatusCode 0 (UNSET), 1 (OK), or 2 (ERROR)"
19113
+ );
19114
+ }
19115
+ } else if (typeof code === "string") {
19116
+ const upper = code.toUpperCase();
19117
+ if (upper !== "STATUS_CODE_UNSET" && upper !== "STATUS_CODE_OK" && upper !== "STATUS_CODE_ERROR" && upper !== "UNSET" && upper !== "OK" && upper !== "ERROR" && !/^[012]$/.test(code.trim())) {
19118
+ pushPath(
19119
+ errors,
19120
+ `${spanPath}.status.code`,
19121
+ "unrecognized StatusCode string"
19122
+ );
19123
+ } else {
19124
+ warnings.push(
19125
+ `${spanPath}.status.code: string StatusCode is legacy; prefer numeric 0/1/2`
19126
+ );
19127
+ }
19128
+ } else {
19129
+ pushPath(
19130
+ errors,
19131
+ `${spanPath}.status.code`,
19132
+ "must be numeric StatusCode 0/1/2 or historical string enum"
19133
+ );
19134
+ }
19135
+ }
19136
+ });
19137
+ });
19138
+ });
19139
+ return { ok: errors.length === 0, format: "otlp-json", errors, warnings };
19140
+ }
18902
19141
  function validateExportContent(format, content) {
18903
19142
  const errors = [];
18904
19143
  const warnings = [EXPERIMENTAL];
@@ -18944,25 +19183,7 @@ function validateExportContent(format, content) {
18944
19183
  return { ok: errors.length === 0, format, errors, warnings };
18945
19184
  }
18946
19185
  if (format === "otlp-json") {
18947
- let parsed;
18948
- try {
18949
- parsed = JSON.parse(content);
18950
- } catch {
18951
- errors.push("OTLP JSON export is not valid JSON");
18952
- return { ok: false, format, errors, warnings };
18953
- }
18954
- if (!parsed || typeof parsed !== "object") {
18955
- errors.push("OTLP JSON export must be an object");
18956
- return { ok: false, format, errors, warnings };
18957
- }
18958
- const o = parsed;
18959
- if (!Array.isArray(o.resourceSpans)) {
18960
- errors.push("OTLP JSON export must include resourceSpans array");
18961
- }
18962
- warnings.push(
18963
- "OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation."
18964
- );
18965
- return { ok: errors.length === 0, format, errors, warnings };
19186
+ return validateOtlpJson(content);
18966
19187
  }
18967
19188
  errors.push(`Unsupported export format`);
18968
19189
  return { ok: false, format, errors, warnings };
@@ -19366,7 +19587,7 @@ async function exportCommand(runId, options = {}) {
19366
19587
  const traceDir = resolveTraceDir({ dir: options.dir });
19367
19588
  let events;
19368
19589
  try {
19369
- const result2 = await readRunTraceEvents(id, traceDir);
19590
+ const result2 = await readRunPersistedEvents(id, traceDir);
19370
19591
  events = result2?.events ?? [];
19371
19592
  } catch (e) {
19372
19593
  const msg = e instanceof Error ? e.message : String(e);
@@ -19382,7 +19603,11 @@ Trace directory: ${traceDir}`);
19382
19603
  }
19383
19604
  let tree;
19384
19605
  try {
19385
- tree = manualTraceEventsToRunTree(events);
19606
+ const trees = persistedInspectEventsToRunTrees(events);
19607
+ tree = trees.find((candidate) => candidate.runId === id) ?? trees[0];
19608
+ if (tree === void 0) {
19609
+ throw new Error("No run tree could be built from persisted events");
19610
+ }
19386
19611
  } catch (e) {
19387
19612
  const msg = e instanceof Error ? e.message : String(e);
19388
19613
  console.error(`[AgentInspect] export failed: ${msg}`);
@@ -19410,7 +19635,9 @@ Trace directory: ${traceDir}`);
19410
19635
  await promises.mkdir(path33__default.default.dirname(outPath), { recursive: true });
19411
19636
  await promises.writeFile(outPath, result.content, "utf-8");
19412
19637
  const vlabel = validation !== void 0 ? validation.ok ? "ok" : "failed" : "skipped";
19413
- console.log(`Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`);
19638
+ console.error(
19639
+ `Wrote ${result.fileExtension} export to ${outPath} (validation: ${vlabel})`
19640
+ );
19414
19641
  if (validation !== void 0 && !validation.ok) {
19415
19642
  console.error("Validation errors:", validation.errors.join("; "));
19416
19643
  }
@@ -19423,7 +19650,9 @@ Trace directory: ${traceDir}`);
19423
19650
  warnings: [...result.warnings, ...validation?.warnings ?? []],
19424
19651
  validation
19425
19652
  };
19426
- if (outPath === void 0) {
19653
+ if (outPath !== void 0) {
19654
+ payload.out = outPath;
19655
+ } else {
19427
19656
  payload.content = result.content;
19428
19657
  }
19429
19658
  console.log(JSON.stringify(payload, null, 2));
@@ -20535,7 +20764,7 @@ var STRICT_PROFILE_EXTRA_KEYS2 = [
20535
20764
  "retrieval",
20536
20765
  "query"
20537
20766
  ];
20538
- function isRecord16(value) {
20767
+ function isRecord17(value) {
20539
20768
  return typeof value === "object" && value !== null && !Array.isArray(value);
20540
20769
  }
20541
20770
  function toKey2(key) {
@@ -20964,7 +21193,7 @@ var Redactor2 = class {
20964
21193
  });
20965
21194
  return out;
20966
21195
  }
20967
- if (isRecord16(value)) {
21196
+ if (isRecord17(value)) {
20968
21197
  if (state.seen.has(value)) return state.seen.get(value);
20969
21198
  const out = {};
20970
21199
  state.seen.set(value, out);
@@ -20999,7 +21228,7 @@ var REDACTION_POLICY_LIMITS = {
20999
21228
  };
21000
21229
  var ALLOWED_TOP_LEVEL = /* @__PURE__ */ new Set(["version", "extraKeys", "patterns"]);
21001
21230
  var ALLOWED_PATTERN_FIELDS = /* @__PURE__ */ new Set(["id", "type", "value", "severity"]);
21002
- function isRecord17(value) {
21231
+ function isRecord18(value) {
21003
21232
  return value !== null && typeof value === "object" && !Array.isArray(value);
21004
21233
  }
21005
21234
  function rejectRemotePolicyPath(policyPath) {
@@ -21039,7 +21268,7 @@ function rejectUnknownFields(record, allowed, label) {
21039
21268
  }
21040
21269
  function compilePatternDetector(input3, index) {
21041
21270
  const label = `patterns[${index}]`;
21042
- if (!isRecord17(input3)) throw new Error(`${label} must be an object.`);
21271
+ if (!isRecord18(input3)) throw new Error(`${label} must be an object.`);
21043
21272
  const typeEarly = input3.type;
21044
21273
  if (typeEarly === "typed") {
21045
21274
  throw new Error(
@@ -21094,7 +21323,7 @@ function compilePatternDetector(input3, index) {
21094
21323
  };
21095
21324
  }
21096
21325
  function compileRedactionPolicy(raw, policyPath) {
21097
- if (!isRecord17(raw)) {
21326
+ if (!isRecord18(raw)) {
21098
21327
  throw new Error(`Redaction policy must be a JSON object (${policyPath}).`);
21099
21328
  }
21100
21329
  rejectUnknownFields(raw, ALLOWED_TOP_LEVEL, "Redaction policy");
@@ -22130,7 +22359,7 @@ async function openCommand(input3, options = {}, stdin = process.stdin) {
22130
22359
 
22131
22360
  // packages/cli/src/migrate.ts
22132
22361
  init_advanced();
22133
- function isRecord18(value) {
22362
+ function isRecord19(value) {
22134
22363
  return typeof value === "object" && value !== null && !Array.isArray(value);
22135
22364
  }
22136
22365
  function parseTarget(value) {
@@ -22139,7 +22368,7 @@ function parseTarget(value) {
22139
22368
  throw new Error('Unsupported migration target. Use "--to 1.0".');
22140
22369
  }
22141
22370
  function formatOf(value) {
22142
- if (!isRecord18(value)) return "unknown";
22371
+ if (!isRecord19(value)) return "unknown";
22143
22372
  if (value.schemaVersion === "0.1") return "0.1";
22144
22373
  if (value.schemaVersion === "0.2") return "0.2";
22145
22374
  if (value.schemaVersion === "1.0") return "1.0";
@@ -28663,16 +28892,120 @@ function demoTemplate(framework) {
28663
28892
  switch (framework) {
28664
28893
  case "ai-sdk":
28665
28894
  return `/**
28666
- * AI SDK starter \u2014 metadata-only telemetry (no real model calls in this demo).
28667
- * Install: npm install agent-inspect @agent-inspect/ai-sdk ai
28895
+ * AI SDK starter \u2014 keyless MockLanguageModelV3 + @agent-inspect/ai-sdk telemetry.
28896
+ * Install: npm install agent-inspect @agent-inspect/ai-sdk ai@6.0.210 zod
28668
28897
  */
28669
- import { inspectRun, step } from "agent-inspect";
28898
+ import { generateText, stepCountIs, tool } from "ai";
28899
+ import { MockLanguageModelV3 } from "ai/test";
28900
+ import { agentInspect } from "@agent-inspect/ai-sdk";
28901
+ import { z } from "zod";
28902
+ import { readdirSync, readFileSync } from "node:fs";
28903
+ import path from "node:path";
28904
+
28905
+ const TRACE_DIR = ".agent-inspect";
28906
+ const ANSWER = "You have 2 orders";
28907
+ const CORRECT_RUN = "ai-sdk-demo-correct";
28908
+ const WRONG_RUN = "ai-sdk-demo-wrong";
28909
+
28910
+ const usage = {
28911
+ inputTokens: { total: 4, noCache: 4, cacheRead: 0, cacheWrite: 0 },
28912
+ outputTokens: { total: 3, text: 3, reasoning: 0 },
28913
+ };
28914
+
28915
+ const lookupOrders = tool({
28916
+ description: "Look up orders for a user",
28917
+ inputSchema: z.object({ userId: z.string() }),
28918
+ execute: async () => ({ orders: 2 }),
28919
+ });
28920
+
28921
+ const deleteOrders = tool({
28922
+ description: "Delete orders for a user (wrong path)",
28923
+ inputSchema: z.object({ userId: z.string() }),
28924
+ execute: async () => ({ orders: 2 }),
28925
+ });
28926
+
28927
+ async function runPath(runName, toolName) {
28928
+ const integration = agentInspect({
28929
+ traceDir: TRACE_DIR,
28930
+ runName,
28931
+ capture: "metadata-only",
28932
+ });
28933
+ let step = 0;
28934
+ try {
28935
+ const result = await generateText({
28936
+ model: new MockLanguageModelV3({
28937
+ provider: "fixture-provider",
28938
+ modelId: "fixture-tools",
28939
+ doGenerate: async () => {
28940
+ step += 1;
28941
+ if (step === 1) {
28942
+ return {
28943
+ content: [
28944
+ {
28945
+ type: "tool-call",
28946
+ toolCallId: \`call-\${toolName}\`,
28947
+ toolName,
28948
+ input: { userId: "u1" },
28949
+ },
28950
+ ],
28951
+ finishReason: { unified: "tool-calls", raw: "tool-calls" },
28952
+ usage,
28953
+ warnings: [],
28954
+ };
28955
+ }
28956
+ return {
28957
+ content: [{ type: "text", text: ANSWER }],
28958
+ finishReason: { unified: "stop", raw: "stop" },
28959
+ usage,
28960
+ warnings: [],
28961
+ };
28962
+ },
28963
+ }),
28964
+ tools: { lookup_orders: lookupOrders, delete_orders: deleteOrders },
28965
+ prompt: "How many orders do I have?",
28966
+ stopWhen: stepCountIs(5),
28967
+ experimental_telemetry: {
28968
+ isEnabled: true,
28969
+ recordInputs: false,
28970
+ recordOutputs: false,
28971
+ integrations: [integration],
28972
+ },
28973
+ });
28974
+ if (result.text !== ANSWER) {
28975
+ throw new Error(\`unexpected answer for \${runName}: \${result.text}\`);
28976
+ }
28977
+ } finally {
28978
+ await integration.flush();
28979
+ await integration.close();
28980
+ }
28981
+ }
28982
+
28983
+ function selectRunIdByName(runName) {
28984
+ const files = readdirSync(TRACE_DIR).filter((f) => f.endsWith(".jsonl"));
28985
+ const matches = [];
28986
+ for (const file of files) {
28987
+ const text = readFileSync(path.join(TRACE_DIR, file), "utf8");
28988
+ if (text.includes(\`"name":"\${runName}"\`) || text.includes(\`"name": "\${runName}"\`)) {
28989
+ matches.push(file.replace(/\\.jsonl$/, ""));
28990
+ }
28991
+ }
28992
+ if (matches.length !== 1) {
28993
+ throw new Error(
28994
+ \`expected exactly one run named \${runName}, found \${matches.length}\`,
28995
+ );
28996
+ }
28997
+ return matches[0];
28998
+ }
28670
28999
 
28671
29000
  async function main() {
28672
- await inspectRun("ai-sdk-demo", async () => {
28673
- await step.tool("mock-generate", async () => ({ text: "ok" }));
28674
- }, { traceDir: ".agent-inspect", silent: true });
29001
+ await runPath(CORRECT_RUN, "lookup_orders");
29002
+ await runPath(WRONG_RUN, "delete_orders");
29003
+ const correctId = selectRunIdByName(CORRECT_RUN);
29004
+ const wrongId = selectRunIdByName(WRONG_RUN);
28675
29005
  console.log("Trace written to .agent-inspect/");
29006
+ console.log(\`Correct path runId: \${correctId}\`);
29007
+ console.log(\`Wrong path runId: \${wrongId}\`);
29008
+ console.log(\`Next: npx agent-inspect check \${correctId} --required-tool lookup_orders\`);
28676
29009
  }
28677
29010
 
28678
29011
  main().catch((error) => {