agent-inspect 6.31.7 → 6.31.8

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 (42) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/packages/cli/dist/{chunk-QV73NM25.mjs → chunk-6FE47XSF.mjs} +24 -11
  5. package/packages/cli/dist/chunk-6FE47XSF.mjs.map +1 -0
  6. package/packages/cli/dist/index.cjs +176 -42
  7. package/packages/cli/dist/index.cjs.map +1 -1
  8. package/packages/cli/dist/index.mjs +156 -36
  9. package/packages/cli/dist/index.mjs.map +1 -1
  10. package/packages/cli/dist/{src-KFOBXFPN.mjs → src-NXAYHG34.mjs} +3 -3
  11. package/packages/cli/dist/{src-KFOBXFPN.mjs.map → src-NXAYHG34.mjs.map} +1 -1
  12. package/packages/core/dist/advanced.cjs +22 -9
  13. package/packages/core/dist/advanced.cjs.map +1 -1
  14. package/packages/core/dist/advanced.mjs +5 -5
  15. package/packages/core/dist/checks.mjs +2 -2
  16. package/packages/core/dist/{chunk-LXYPM2ZO.mjs → chunk-2CCRUI42.mjs} +19 -318
  17. package/packages/core/dist/chunk-2CCRUI42.mjs.map +1 -0
  18. package/packages/core/dist/{chunk-QLYUWKK7.mjs → chunk-2IRRUNIN.mjs} +11 -5
  19. package/packages/core/dist/chunk-2IRRUNIN.mjs.map +1 -0
  20. package/packages/core/dist/{chunk-3RV3JILQ.mjs → chunk-IJJSPJXV.mjs} +20 -12
  21. package/packages/core/dist/chunk-IJJSPJXV.mjs.map +1 -0
  22. package/packages/core/dist/chunk-L5WLVBW4.mjs +355 -0
  23. package/packages/core/dist/chunk-L5WLVBW4.mjs.map +1 -0
  24. package/packages/core/dist/exporters.cjs +110 -18
  25. package/packages/core/dist/exporters.cjs.map +1 -1
  26. package/packages/core/dist/exporters.mjs +110 -18
  27. package/packages/core/dist/exporters.mjs.map +1 -1
  28. package/packages/core/dist/persisted.cjs +344 -9
  29. package/packages/core/dist/persisted.cjs.map +1 -1
  30. package/packages/core/dist/persisted.d.cts +8 -1
  31. package/packages/core/dist/persisted.d.ts +8 -1
  32. package/packages/core/dist/persisted.mjs +3 -2
  33. package/packages/core/dist/persisted.mjs.map +1 -1
  34. package/packages/core/dist/readers.cjs +377 -87
  35. package/packages/core/dist/readers.cjs.map +1 -1
  36. package/packages/core/dist/readers.mjs +3 -3
  37. package/packages/cli/dist/chunk-QV73NM25.mjs.map +0 -1
  38. package/packages/core/dist/chunk-3RV3JILQ.mjs.map +0 -1
  39. package/packages/core/dist/chunk-FWK3Q3OJ.mjs +0 -56
  40. package/packages/core/dist/chunk-FWK3Q3OJ.mjs.map +0 -1
  41. package/packages/core/dist/chunk-LXYPM2ZO.mjs.map +0 -1
  42. package/packages/core/dist/chunk-QLYUWKK7.mjs.map +0 -1
@@ -12618,14 +12618,20 @@ var init_to_inspect_event = __esm({
12618
12618
  });
12619
12619
 
12620
12620
  // packages/core/src/persisted/tree-bridge.ts
12621
+ function logicalToPersisted(event) {
12622
+ const { sourceEventIds: _sourceEventIds, projection: _projection, ...rest } = event;
12623
+ return rest;
12624
+ }
12621
12625
  function persistedInspectEventsToRunTrees(events, options) {
12622
- const inspectEvents = persistedInspectEventsToInspectEvents(events, {
12626
+ const sourceEvents = options?.coalesceLifecycle === true ? projectLogicalEvents(events).logicalEvents.map(logicalToPersisted) : events;
12627
+ const inspectEvents = persistedInspectEventsToInspectEvents(sourceEvents, {
12623
12628
  skipInvalid: options?.skipInvalid
12624
12629
  });
12625
12630
  return new TreeBuilder().build(inspectEvents);
12626
12631
  }
12627
12632
  var init_tree_bridge = __esm({
12628
12633
  "packages/core/src/persisted/tree-bridge.ts"() {
12634
+ init_logical_events();
12629
12635
  init_tree_builder();
12630
12636
  init_from_trace_event();
12631
12637
  init_to_inspect_event();
@@ -13246,7 +13252,7 @@ function mapOpenInferenceSpan(span, index, version2) {
13246
13252
  const errorMessage = isRecord11(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
13247
13253
  const event = {
13248
13254
  schemaVersion: "0.2",
13249
- eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
13255
+ eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : `${traceId}:${spanId}`,
13250
13256
  runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
13251
13257
  kind,
13252
13258
  name,
@@ -13297,12 +13303,16 @@ function mapOpenInferenceEvents(document) {
13297
13303
  const mapped = document.spans.map(
13298
13304
  (span, index) => mapOpenInferenceSpan(span, index, document.version)
13299
13305
  );
13300
- const spanIdToEventId = new Map(
13301
- mapped.map((span) => [span.spanId, span.event.eventId])
13306
+ const spanKeyToEventId = new Map(
13307
+ mapped.map((span) => {
13308
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
13309
+ return [`${traceId}:${span.spanId}`, span.event.eventId];
13310
+ })
13302
13311
  );
13303
13312
  for (const span of mapped) {
13304
13313
  if (span.parentSpanId === void 0) continue;
13305
- span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
13314
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
13315
+ span.event.parentId = spanKeyToEventId.get(`${traceId}:${span.parentSpanId}`) ?? span.parentSpanId;
13306
13316
  }
13307
13317
  return {
13308
13318
  events: mapped.map((span) => span.event),
@@ -13773,7 +13783,7 @@ function mapOtlpSpan(context) {
13773
13783
  const errorMessage = isRecord11(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
13774
13784
  const event = {
13775
13785
  schemaVersion: "0.2",
13776
- eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
13786
+ eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : `${traceId}:${spanId}`,
13777
13787
  runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
13778
13788
  kind,
13779
13789
  name: readStringField(span, ["name"]) ?? spanId,
@@ -13822,12 +13832,16 @@ function mapOtlpSpan(context) {
13822
13832
  }
13823
13833
  function mapOtlpEventsToPersisted(document) {
13824
13834
  const mapped = document.spans.map((span) => mapOtlpSpan(span));
13825
- const spanIdToEventId = new Map(
13826
- mapped.map((span) => [span.spanId, span.event.eventId])
13835
+ const spanKeyToEventId = new Map(
13836
+ mapped.map((span) => {
13837
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
13838
+ return [`${traceId}:${span.spanId}`, span.event.eventId];
13839
+ })
13827
13840
  );
13828
13841
  for (const span of mapped) {
13829
13842
  if (span.parentSpanId === void 0) continue;
13830
- span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
13843
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
13844
+ span.event.parentId = spanKeyToEventId.get(`${traceId}:${span.parentSpanId}`) ?? span.parentSpanId;
13831
13845
  }
13832
13846
  return {
13833
13847
  events: mapped.map((span) => span.event),
@@ -16235,7 +16249,7 @@ var init_src = __esm({
16235
16249
  });
16236
16250
 
16237
16251
  // package.json
16238
- var version = "6.31.7";
16252
+ var version = "6.31.8";
16239
16253
 
16240
16254
  // packages/cli/src/list.ts
16241
16255
  init_advanced();
@@ -18770,11 +18784,13 @@ function exportOpenInference(tree, options) {
18770
18784
  endNs = startNs + unixNano(ev.durationMs);
18771
18785
  }
18772
18786
  const { openInferenceKind } = mapInspectKindToOI(ev.kind, warnings);
18787
+ const meta2 = ev.attributes;
18788
+ const originalSource = typeof meta2?.originalSourceType === "string" && meta2.originalSourceType.trim() !== "" ? meta2.originalSourceType.trim() : ev.source.type;
18773
18789
  const attrs = {
18774
18790
  "openinference.span.kind": openInferenceKind,
18775
18791
  "agent_inspect.kind": ev.kind,
18776
18792
  "agent_inspect.confidence": ev.confidence,
18777
- "agent_inspect.source.type": ev.source.type,
18793
+ "agent_inspect.source.type": originalSource,
18778
18794
  "agent_inspect.run_id": tree.runId,
18779
18795
  "agent_inspect.event_id": ev.eventId,
18780
18796
  "agent_inspect.status": ev.status ?? "unset"
@@ -18782,9 +18798,9 @@ function exportOpenInference(tree, options) {
18782
18798
  if (ev.durationMs !== void 0) {
18783
18799
  attrs["agent_inspect.duration_ms"] = ev.durationMs;
18784
18800
  }
18785
- const meta2 = ev.attributes;
18786
- if (meta2?.model !== void 0 && typeof meta2.model === "string") {
18787
- attrs["llm.model_name"] = meta2.model;
18801
+ const requestModel = (typeof meta2?.model === "string" && meta2.model.trim() !== "" ? meta2.model : void 0) ?? (typeof meta2?.modelId === "string" && meta2.modelId.trim() !== "" ? meta2.modelId : void 0);
18802
+ if (requestModel !== void 0) {
18803
+ attrs["llm.model_name"] = requestModel;
18788
18804
  }
18789
18805
  const tokens = meta2?.tokens;
18790
18806
  if (tokens && typeof tokens === "object" && tokens !== null) {
@@ -18794,8 +18810,9 @@ function exportOpenInference(tree, options) {
18794
18810
  if (typeof outp === "number") attrs["llm.token_count.completion"] = outp;
18795
18811
  }
18796
18812
  if (includeAttributes && meta2 && typeof meta2 === "object") {
18813
+ const skipKeys = /* @__PURE__ */ new Set(["tokens", "model", "modelId", "originalSourceType"]);
18797
18814
  for (const [k, v] of Object.entries(meta2)) {
18798
- if (k === "tokens" || k === "model") continue;
18815
+ if (skipKeys.has(k)) continue;
18799
18816
  if (v !== void 0 && v !== null && typeof v !== "object") {
18800
18817
  attrs[`agent_inspect.preview.${k}`] = typeof v === "string" ? v.slice(0, maxLen) : v;
18801
18818
  }
@@ -18916,24 +18933,33 @@ function exportOtlpJson(tree, options) {
18916
18933
  const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
18917
18934
  const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
18918
18935
  const { startNs, endNs } = resolveSpanTimes(ev);
18936
+ const meta2 = ev.attributes;
18937
+ const originalSource = typeof meta2?.originalSourceType === "string" && meta2.originalSourceType.trim() !== "" ? meta2.originalSourceType.trim() : ev.source.type;
18919
18938
  const attrs = [
18920
18939
  stringAttr2("agent_inspect.kind", ev.kind),
18921
18940
  stringAttr2("agent_inspect.confidence", ev.confidence),
18922
- stringAttr2("agent_inspect.source.type", ev.source.type),
18941
+ stringAttr2("agent_inspect.source.type", originalSource),
18923
18942
  stringAttr2("agent_inspect.run_id", tree.runId),
18924
18943
  stringAttr2("agent_inspect.event_id", ev.eventId),
18925
18944
  stringAttr2("agent_inspect.status", ev.status ?? "unset")
18926
18945
  ];
18927
18946
  if (ev.durationMs !== void 0) {
18928
- attrs.push(intAttr("agent_inspect.duration_ms", ev.durationMs));
18947
+ attrs.push(numberAttr("agent_inspect.duration_ms", ev.durationMs));
18929
18948
  }
18930
18949
  const op = genAiOperationName(ev.kind);
18931
18950
  if (op !== void 0) {
18932
18951
  attrs.push(stringAttr2("gen_ai.operation.name", op));
18933
18952
  }
18934
- const meta2 = ev.attributes;
18935
- if (meta2?.model !== void 0 && typeof meta2.model === "string") {
18936
- attrs.push(stringAttr2("gen_ai.request.model", meta2.model.slice(0, maxLen)));
18953
+ const requestModel = (typeof meta2?.model === "string" && meta2.model.trim() !== "" ? meta2.model : void 0) ?? (typeof meta2?.modelId === "string" && meta2.modelId.trim() !== "" ? meta2.modelId : void 0);
18954
+ if (requestModel !== void 0) {
18955
+ attrs.push(stringAttr2("gen_ai.request.model", requestModel.slice(0, maxLen)));
18956
+ }
18957
+ const responseModel = typeof meta2?.responseModelId === "string" && meta2.responseModelId.trim() !== "" ? meta2.responseModelId : typeof meta2?.responseModel === "string" && meta2.responseModel.trim() !== "" ? meta2.responseModel : void 0;
18958
+ if (responseModel !== void 0) {
18959
+ attrs.push(stringAttr2("gen_ai.response.model", responseModel.slice(0, maxLen)));
18960
+ }
18961
+ if (typeof meta2?.provider === "string" && meta2.provider.trim() !== "") {
18962
+ attrs.push(stringAttr2("gen_ai.provider.name", meta2.provider.slice(0, maxLen)));
18937
18963
  }
18938
18964
  const tokens = meta2?.tokens;
18939
18965
  if (tokens && typeof tokens === "object" && tokens !== null) {
@@ -18943,8 +18969,17 @@ function exportOtlpJson(tree, options) {
18943
18969
  if (typeof outp === "number") attrs.push(intAttr("gen_ai.usage.output_tokens", outp));
18944
18970
  }
18945
18971
  if (includeAttributes && meta2 && typeof meta2 === "object") {
18972
+ const skipKeys = /* @__PURE__ */ new Set([
18973
+ "tokens",
18974
+ "model",
18975
+ "modelId",
18976
+ "responseModel",
18977
+ "responseModelId",
18978
+ "provider",
18979
+ "originalSourceType"
18980
+ ]);
18946
18981
  for (const [k, v] of Object.entries(meta2)) {
18947
- if (k === "tokens" || k === "model") continue;
18982
+ if (skipKeys.has(k)) continue;
18948
18983
  if (typeof v === "string") {
18949
18984
  attrs.push(stringAttr2(`agent_inspect.preview.${k}`, v.slice(0, maxLen)));
18950
18985
  } else if (typeof v === "number" && Number.isFinite(v)) {
@@ -19014,12 +19049,42 @@ function pushPath(errors, path44, message) {
19014
19049
  function isRecord16(value) {
19015
19050
  return value !== null && typeof value === "object" && !Array.isArray(value);
19016
19051
  }
19052
+ function isHexId(value, byteLen) {
19053
+ return typeof value === "string" && new RegExp(`^[0-9a-fA-F]{${byteLen * 2}}$`).test(value);
19054
+ }
19055
+ function validateAnyValue(errors, path44, value) {
19056
+ if (!isRecord16(value)) {
19057
+ pushPath(errors, path44, "must be an AnyValue object");
19058
+ return;
19059
+ }
19060
+ const variants = [
19061
+ "stringValue",
19062
+ "boolValue",
19063
+ "intValue",
19064
+ "doubleValue",
19065
+ "bytesValue",
19066
+ "arrayValue",
19067
+ "kvlistValue"
19068
+ ].filter((key) => value[key] !== void 0);
19069
+ if (variants.length !== 1) {
19070
+ pushPath(
19071
+ errors,
19072
+ path44,
19073
+ `AnyValue must set exactly one variant (found ${variants.length}: ${variants.join(",")})`
19074
+ );
19075
+ }
19076
+ if (value.intValue !== void 0) {
19077
+ if (typeof value.intValue !== "string" || !/^-?\d+$/.test(value.intValue)) {
19078
+ pushPath(errors, `${path44}.intValue`, "must be a decimal integer string");
19079
+ }
19080
+ }
19081
+ }
19017
19082
  function validateOtlpJson(content) {
19018
19083
  const errors = [];
19019
19084
  const warnings = [
19020
19085
  EXPERIMENTAL,
19021
19086
  "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."
19087
+ "producer-profile checks IDs, timing, and AnyValue shape; historical string enums are reader-compat warnings only."
19023
19088
  ];
19024
19089
  let parsed;
19025
19090
  try {
@@ -19062,11 +19127,26 @@ function validateOtlpJson(content) {
19062
19127
  pushPath(errors, spanPath, "must be an object");
19063
19128
  return;
19064
19129
  }
19065
- if (typeof span.traceId !== "string" || span.traceId.length === 0) {
19066
- pushPath(errors, `${spanPath}.traceId`, "must be a non-empty string");
19130
+ if (!isHexId(span.traceId, 16)) {
19131
+ pushPath(
19132
+ errors,
19133
+ `${spanPath}.traceId`,
19134
+ "must be a 32-char hex trace id (16 bytes)"
19135
+ );
19136
+ }
19137
+ if (!isHexId(span.spanId, 8)) {
19138
+ pushPath(
19139
+ errors,
19140
+ `${spanPath}.spanId`,
19141
+ "must be a 16-char hex span id (8 bytes)"
19142
+ );
19067
19143
  }
19068
- if (typeof span.spanId !== "string" || span.spanId.length === 0) {
19069
- pushPath(errors, `${spanPath}.spanId`, "must be a non-empty string");
19144
+ if (span.parentSpanId !== void 0 && !isHexId(span.parentSpanId, 8)) {
19145
+ pushPath(
19146
+ errors,
19147
+ `${spanPath}.parentSpanId`,
19148
+ "must be a 16-char hex span id when present"
19149
+ );
19070
19150
  }
19071
19151
  if (typeof span.name !== "string") {
19072
19152
  pushPath(errors, `${spanPath}.name`, "must be a string");
@@ -19085,13 +19165,39 @@ function validateOtlpJson(content) {
19085
19165
  "must be a decimal-string 64-bit integer when present"
19086
19166
  );
19087
19167
  }
19168
+ if (typeof span.startTimeUnixNano === "string" && /^\d+$/.test(span.startTimeUnixNano) && typeof span.endTimeUnixNano === "string" && /^\d+$/.test(span.endTimeUnixNano)) {
19169
+ try {
19170
+ if (BigInt(span.endTimeUnixNano) < BigInt(span.startTimeUnixNano)) {
19171
+ pushPath(
19172
+ errors,
19173
+ `${spanPath}.endTimeUnixNano`,
19174
+ "must be >= startTimeUnixNano"
19175
+ );
19176
+ }
19177
+ } catch {
19178
+ pushPath(errors, `${spanPath}.endTimeUnixNano`, "out of integer range");
19179
+ }
19180
+ }
19181
+ if (Array.isArray(span.attributes)) {
19182
+ span.attributes.forEach((attr, ai) => {
19183
+ const attrPath = `${spanPath}.attributes[${ai}]`;
19184
+ if (!isRecord16(attr)) {
19185
+ pushPath(errors, attrPath, "must be an object");
19186
+ return;
19187
+ }
19188
+ if (typeof attr.key !== "string") {
19189
+ pushPath(errors, `${attrPath}.key`, "must be a string");
19190
+ }
19191
+ validateAnyValue(errors, `${attrPath}.value`, attr.value);
19192
+ });
19193
+ }
19088
19194
  if (typeof span.kind === "number") {
19089
19195
  if (!Number.isInteger(span.kind)) {
19090
19196
  pushPath(errors, `${spanPath}.kind`, "must be an integer SpanKind enum");
19091
19197
  }
19092
19198
  } else if (typeof span.kind === "string") {
19093
19199
  warnings.push(
19094
- `${spanPath}.kind: string SpanKind enum is legacy; prefer numeric (INTERNAL=1)`
19200
+ `${spanPath}.kind: string SpanKind is historical reader-compat only; producer wire format uses numeric enums`
19095
19201
  );
19096
19202
  } else if (span.kind !== void 0) {
19097
19203
  pushPath(
@@ -19122,7 +19228,7 @@ function validateOtlpJson(content) {
19122
19228
  );
19123
19229
  } else {
19124
19230
  warnings.push(
19125
- `${spanPath}.status.code: string StatusCode is legacy; prefer numeric 0/1/2`
19231
+ `${spanPath}.status.code: string StatusCode is historical reader-compat only; producer wire format uses numeric 0/1/2`
19126
19232
  );
19127
19233
  }
19128
19234
  } else {
@@ -19603,7 +19709,9 @@ Trace directory: ${traceDir}`);
19603
19709
  }
19604
19710
  let tree;
19605
19711
  try {
19606
- const trees = persistedInspectEventsToRunTrees(events);
19712
+ const trees = persistedInspectEventsToRunTrees(events, {
19713
+ coalesceLifecycle: true
19714
+ });
19607
19715
  tree = trees.find((candidate) => candidate.runId === id) ?? trees[0];
19608
19716
  if (tree === void 0) {
19609
19717
  throw new Error("No run tree could be built from persisted events");
@@ -28899,13 +29007,15 @@ import { generateText, stepCountIs, tool } from "ai";
28899
29007
  import { MockLanguageModelV3 } from "ai/test";
28900
29008
  import { agentInspect } from "@agent-inspect/ai-sdk";
28901
29009
  import { z } from "zod";
28902
- import { readdirSync, readFileSync } from "node:fs";
29010
+ import { mkdirSync, readdirSync, readFileSync, rmSync } from "node:fs";
28903
29011
  import path from "node:path";
29012
+ import { randomUUID } from "node:crypto";
28904
29013
 
28905
- const TRACE_DIR = ".agent-inspect";
29014
+ const SESSION = randomUUID().slice(0, 8);
29015
+ const TRACE_DIR = path.join(".agent-inspect", \`demo-\${SESSION}\`);
28906
29016
  const ANSWER = "You have 2 orders";
28907
- const CORRECT_RUN = "ai-sdk-demo-correct";
28908
- const WRONG_RUN = "ai-sdk-demo-wrong";
29017
+ const CORRECT_RUN = \`ai-sdk-demo-correct-\${SESSION}\`;
29018
+ const WRONG_RUN = \`ai-sdk-demo-wrong-\${SESSION}\`;
28909
29019
 
28910
29020
  const usage = {
28911
29021
  inputTokens: { total: 4, noCache: 4, cacheRead: 0, cacheWrite: 0 },
@@ -28945,7 +29055,7 @@ async function runPath(runName, toolName) {
28945
29055
  type: "tool-call",
28946
29056
  toolCallId: \`call-\${toolName}\`,
28947
29057
  toolName,
28948
- input: { userId: "u1" },
29058
+ input: JSON.stringify({ userId: "u1" }),
28949
29059
  },
28950
29060
  ],
28951
29061
  finishReason: { unified: "tool-calls", raw: "tool-calls" },
@@ -28997,15 +29107,39 @@ function selectRunIdByName(runName) {
28997
29107
  return matches[0];
28998
29108
  }
28999
29109
 
29110
+ function assertToolExecuted(runId, requiredTool) {
29111
+ const text = readFileSync(path.join(TRACE_DIR, \`\${runId}.jsonl\`), "utf8");
29112
+ const toolHits = text
29113
+ .split("\\n")
29114
+ .filter(Boolean)
29115
+ .map((line) => JSON.parse(line))
29116
+ .filter(
29117
+ (ev) =>
29118
+ (ev.kind === "TOOL" || ev.attributes?.stepType === "tool") &&
29119
+ (ev.name === requiredTool || ev.attributes?.toolName === requiredTool),
29120
+ );
29121
+ if (toolHits.length === 0) {
29122
+ throw new Error(\`expected TOOL events for \${requiredTool} in \${runId}\`);
29123
+ }
29124
+ }
29125
+
29000
29126
  async function main() {
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);
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\`);
29127
+ mkdirSync(TRACE_DIR, { recursive: true });
29128
+ try {
29129
+ await runPath(CORRECT_RUN, "lookup_orders");
29130
+ await runPath(WRONG_RUN, "delete_orders");
29131
+ const correctId = selectRunIdByName(CORRECT_RUN);
29132
+ const wrongId = selectRunIdByName(WRONG_RUN);
29133
+ assertToolExecuted(correctId, "lookup_orders");
29134
+ assertToolExecuted(wrongId, "delete_orders");
29135
+ console.log(\`Trace written to \${TRACE_DIR}/\`);
29136
+ console.log(\`Correct path runId: \${correctId}\`);
29137
+ console.log(\`Wrong path runId: \${wrongId}\`);
29138
+ console.log(\`Next: npx agent-inspect check \${correctId} --dir \${TRACE_DIR} --required-tool lookup_orders\`);
29139
+ } catch (error) {
29140
+ rmSync(TRACE_DIR, { recursive: true, force: true });
29141
+ throw error;
29142
+ }
29009
29143
  }
29010
29144
 
29011
29145
  main().catch((error) => {