agent-inspect 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +12 -4
  3. package/docs/API.md +124 -9
  4. package/docs/ARCHITECTURE.md +4 -0
  5. package/docs/CLI.md +41 -12
  6. package/docs/KNOWN-ISSUES.md +8 -1
  7. package/docs/LIMITATIONS.md +11 -2
  8. package/docs/SCHEMA.md +16 -6
  9. package/package.json +21 -1
  10. package/packages/cli/dist/index.cjs +2449 -157
  11. package/packages/cli/dist/index.cjs.map +1 -1
  12. package/packages/cli/dist/index.mjs +2450 -158
  13. package/packages/cli/dist/index.mjs.map +1 -1
  14. package/packages/core/dist/advanced.cjs +839 -18
  15. package/packages/core/dist/advanced.cjs.map +1 -1
  16. package/packages/core/dist/advanced.d.cts +98 -3
  17. package/packages/core/dist/advanced.d.ts +98 -3
  18. package/packages/core/dist/advanced.mjs +7 -4
  19. package/packages/core/dist/chunk-57S5D6HR.mjs +655 -0
  20. package/packages/core/dist/chunk-57S5D6HR.mjs.map +1 -0
  21. package/packages/core/dist/chunk-6QSLZCBJ.mjs +743 -0
  22. package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +1 -0
  23. package/packages/core/dist/chunk-6SZPTECC.mjs +342 -0
  24. package/packages/core/dist/chunk-6SZPTECC.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-QX3ZMPUF.mjs → chunk-74XZ6N7Q.mjs} +13 -55
  26. package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +1 -0
  27. package/packages/core/dist/{chunk-QPAU2TPA.mjs → chunk-HR7G62IE.mjs} +4 -4
  28. package/packages/core/dist/{chunk-QPAU2TPA.mjs.map → chunk-HR7G62IE.mjs.map} +1 -1
  29. package/packages/core/dist/chunk-S4YWKV4G.mjs +48 -0
  30. package/packages/core/dist/chunk-S4YWKV4G.mjs.map +1 -0
  31. package/packages/core/dist/chunk-TFLPUZ56.mjs +1571 -0
  32. package/packages/core/dist/chunk-TFLPUZ56.mjs.map +1 -0
  33. package/packages/core/dist/{chunk-Q6EPNB3V.mjs → chunk-TZISEVLQ.mjs} +34 -183
  34. package/packages/core/dist/chunk-TZISEVLQ.mjs.map +1 -0
  35. package/packages/core/dist/chunk-U2BGPESY.mjs +150 -0
  36. package/packages/core/dist/chunk-U2BGPESY.mjs.map +1 -0
  37. package/packages/core/dist/chunk-VTIB5MDK.mjs +304 -0
  38. package/packages/core/dist/chunk-VTIB5MDK.mjs.map +1 -0
  39. package/packages/core/dist/{chunk-5EMIZZXD.mjs → chunk-Y56BPA3B.mjs} +87 -4
  40. package/packages/core/dist/chunk-Y56BPA3B.mjs.map +1 -0
  41. package/packages/core/dist/diff.d.cts +3 -2
  42. package/packages/core/dist/diff.d.ts +3 -2
  43. package/packages/core/dist/exporters.cjs.map +1 -1
  44. package/packages/core/dist/exporters.d.cts +3 -2
  45. package/packages/core/dist/exporters.d.ts +3 -2
  46. package/packages/core/dist/exporters.mjs +2 -2
  47. package/packages/core/dist/index.cjs +2975 -229
  48. package/packages/core/dist/index.cjs.map +1 -1
  49. package/packages/core/dist/index.d.cts +27 -6
  50. package/packages/core/dist/index.d.ts +27 -6
  51. package/packages/core/dist/index.mjs +113 -60
  52. package/packages/core/dist/index.mjs.map +1 -1
  53. package/packages/core/dist/{log-config-BzGmDYum.d.cts → inspect-event-Des4JDHo.d.cts} +1 -31
  54. package/packages/core/dist/{log-config-BzGmDYum.d.ts → inspect-event-Des4JDHo.d.ts} +1 -31
  55. package/packages/core/dist/log-config-BnH8Ykcb.d.cts +33 -0
  56. package/packages/core/dist/log-config-C1GcJPIM.d.ts +33 -0
  57. package/packages/core/dist/logs.d.cts +3 -2
  58. package/packages/core/dist/logs.d.ts +3 -2
  59. package/packages/core/dist/logs.mjs +3 -3
  60. package/packages/core/dist/persisted-inspect-event-0kaRADsp.d.cts +56 -0
  61. package/packages/core/dist/persisted-inspect-event-DiFto0K2.d.ts +56 -0
  62. package/packages/core/dist/persisted.cjs +38 -40
  63. package/packages/core/dist/persisted.cjs.map +1 -1
  64. package/packages/core/dist/persisted.d.cts +6 -55
  65. package/packages/core/dist/persisted.d.ts +6 -55
  66. package/packages/core/dist/persisted.mjs +4 -2
  67. package/packages/core/dist/readers.cjs +2590 -0
  68. package/packages/core/dist/readers.cjs.map +1 -0
  69. package/packages/core/dist/readers.d.cts +80 -0
  70. package/packages/core/dist/readers.d.ts +80 -0
  71. package/packages/core/dist/readers.mjs +9 -0
  72. package/packages/core/dist/readers.mjs.map +1 -0
  73. package/packages/core/dist/{types-CNbheSdk.d.cts → types-DB8jB6Jg.d.cts} +7 -1
  74. package/packages/core/dist/{types-Bkt7LS01.d.ts → types-tSix7tfv.d.ts} +7 -1
  75. package/packages/core/dist/writers.cjs +997 -0
  76. package/packages/core/dist/writers.cjs.map +1 -0
  77. package/packages/core/dist/writers.d.cts +62 -0
  78. package/packages/core/dist/writers.d.ts +62 -0
  79. package/packages/core/dist/writers.mjs +9 -0
  80. package/packages/core/dist/writers.mjs.map +1 -0
  81. package/packages/core/dist/chunk-5EMIZZXD.mjs.map +0 -1
  82. package/packages/core/dist/chunk-Q6EPNB3V.mjs.map +0 -1
  83. package/packages/core/dist/chunk-QX3ZMPUF.mjs.map +0 -1
  84. package/packages/core/dist/chunk-XDBND27A.mjs +0 -975
  85. package/packages/core/dist/chunk-XDBND27A.mjs.map +0 -1
@@ -148,6 +148,7 @@ function isPersistedTokenUsage(value) {
148
148
  if (!isOptionalNonNegativeNumber(value.input)) return false;
149
149
  if (!isOptionalNonNegativeNumber(value.output)) return false;
150
150
  if (!isOptionalNonNegativeNumber(value.total)) return false;
151
+ if (!isOptionalNonNegativeNumber(value.cached)) return false;
151
152
  return true;
152
153
  }
153
154
  function isPersistedTraceContext(value) {
@@ -238,6 +239,32 @@ function buildRunStartedMetadata(options) {
238
239
  return Object.keys(merged).length > 0 ? merged : void 0;
239
240
  }
240
241
 
242
+ // packages/core/src/persisted/token-usage.ts
243
+ function isRecord3(value) {
244
+ return typeof value === "object" && value !== null && !Array.isArray(value);
245
+ }
246
+ function nonNegativeFinite(value) {
247
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
248
+ }
249
+ function normalizeTokenUsage(value) {
250
+ if (!isRecord3(value)) return void 0;
251
+ const input = nonNegativeFinite(value.input);
252
+ const output = nonNegativeFinite(value.output);
253
+ const suppliedTotal = nonNegativeFinite(value.total);
254
+ const cached = nonNegativeFinite(value.cached);
255
+ const derivedTotal = input !== void 0 && output !== void 0 && Number.isFinite(input + output) ? input + output : void 0;
256
+ const total = suppliedTotal ?? derivedTotal;
257
+ if (input === void 0 && output === void 0 && total === void 0 && cached === void 0) {
258
+ return void 0;
259
+ }
260
+ return {
261
+ ...input !== void 0 ? { input } : {},
262
+ ...output !== void 0 ? { output } : {},
263
+ ...total !== void 0 ? { total } : {},
264
+ ...cached !== void 0 ? { cached } : {}
265
+ };
266
+ }
267
+
241
268
  // packages/core/src/persisted/from-trace-event.ts
242
269
  function sanitizeIdPart(value) {
243
270
  return value.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -310,22 +337,7 @@ function mapErrorInfo(error) {
310
337
  return out;
311
338
  }
312
339
  function mapTokenUsageFromMetadata(metadata) {
313
- const tokens = metadata?.tokens;
314
- if (!tokens || typeof tokens !== "object") {
315
- return void 0;
316
- }
317
- const input = typeof tokens.input === "number" && Number.isFinite(tokens.input) && tokens.input >= 0 ? tokens.input : void 0;
318
- const output = typeof tokens.output === "number" && Number.isFinite(tokens.output) && tokens.output >= 0 ? tokens.output : void 0;
319
- if (input === void 0 && output === void 0) {
320
- return void 0;
321
- }
322
- const usage = {};
323
- if (input !== void 0) usage.input = input;
324
- if (output !== void 0) usage.output = output;
325
- if (input !== void 0 && output !== void 0) {
326
- usage.total = input + output;
327
- }
328
- return usage;
340
+ return normalizeTokenUsage(metadata?.tokens);
329
341
  }
330
342
  function compactAttributes(entries) {
331
343
  const out = {};
@@ -529,23 +541,7 @@ function mapInspectSourceToPersisted(source, options) {
529
541
  }
530
542
  }
531
543
  function mapTokenUsageFromAttributes(attributes) {
532
- const tokens = attributes?.tokens;
533
- if (!tokens || typeof tokens !== "object" || Array.isArray(tokens)) {
534
- return void 0;
535
- }
536
- const rec = tokens;
537
- const input = typeof rec.input === "number" && Number.isFinite(rec.input) && rec.input >= 0 ? rec.input : void 0;
538
- const output = typeof rec.output === "number" && Number.isFinite(rec.output) && rec.output >= 0 ? rec.output : void 0;
539
- if (input === void 0 && output === void 0) {
540
- return void 0;
541
- }
542
- const usage = {};
543
- if (input !== void 0) usage.input = input;
544
- if (output !== void 0) usage.output = output;
545
- if (input !== void 0 && output !== void 0) {
546
- usage.total = input + output;
547
- }
548
- return usage;
544
+ return normalizeTokenUsage(attributes?.tokens);
549
545
  }
550
546
  function mapErrorFromAttributes(event) {
551
547
  if (event.status !== "error" || !event.attributes) {
@@ -802,10 +798,10 @@ function mapPersistedStatusToRunStatus(status) {
802
798
  return void 0;
803
799
  }
804
800
  }
805
- function mapPersistedError(error) {
801
+ function mapPersistedError(error, attributes) {
806
802
  if (!error?.message) return void 0;
807
803
  const out = { message: error.message };
808
- const stack = typeof error.name === "string" && error.name.length > 0 ? error.name : void 0;
804
+ const stack = typeof attributes?.errorStack === "string" && attributes.errorStack.length > 0 ? attributes.errorStack : void 0;
809
805
  if (stack) {
810
806
  out.stack = stack;
811
807
  }
@@ -819,7 +815,9 @@ function mapTokenUsageToMetadata(tokenUsage, attributes) {
819
815
  if (tokenUsage) {
820
816
  metadata.tokens = {
821
817
  ...tokenUsage.input !== void 0 ? { input: tokenUsage.input } : {},
822
- ...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {}
818
+ ...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {},
819
+ ...tokenUsage.total !== void 0 ? { total: tokenUsage.total } : {},
820
+ ...tokenUsage.cached !== void 0 ? { cached: tokenUsage.cached } : {}
823
821
  };
824
822
  }
825
823
  return Object.keys(metadata).length > 0 ? metadata : void 0;
@@ -892,7 +890,7 @@ function fromLegacyRunCompleted(event) {
892
890
  endTime,
893
891
  durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
894
892
  };
895
- const error = mapPersistedError(event.error);
893
+ const error = mapPersistedError(event.error, event.attributes);
896
894
  if (error) out.error = error;
897
895
  return out;
898
896
  }
@@ -926,7 +924,7 @@ function fromLegacyStepCompleted(event) {
926
924
  endTime,
927
925
  durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
928
926
  };
929
- const error = mapPersistedError(event.error);
927
+ const error = mapPersistedError(event.error, event.attributes);
930
928
  if (error) out.error = error;
931
929
  return out;
932
930
  }
@@ -957,7 +955,7 @@ function fromNativeRun(event) {
957
955
  endTime,
958
956
  durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
959
957
  };
960
- const error = mapPersistedError(event.error);
958
+ const error = mapPersistedError(event.error, event.attributes);
961
959
  if (error) completed.error = error;
962
960
  out.push(completed);
963
961
  }
@@ -999,7 +997,7 @@ function fromNativeStep(event) {
999
997
  endTime,
1000
998
  durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
1001
999
  };
1002
- const error = mapPersistedError(event.error);
1000
+ const error = mapPersistedError(event.error, event.attributes);
1003
1001
  if (error) completed.error = error;
1004
1002
  out.push(completed);
1005
1003
  }
@@ -1092,7 +1090,7 @@ var TreeBuilder = class {
1092
1090
  const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
1093
1091
  const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
1094
1092
  const status = computeRunStatus(sorted);
1095
- const durationMs = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
1093
+ const durationMs2 = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
1096
1094
  const name = sorted.find((e) => e.kind === "RUN")?.name;
1097
1095
  out.push({
1098
1096
  runId,
@@ -1100,7 +1098,7 @@ var TreeBuilder = class {
1100
1098
  status,
1101
1099
  startedAt,
1102
1100
  endedAt: status === "running" ? void 0 : endedAt,
1103
- durationMs,
1101
+ durationMs: durationMs2,
1104
1102
  children: roots,
1105
1103
  metadata: {
1106
1104
  totalEvents: sorted.length,
@@ -1125,7 +1123,7 @@ function traceEventsToPersistedRunTrees(events) {
1125
1123
  const persisted = traceEventsToPersistedInspectEvents(events);
1126
1124
  return persistedInspectEventsToRunTrees(persisted);
1127
1125
  }
1128
- function isRecord3(v) {
1126
+ function isRecord4(v) {
1129
1127
  return typeof v === "object" && v !== null && !Array.isArray(v);
1130
1128
  }
1131
1129
  function isNonEmptyStringArray(v) {
@@ -1137,7 +1135,7 @@ function validateRedact(redact) {
1137
1135
  }
1138
1136
  for (const r of redact) {
1139
1137
  if (typeof r === "string") continue;
1140
- if (!isRecord3(r)) {
1138
+ if (!isRecord4(r)) {
1141
1139
  throw new Error("Invalid config: redact entries must be strings or objects");
1142
1140
  }
1143
1141
  if (typeof r.key !== "string" || r.key.trim() === "") {
@@ -1156,7 +1154,7 @@ function validateRedact(redact) {
1156
1154
  }
1157
1155
  }
1158
1156
  function validateMappings(mappings) {
1159
- if (!isRecord3(mappings)) {
1157
+ if (!isRecord4(mappings)) {
1160
1158
  throw new Error("Invalid config: mappings must be an object");
1161
1159
  }
1162
1160
  }
@@ -1206,7 +1204,7 @@ async function loadLogIngestConfig(configPath) {
1206
1204
  const msg = e instanceof Error ? e.message : String(e);
1207
1205
  throw new Error(`Invalid JSON in config file: ${configPath} (${msg})`);
1208
1206
  }
1209
- if (!isRecord3(parsed)) {
1207
+ if (!isRecord4(parsed)) {
1210
1208
  throw new Error("Invalid config: expected a JSON object at top-level");
1211
1209
  }
1212
1210
  const user = parsed;
@@ -1243,7 +1241,7 @@ async function loadLogIngestConfig(configPath) {
1243
1241
  }
1244
1242
  return mergeLogIngestConfig(DEFAULT_LOG_INGEST_CONFIG, user);
1245
1243
  }
1246
- function isRecord4(v) {
1244
+ function isRecord5(v) {
1247
1245
  return typeof v === "object" && v !== null && !Array.isArray(v);
1248
1246
  }
1249
1247
  var JsonLogParser = class {
@@ -1268,7 +1266,7 @@ var JsonLogParser = class {
1268
1266
  });
1269
1267
  continue;
1270
1268
  }
1271
- if (!isRecord4(parsed)) {
1269
+ if (!isRecord5(parsed)) {
1272
1270
  warnings.push({
1273
1271
  code: "MALFORMED_JSON",
1274
1272
  message: "JSON log line must be an object",
@@ -1299,7 +1297,7 @@ var JsonLogParser = class {
1299
1297
  return this.parseLines(lines, filePath);
1300
1298
  }
1301
1299
  };
1302
- function isRecord5(v) {
1300
+ function isRecord6(v) {
1303
1301
  return typeof v === "object" && v !== null && !Array.isArray(v);
1304
1302
  }
1305
1303
  function findLastJsonObjectSubstring(line) {
@@ -1375,7 +1373,7 @@ var Log4jsParser = class {
1375
1373
  });
1376
1374
  continue;
1377
1375
  }
1378
- if (!isRecord5(parsed)) {
1376
+ if (!isRecord6(parsed)) {
1379
1377
  warnings.push({
1380
1378
  code: "UNSUPPORTED_LOG4JS_PAYLOAD",
1381
1379
  message: "Embedded JSON payload must be an object",
@@ -1453,7 +1451,7 @@ var DEFAULT_REDACT_KEYS = [
1453
1451
  "secret",
1454
1452
  "email"
1455
1453
  ];
1456
- function isRecord6(v) {
1454
+ function isRecord7(v) {
1457
1455
  return typeof v === "object" && v !== null && !Array.isArray(v);
1458
1456
  }
1459
1457
  function toKey(s) {
@@ -1526,7 +1524,7 @@ var Redactor = class {
1526
1524
  if (Array.isArray(value)) {
1527
1525
  return value.map((v) => this.#redactNested(v));
1528
1526
  }
1529
- if (isRecord6(value)) {
1527
+ if (isRecord7(value)) {
1530
1528
  const out = {};
1531
1529
  for (const [k, v] of Object.entries(value)) {
1532
1530
  out[k] = this.redactValue(k, v);
@@ -1654,13 +1652,13 @@ var EventNormalizer = class {
1654
1652
  const timestampMissing = parsedTs === void 0;
1655
1653
  const parentIdKey = cfg.parentIdKey;
1656
1654
  const parentId = parentIdKey ? safeString(raw[parentIdKey]) : void 0;
1657
- let durationMs;
1655
+ let durationMs2;
1658
1656
  const durationKey = cfg.durationKey;
1659
1657
  if (durationKey) {
1660
1658
  const v = raw[durationKey];
1661
- if (isFiniteNumber(v)) durationMs = v;
1659
+ if (isFiniteNumber(v)) durationMs2 = v;
1662
1660
  } else if (isFiniteNumber(raw.durationMs)) {
1663
- durationMs = raw.durationMs;
1661
+ durationMs2 = raw.durationMs;
1664
1662
  }
1665
1663
  let status;
1666
1664
  const statusKey = cfg.statusKey;
@@ -1707,7 +1705,7 @@ var EventNormalizer = class {
1707
1705
  kind,
1708
1706
  timestamp,
1709
1707
  ...status ? { status } : {},
1710
- ...durationMs !== void 0 ? { durationMs } : {},
1708
+ ...durationMs2 !== void 0 ? { durationMs: durationMs2 } : {},
1711
1709
  ...Object.keys(attributes).length > 0 ? { attributes } : {},
1712
1710
  confidence,
1713
1711
  source: {
@@ -2286,69 +2284,81 @@ function truncateStringForProfile(value, key, maxMetadataValueLength, maxPreview
2286
2284
  }
2287
2285
 
2288
2286
  // packages/core/src/read-trace.ts
2289
- function isRecord7(value) {
2287
+ function isRecord8(value) {
2290
2288
  return typeof value === "object" && value !== null && !Array.isArray(value);
2291
2289
  }
2292
2290
  function detectLineFormat(parsed) {
2293
- if (!isRecord7(parsed)) return "unknown";
2291
+ if (!isRecord8(parsed)) return "unknown";
2294
2292
  if (parsed.schemaVersion === "0.1") return "0.1";
2295
2293
  if (parsed.schemaVersion === "0.2") return "0.2";
2296
2294
  return "unknown";
2297
2295
  }
2298
2296
  function parseTraceJsonl(raw, options = {}) {
2299
2297
  const validate = options.validate ?? isTraceEvent;
2298
+ const emitWarning = (message) => {
2299
+ if (options.warnings !== false) warn(message);
2300
+ };
2300
2301
  const persisted = [];
2301
2302
  const traceEvents = [];
2303
+ const rows = [];
2304
+ let sourceEventCount = 0;
2302
2305
  let saw01 = false;
2303
2306
  let saw02 = false;
2307
+ let lineNumber = 0;
2304
2308
  for (const line of raw.split(/\r?\n/)) {
2309
+ lineNumber += 1;
2305
2310
  const trimmed = line.trim();
2306
2311
  if (trimmed === "") continue;
2307
2312
  let parsed;
2308
2313
  try {
2309
2314
  parsed = JSON.parse(trimmed);
2310
2315
  } catch {
2311
- warn("Skipped invalid JSON line in trace file");
2316
+ emitWarning("Skipped invalid JSON line in trace file");
2312
2317
  continue;
2313
2318
  }
2314
2319
  const format2 = detectLineFormat(parsed);
2315
2320
  if (format2 === "0.1") {
2316
2321
  saw01 = true;
2317
2322
  if (validate(parsed)) {
2323
+ sourceEventCount += 1;
2318
2324
  traceEvents.push(parsed);
2325
+ rows.push({ format: "0.1", event: parsed, sourceLine: lineNumber });
2319
2326
  } else {
2320
- warn("Skipped invalid trace event line in trace file");
2327
+ emitWarning("Skipped invalid trace event line in trace file");
2321
2328
  }
2322
2329
  continue;
2323
2330
  }
2324
2331
  if (format2 === "0.2") {
2325
2332
  saw02 = true;
2326
2333
  if (isPersistedInspectEvent(parsed)) {
2334
+ sourceEventCount += 1;
2327
2335
  persisted.push(parsed);
2336
+ rows.push({ format: "0.2", event: parsed, sourceLine: lineNumber });
2337
+ traceEvents.push(...persistedInspectEventToTraceEvents(parsed));
2328
2338
  } else {
2329
- warn("Skipped invalid persisted inspect event line in trace file");
2339
+ emitWarning("Skipped invalid persisted inspect event line in trace file");
2330
2340
  }
2331
2341
  continue;
2332
2342
  }
2333
- warn("Skipped trace line with unknown schemaVersion");
2343
+ emitWarning("Skipped trace line with unknown schemaVersion");
2334
2344
  }
2335
2345
  if (saw01 && saw02) {
2336
- warn("Trace file mixes schemaVersion 0.1 and 0.2 lines; normalizing all rows");
2346
+ emitWarning(
2347
+ "Trace file mixes schemaVersion 0.1 and 0.2 lines; normalizing all rows"
2348
+ );
2337
2349
  }
2338
- const converted = persisted.length > 0 ? persistedInspectEventsToTraceEvents(persisted) : [];
2339
- const events = [...traceEvents, ...converted];
2340
2350
  let format = "empty";
2341
2351
  if (saw01 && saw02) format = "mixed";
2342
2352
  else if (saw01) format = "0.1";
2343
2353
  else if (saw02) format = "0.2";
2344
- return { format, events, persisted };
2354
+ return { format, sourceEventCount, events: traceEvents, persisted, rows };
2345
2355
  }
2346
2356
  function unknownTraceFormatMessage() {
2347
2357
  return "Unsupported trace format. Expected schemaVersion 0.1 (TraceEvent) or 0.2 (PersistedInspectEvent).";
2348
2358
  }
2349
2359
 
2350
2360
  // packages/core/src/storage.ts
2351
- function isRecord8(value) {
2361
+ function isRecord9(value) {
2352
2362
  return typeof value === "object" && value !== null && !Array.isArray(value);
2353
2363
  }
2354
2364
  function nonEmptyString(value) {
@@ -2359,7 +2369,7 @@ function finiteNumber(value) {
2359
2369
  }
2360
2370
  function optionalErrorInfo(value) {
2361
2371
  if (value === void 0) return true;
2362
- if (!isRecord8(value)) return false;
2372
+ if (!isRecord9(value)) return false;
2363
2373
  if (typeof value.message !== "string") return false;
2364
2374
  if ("stack" in value && value.stack !== void 0) {
2365
2375
  if (typeof value.stack !== "string") return false;
@@ -2367,7 +2377,7 @@ function optionalErrorInfo(value) {
2367
2377
  return true;
2368
2378
  }
2369
2379
  function validateEvent(event) {
2370
- if (!isRecord8(event)) return false;
2380
+ if (!isRecord9(event)) return false;
2371
2381
  if (event.schemaVersion !== "0.1") return false;
2372
2382
  if (!finiteNumber(event.timestamp)) return false;
2373
2383
  if (typeof event.event !== "string") return false;
@@ -2376,7 +2386,7 @@ function validateEvent(event) {
2376
2386
  if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
2377
2387
  return false;
2378
2388
  }
2379
- if (event.metadata !== void 0 && !isRecord8(event.metadata)) {
2389
+ if (event.metadata !== void 0 && !isRecord9(event.metadata)) {
2380
2390
  return false;
2381
2391
  }
2382
2392
  return true;
@@ -2391,7 +2401,7 @@ function validateEvent(event) {
2391
2401
  if (event.parentId !== void 0 && typeof event.parentId !== "string") {
2392
2402
  return false;
2393
2403
  }
2394
- if (event.metadata !== void 0 && !isRecord8(event.metadata)) {
2404
+ if (event.metadata !== void 0 && !isRecord9(event.metadata)) {
2395
2405
  return false;
2396
2406
  }
2397
2407
  return true;
@@ -2482,16 +2492,25 @@ async function readTraceFile(runId, traceDir) {
2482
2492
  }
2483
2493
  async function readTraceEvents(runId, traceDir) {
2484
2494
  try {
2485
- const raw = await readTraceFile(runId, traceDir);
2486
- if (raw === void 0) {
2487
- return [];
2488
- }
2489
- return parseTraceJsonl(raw, { validate: validateEvent }).events;
2495
+ const filePath = getTraceFilePath(runId, traceDir);
2496
+ return await readTraceEventsFromFile(filePath);
2490
2497
  } catch (e) {
2491
2498
  warn("Failed to read trace events", e);
2492
2499
  return [];
2493
2500
  }
2494
2501
  }
2502
+ async function readTraceEventsFromFile(filePath) {
2503
+ try {
2504
+ const raw = await promises.readFile(filePath, "utf-8");
2505
+ return parseTraceJsonl(raw, { validate: validateEvent }).events;
2506
+ } catch (e) {
2507
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
2508
+ return [];
2509
+ }
2510
+ warn("Failed to read trace events from file", e);
2511
+ return [];
2512
+ }
2513
+ }
2495
2514
  async function listTraceFiles(traceDir) {
2496
2515
  try {
2497
2516
  const usable = path__default.default.resolve(traceDir);
@@ -2531,7 +2550,7 @@ function getRunIdFromTraceFileName(fileName) {
2531
2550
  var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
2532
2551
  var DEFAULT_MAX_PREVIEW_LENGTH = 500;
2533
2552
  var DEFAULT_MAX_EVENT_BYTES = 65536;
2534
- function isRecord9(value) {
2553
+ function isRecord10(value) {
2535
2554
  return typeof value === "object" && value !== null && !Array.isArray(value);
2536
2555
  }
2537
2556
  function isPreviewKey2(key) {
@@ -2553,7 +2572,7 @@ function resolveTraceSafetyOptions(options) {
2553
2572
  redactEnabled = false;
2554
2573
  } else if (redact === true || redact === void 0) {
2555
2574
  redactEnabled = true;
2556
- } else if (isRecord9(redact)) {
2575
+ } else if (isRecord10(redact)) {
2557
2576
  redactEnabled = true;
2558
2577
  redactionRules = redact.rules;
2559
2578
  }
@@ -2584,6 +2603,21 @@ function resolveTraceSafetyOptions(options) {
2584
2603
  }
2585
2604
  function boundMetadataValue(key, value, opts, seen, depth) {
2586
2605
  if (depth > 32) return "[MaxDepth]";
2606
+ if (typeof value === "bigint") {
2607
+ return `${value.toString()}n`;
2608
+ }
2609
+ if (typeof value === "function") {
2610
+ return "[Function]";
2611
+ }
2612
+ if (typeof value === "symbol") {
2613
+ return "[Symbol]";
2614
+ }
2615
+ if (typeof value === "number" && !Number.isFinite(value)) {
2616
+ return String(value);
2617
+ }
2618
+ if (value === void 0) {
2619
+ return null;
2620
+ }
2587
2621
  if (value === null || typeof value !== "object") {
2588
2622
  if (typeof value === "string") {
2589
2623
  const max = isPreviewKey2(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
@@ -2605,8 +2639,12 @@ function boundMetadataValue(key, value, opts, seen, depth) {
2605
2639
  }
2606
2640
  const record = value;
2607
2641
  const out = {};
2608
- for (const [k, v] of Object.entries(record)) {
2609
- out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
2642
+ try {
2643
+ for (const [k, v] of Object.entries(record)) {
2644
+ out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
2645
+ }
2646
+ } catch {
2647
+ return { truncated: true, reason: "metadataEnumerationFailed" };
2610
2648
  }
2611
2649
  return out;
2612
2650
  }
@@ -2620,16 +2658,25 @@ function redactMetadata(metadata, opts) {
2620
2658
  }
2621
2659
  function prepareMetadataForDisk(metadata, opts) {
2622
2660
  try {
2623
- const redacted = redactMetadata(metadata, opts);
2624
- const seen = /* @__PURE__ */ new WeakSet();
2661
+ const preBounded = boundMetadataValue(
2662
+ "metadata",
2663
+ metadata,
2664
+ opts,
2665
+ /* @__PURE__ */ new WeakSet(),
2666
+ 0
2667
+ );
2668
+ const redacted = redactMetadata(
2669
+ isRecord10(preBounded) ? preBounded : {},
2670
+ opts
2671
+ );
2625
2672
  const bounded = boundMetadataValue(
2626
2673
  "metadata",
2627
2674
  redacted,
2628
2675
  opts,
2629
- seen,
2676
+ /* @__PURE__ */ new WeakSet(),
2630
2677
  0
2631
2678
  );
2632
- return isRecord9(bounded) ? bounded : {};
2679
+ return isRecord10(bounded) ? bounded : {};
2633
2680
  } catch {
2634
2681
  return { truncated: true, reason: "metadataPreparationFailed" };
2635
2682
  }
@@ -2750,6 +2797,210 @@ function prepareTraceEventForDisk(event, opts) {
2750
2797
  return event;
2751
2798
  }
2752
2799
  }
2800
+ function safeGet(record, key) {
2801
+ try {
2802
+ return record[key];
2803
+ } catch {
2804
+ return void 0;
2805
+ }
2806
+ }
2807
+ function optionalBoundedString(value, _key, opts) {
2808
+ if (typeof value !== "string") return void 0;
2809
+ return truncateString(value, opts.maxMetadataValueLength);
2810
+ }
2811
+ function requiredBoundedString(value, key, opts) {
2812
+ const out = optionalBoundedString(value, key, opts);
2813
+ return out && out.length > 0 ? out : void 0;
2814
+ }
2815
+ function preparePersistedSummaryForDisk(key, value, opts) {
2816
+ try {
2817
+ const redactor = new Redactor({
2818
+ rules: opts.redactionRules,
2819
+ extraKeys: opts.profileExtraKeys
2820
+ });
2821
+ const redacted = opts.redactEnabled ? redactor.redactValue(key, value) : value;
2822
+ return boundMetadataValue(key, redacted, opts, /* @__PURE__ */ new WeakSet(), 0);
2823
+ } catch {
2824
+ return { truncated: true, reason: "summaryPreparationFailed" };
2825
+ }
2826
+ }
2827
+ function preparePersistedErrorForDisk(value, opts) {
2828
+ if (!isRecord10(value)) return void 0;
2829
+ try {
2830
+ const redactor = new Redactor({
2831
+ rules: opts.redactionRules,
2832
+ extraKeys: opts.profileExtraKeys
2833
+ });
2834
+ const rawMessage = safeGet(value, "message");
2835
+ const redactedMessage = opts.redactEnabled ? redactor.redactValue("message", rawMessage) : rawMessage;
2836
+ const boundedMessage = boundMetadataValue(
2837
+ "message",
2838
+ redactedMessage,
2839
+ opts,
2840
+ /* @__PURE__ */ new WeakSet(),
2841
+ 0
2842
+ );
2843
+ const message = typeof boundedMessage === "string" && boundedMessage.length > 0 ? boundedMessage : "Unknown error";
2844
+ const out = { message };
2845
+ const name = optionalBoundedString(safeGet(value, "name"), "name", opts);
2846
+ const code = optionalBoundedString(safeGet(value, "code"), "code", opts);
2847
+ if (name !== void 0) out.name = name;
2848
+ if (code !== void 0) out.code = code;
2849
+ return out;
2850
+ } catch {
2851
+ return { message: "Error preparation failed" };
2852
+ }
2853
+ }
2854
+ function prepareTokenUsage(value) {
2855
+ if (!isRecord10(value)) return void 0;
2856
+ const out = {};
2857
+ for (const key of ["input", "output", "total", "cached"]) {
2858
+ const item = safeGet(value, key);
2859
+ if (typeof item === "number" && Number.isFinite(item) && item >= 0) {
2860
+ out[key] = item;
2861
+ }
2862
+ }
2863
+ return Object.keys(out).length > 0 ? out : void 0;
2864
+ }
2865
+ function prepareTraceContext(value, opts) {
2866
+ if (!isRecord10(value)) return void 0;
2867
+ const out = {};
2868
+ const traceId = optionalBoundedString(safeGet(value, "traceId"), "traceId", opts);
2869
+ const spanId = optionalBoundedString(safeGet(value, "spanId"), "spanId", opts);
2870
+ const parentSpanId = optionalBoundedString(
2871
+ safeGet(value, "parentSpanId"),
2872
+ "parentSpanId",
2873
+ opts
2874
+ );
2875
+ if (traceId !== void 0) out.traceId = traceId;
2876
+ if (spanId !== void 0) out.spanId = spanId;
2877
+ if (parentSpanId !== void 0) out.parentSpanId = parentSpanId;
2878
+ return Object.keys(out).length > 0 ? out : void 0;
2879
+ }
2880
+ function serializedPersistedEvent(event) {
2881
+ try {
2882
+ return JSON.stringify(event);
2883
+ } catch {
2884
+ return void 0;
2885
+ }
2886
+ }
2887
+ function persistedEventByteLength(event) {
2888
+ const serialized = serializedPersistedEvent(event);
2889
+ return serialized === void 0 ? void 0 : byteLength(serialized);
2890
+ }
2891
+ function minimalPersistedEvent(event, opts, originalApproxBytes) {
2892
+ return {
2893
+ schemaVersion: "0.2",
2894
+ eventId: truncateString(event.eventId, 128),
2895
+ runId: truncateString(event.runId, 128),
2896
+ kind: event.kind,
2897
+ name: truncateString(event.name, 128),
2898
+ ...event.status !== void 0 ? { status: event.status } : {},
2899
+ timestamp: truncateString(event.timestamp, 128),
2900
+ confidence: event.confidence,
2901
+ source: {
2902
+ type: event.source.type,
2903
+ ...event.source.name !== void 0 ? { name: truncateString(event.source.name, 128) } : {},
2904
+ ...event.source.version !== void 0 ? { version: truncateString(event.source.version, 128) } : {}
2905
+ },
2906
+ attributes: {
2907
+ truncated: true,
2908
+ reason: "maxEventBytes",
2909
+ originalApproxBytes,
2910
+ maxEventBytes: opts.maxEventBytes
2911
+ }
2912
+ };
2913
+ }
2914
+ function tinyPersistedEvent(event) {
2915
+ return {
2916
+ schemaVersion: "0.2",
2917
+ eventId: truncateString(event.eventId, 32),
2918
+ runId: truncateString(event.runId, 32),
2919
+ kind: event.kind,
2920
+ name: truncateString(event.name, 32),
2921
+ timestamp: truncateString(event.timestamp, 32),
2922
+ confidence: event.confidence,
2923
+ source: { type: event.source.type },
2924
+ attributes: { truncated: true, reason: "maxEventBytes" }
2925
+ };
2926
+ }
2927
+ function enforcePersistedEventSize(event, opts) {
2928
+ const bytes = persistedEventByteLength(event);
2929
+ if (bytes === void 0) return void 0;
2930
+ if (bytes <= opts.maxEventBytes) return event;
2931
+ const minimal = minimalPersistedEvent(event, opts, bytes);
2932
+ const minimalBytes = persistedEventByteLength(minimal);
2933
+ if (minimalBytes !== void 0 && minimalBytes <= opts.maxEventBytes) {
2934
+ return minimal;
2935
+ }
2936
+ const tiny = tinyPersistedEvent(event);
2937
+ return isPersistedInspectEvent(tiny) ? tiny : void 0;
2938
+ }
2939
+ function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOptions()) {
2940
+ try {
2941
+ if (!isRecord10(value)) return void 0;
2942
+ const source = safeGet(value, "source");
2943
+ if (!isRecord10(source)) return void 0;
2944
+ const candidate = {
2945
+ schemaVersion: safeGet(value, "schemaVersion"),
2946
+ eventId: requiredBoundedString(safeGet(value, "eventId"), "eventId", opts) ?? "",
2947
+ runId: requiredBoundedString(safeGet(value, "runId"), "runId", opts) ?? "",
2948
+ kind: safeGet(value, "kind"),
2949
+ name: requiredBoundedString(safeGet(value, "name"), "name", opts) ?? "",
2950
+ timestamp: requiredBoundedString(safeGet(value, "timestamp"), "timestamp", opts) ?? "",
2951
+ confidence: safeGet(value, "confidence"),
2952
+ source: {
2953
+ type: safeGet(source, "type")
2954
+ }
2955
+ };
2956
+ const parentId = requiredBoundedString(safeGet(value, "parentId"), "parentId", opts);
2957
+ const status = safeGet(value, "status");
2958
+ const startedAt = optionalBoundedString(safeGet(value, "startedAt"), "startedAt", opts);
2959
+ const endedAt = optionalBoundedString(safeGet(value, "endedAt"), "endedAt", opts);
2960
+ const durationMs2 = safeGet(value, "durationMs");
2961
+ const sourceName = optionalBoundedString(safeGet(source, "name"), "name", opts);
2962
+ const sourceVersion = optionalBoundedString(safeGet(source, "version"), "version", opts);
2963
+ if (parentId !== void 0) candidate.parentId = parentId;
2964
+ if (status === "running" || status === "ok" || status === "error" || status === "unknown") {
2965
+ candidate.status = status;
2966
+ }
2967
+ if (startedAt !== void 0) candidate.startedAt = startedAt;
2968
+ if (endedAt !== void 0) candidate.endedAt = endedAt;
2969
+ if (typeof durationMs2 === "number" && Number.isFinite(durationMs2) && durationMs2 >= 0) {
2970
+ candidate.durationMs = durationMs2;
2971
+ }
2972
+ if (sourceName !== void 0) candidate.source.name = sourceName;
2973
+ if (sourceVersion !== void 0) candidate.source.version = sourceVersion;
2974
+ const attributes = safeGet(value, "attributes");
2975
+ if (isRecord10(attributes)) {
2976
+ candidate.attributes = prepareMetadataForDisk(attributes, opts);
2977
+ }
2978
+ if (safeGet(value, "inputSummary") !== void 0) {
2979
+ candidate.inputSummary = preparePersistedSummaryForDisk(
2980
+ "input",
2981
+ safeGet(value, "inputSummary"),
2982
+ opts
2983
+ );
2984
+ }
2985
+ if (safeGet(value, "outputSummary") !== void 0) {
2986
+ candidate.outputSummary = preparePersistedSummaryForDisk(
2987
+ "output",
2988
+ safeGet(value, "outputSummary"),
2989
+ opts
2990
+ );
2991
+ }
2992
+ const error = preparePersistedErrorForDisk(safeGet(value, "error"), opts);
2993
+ if (error !== void 0) candidate.error = error;
2994
+ const tokenUsage = prepareTokenUsage(safeGet(value, "tokenUsage"));
2995
+ if (tokenUsage !== void 0) candidate.tokenUsage = tokenUsage;
2996
+ const trace = prepareTraceContext(safeGet(value, "trace"), opts);
2997
+ if (trace !== void 0) candidate.trace = trace;
2998
+ if (!isPersistedInspectEvent(candidate)) return void 0;
2999
+ return enforcePersistedEventSize(candidate, opts);
3000
+ } catch {
3001
+ return void 0;
3002
+ }
3003
+ }
2753
3004
 
2754
3005
  // packages/core/src/context.ts
2755
3006
  var storage = new async_hooks.AsyncLocalStorage();
@@ -2934,12 +3185,10 @@ var TraceDirectory = class {
2934
3185
  function isFiniteNumber2(v) {
2935
3186
  return typeof v === "number" && Number.isFinite(v);
2936
3187
  }
2937
- function safeParseJson(line) {
2938
- try {
2939
- return JSON.parse(line);
2940
- } catch {
2941
- return void 0;
2942
- }
3188
+ function parseIsoToMs3(value) {
3189
+ if (value === void 0) return void 0;
3190
+ const parsed = Date.parse(value);
3191
+ return Number.isFinite(parsed) ? parsed : void 0;
2943
3192
  }
2944
3193
  async function extractMetadata(filePath, _quickScan) {
2945
3194
  const stats = await promises.stat(filePath);
@@ -2948,8 +3197,7 @@ async function extractMetadata(filePath, _quickScan) {
2948
3197
  runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
2949
3198
  }
2950
3199
  const raw = await promises.readFile(filePath, "utf-8");
2951
- const lines = raw.split(/\r?\n/);
2952
- let eventCount = 0;
3200
+ const parsedTrace = parseTraceJsonl(raw, { warnings: false });
2953
3201
  let runId;
2954
3202
  let name;
2955
3203
  let startedAt;
@@ -2959,16 +3207,32 @@ async function extractMetadata(filePath, _quickScan) {
2959
3207
  let hasRunCompleted = false;
2960
3208
  let runCompletedStatus;
2961
3209
  let anyStepError = false;
2962
- let anyKnownEvent = false;
2963
- for (const line of lines) {
2964
- const trimmed = line.trim();
2965
- if (trimmed === "") continue;
2966
- const parsed = safeParseJson(trimmed);
2967
- if (!parsed) continue;
2968
- if (!isTraceEvent(parsed)) continue;
2969
- const e = parsed;
2970
- anyKnownEvent = true;
2971
- eventCount += 1;
3210
+ const anyKnownEvent = parsedTrace.sourceEventCount > 0;
3211
+ let persistedStatus;
3212
+ const persistedRun = parsedTrace.persisted.find(
3213
+ (event) => event.kind === "RUN"
3214
+ );
3215
+ if (persistedRun) {
3216
+ runId = persistedRun.runId;
3217
+ if (persistedRun.name.trim() !== "") {
3218
+ name = persistedRun.name;
3219
+ }
3220
+ startedAt = parseIsoToMs3(persistedRun.startedAt) ?? parseIsoToMs3(persistedRun.timestamp);
3221
+ endedAt = parseIsoToMs3(persistedRun.endedAt);
3222
+ if (isFiniteNumber2(persistedRun.durationMs)) {
3223
+ explicitDurationMs = persistedRun.durationMs;
3224
+ if (endedAt === void 0 && startedAt !== void 0) {
3225
+ endedAt = startedAt + persistedRun.durationMs;
3226
+ }
3227
+ }
3228
+ if (persistedRun.status === "ok") persistedStatus = "success";
3229
+ else if (persistedRun.status === "error") persistedStatus = "error";
3230
+ else if (persistedRun.status === "running") persistedStatus = "running";
3231
+ else if (persistedRun.status === "unknown") persistedStatus = "unknown";
3232
+ } else {
3233
+ runId = parsedTrace.persisted[0]?.runId;
3234
+ }
3235
+ for (const e of parsedTrace.events) {
2972
3236
  if (runId === void 0 && typeof e.runId === "string") {
2973
3237
  runId = e.runId;
2974
3238
  }
@@ -3005,6 +3269,8 @@ async function extractMetadata(filePath, _quickScan) {
3005
3269
  status = runCompletedStatus;
3006
3270
  } else if (anyStepError) {
3007
3271
  status = "error";
3272
+ } else if (persistedStatus !== void 0) {
3273
+ status = persistedStatus;
3008
3274
  } else if (hasRunStarted && !hasRunCompleted) {
3009
3275
  status = "running";
3010
3276
  } else if (anyKnownEvent) {
@@ -3012,20 +3278,23 @@ async function extractMetadata(filePath, _quickScan) {
3012
3278
  } else {
3013
3279
  status = "unknown";
3014
3280
  }
3015
- const durationMs = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
3281
+ const durationMs2 = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
3016
3282
  return {
3017
3283
  runId: resolvedRunId,
3018
3284
  name,
3019
3285
  status,
3020
3286
  startedAt,
3021
3287
  endedAt,
3022
- durationMs,
3023
- eventCount,
3288
+ durationMs: durationMs2,
3289
+ eventCount: parsedTrace.sourceEventCount,
3024
3290
  filePath,
3025
3291
  fileSize: stats.size,
3026
3292
  createdAt: stats.birthtime
3027
3293
  };
3028
3294
  }
3295
+ function isNonNegativeFiniteNumber(value) {
3296
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
3297
+ }
3029
3298
  function buildRunSummary(events) {
3030
3299
  const started = events.find(
3031
3300
  (e) => e.event === "run_started"
@@ -3037,7 +3306,7 @@ function buildRunSummary(events) {
3037
3306
  const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
3038
3307
  const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
3039
3308
  const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
3040
- const durationMs = lastCompleted && isFiniteNumber2(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
3309
+ const durationMs2 = lastCompleted && isFiniteNumber2(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
3041
3310
  started && isFiniteNumber2(started.startTime) ? started.startTime : void 0;
3042
3311
  const steps = /* @__PURE__ */ new Map();
3043
3312
  for (const e of events) {
@@ -3048,8 +3317,10 @@ function buildRunSummary(events) {
3048
3317
  name: s.name,
3049
3318
  status: "running",
3050
3319
  parentId: s.parentId,
3051
- tokensInput: typeof s.metadata?.tokens?.input === "number" ? s.metadata.tokens.input : void 0,
3052
- tokensOutput: typeof s.metadata?.tokens?.output === "number" ? s.metadata.tokens.output : void 0
3320
+ tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
3321
+ tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
3322
+ tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
3323
+ tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
3053
3324
  });
3054
3325
  }
3055
3326
  }
@@ -3071,7 +3342,11 @@ function buildRunSummary(events) {
3071
3342
  let longestStep;
3072
3343
  let totalTokensInput = 0;
3073
3344
  let totalTokensOutput = 0;
3074
- let hasAnyTokens = false;
3345
+ let totalTokensTotal = 0;
3346
+ let totalTokensCached = 0;
3347
+ let tokenBearingSteps = 0;
3348
+ let stepsWithKnownTotal = 0;
3349
+ let hasCachedTokens = false;
3075
3350
  const depthCache = /* @__PURE__ */ new Map();
3076
3351
  const computeDepth = (stepId) => {
3077
3352
  const cached = depthCache.get(stepId);
@@ -3100,17 +3375,28 @@ function buildRunSummary(events) {
3100
3375
  longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
3101
3376
  }
3102
3377
  }
3103
- if (typeof s.tokensInput === "number" || typeof s.tokensOutput === "number") {
3104
- hasAnyTokens = true;
3105
- if (typeof s.tokensInput === "number") totalTokensInput += s.tokensInput;
3106
- if (typeof s.tokensOutput === "number") totalTokensOutput += s.tokensOutput;
3378
+ if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
3379
+ tokenBearingSteps += 1;
3380
+ if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
3381
+ if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
3382
+ if (s.tokensTotal !== void 0) {
3383
+ totalTokensTotal += s.tokensTotal;
3384
+ stepsWithKnownTotal += 1;
3385
+ } else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
3386
+ totalTokensTotal += s.tokensInput + s.tokensOutput;
3387
+ stepsWithKnownTotal += 1;
3388
+ }
3389
+ if (s.tokensCached !== void 0) {
3390
+ totalTokensCached += s.tokensCached;
3391
+ hasCachedTokens = true;
3392
+ }
3107
3393
  }
3108
3394
  }
3109
3395
  const summary = {
3110
3396
  runId,
3111
3397
  name,
3112
3398
  status,
3113
- durationMs,
3399
+ durationMs: durationMs2,
3114
3400
  totalSteps,
3115
3401
  llmSteps,
3116
3402
  toolSteps,
@@ -3118,7 +3404,14 @@ function buildRunSummary(events) {
3118
3404
  errorSteps,
3119
3405
  maxDepth,
3120
3406
  ...longestStep ? { longestStep } : {},
3121
- ...hasAnyTokens ? { totalTokens: { input: totalTokensInput, output: totalTokensOutput } } : {}
3407
+ ...tokenBearingSteps > 0 ? {
3408
+ totalTokens: {
3409
+ input: totalTokensInput,
3410
+ output: totalTokensOutput,
3411
+ ...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
3412
+ ...hasCachedTokens ? { cached: totalTokensCached } : {}
3413
+ }
3414
+ } : {}
3122
3415
  };
3123
3416
  return summary;
3124
3417
  }
@@ -3423,9 +3716,17 @@ function renderRunWhat(summary, options = {}) {
3423
3716
  `Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
3424
3717
  );
3425
3718
  if (summary.totalTokens) {
3426
- lines.push(
3427
- `Tokens: ${summary.totalTokens.input} in / ${summary.totalTokens.output} out`
3428
- );
3719
+ const tokenParts = [
3720
+ `${summary.totalTokens.input} in`,
3721
+ `${summary.totalTokens.output} out`
3722
+ ];
3723
+ if (summary.totalTokens.total !== void 0) {
3724
+ tokenParts.push(`${summary.totalTokens.total} total`);
3725
+ }
3726
+ if (summary.totalTokens.cached !== void 0) {
3727
+ tokenParts.push(`${summary.totalTokens.cached} cached`);
3728
+ }
3729
+ lines.push(`Tokens: ${tokenParts.join(" / ")}`);
3429
3730
  }
3430
3731
  if (showCorrelation && summary.correlation) {
3431
3732
  const parts = [];
@@ -3881,7 +4182,7 @@ function manualTraceEventsToRunTree(events) {
3881
4182
  }
3882
4183
  const startedAt = started.startTime;
3883
4184
  const endedAt = lastCompleted !== void 0 && runStatus !== "running" ? lastCompleted.endTime : void 0;
3884
- const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
4185
+ const durationMs2 = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
3885
4186
  const steps = /* @__PURE__ */ new Map();
3886
4187
  for (const e of events) {
3887
4188
  if (e.event !== "step_started") continue;
@@ -3970,7 +4271,7 @@ function manualTraceEventsToRunTree(events) {
3970
4271
  status: runStatus,
3971
4272
  startedAt,
3972
4273
  endedAt,
3973
- durationMs,
4274
+ durationMs: durationMs2,
3974
4275
  children: roots,
3975
4276
  metadata: {
3976
4277
  totalEvents: inspectNodes.size,
@@ -3981,7 +4282,7 @@ function manualTraceEventsToRunTree(events) {
3981
4282
  }
3982
4283
 
3983
4284
  // packages/core/src/exporters/redact-export.ts
3984
- function isRecord10(value) {
4285
+ function isRecord11(value) {
3985
4286
  return typeof value === "object" && value !== null && !Array.isArray(value);
3986
4287
  }
3987
4288
  function deepClone(value) {
@@ -4055,7 +4356,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
4055
4356
  0
4056
4357
  );
4057
4358
  const err = bounded.error;
4058
- if (isRecord10(err) && typeof err.message === "string") {
4359
+ if (isRecord11(err) && typeof err.message === "string") {
4059
4360
  bounded.error = {
4060
4361
  ...err,
4061
4362
  message: truncateStringForProfile(
@@ -4076,6 +4377,89 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
4076
4377
  }
4077
4378
  return bounded;
4078
4379
  }
4380
+ function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLength) {
4381
+ if (error === void 0) return void 0;
4382
+ const record = redactEventAttributes(
4383
+ { error },
4384
+ redactor,
4385
+ maxMetadataValueLength,
4386
+ maxPreviewLength
4387
+ );
4388
+ const redacted = record?.error;
4389
+ if (!isRecord11(redacted) || typeof redacted.message !== "string") {
4390
+ return void 0;
4391
+ }
4392
+ return {
4393
+ message: redacted.message,
4394
+ ...typeof redacted.stack === "string" ? { stack: redacted.stack } : {}
4395
+ };
4396
+ }
4397
+ function redactTraceEventsForReport(events, options) {
4398
+ const profile = options?.redactionProfile ?? "local";
4399
+ if (profile === "local") {
4400
+ return deepClone(events);
4401
+ }
4402
+ const resolved = resolveRedactionProfile(profile);
4403
+ const { maxMetadataValueLength, maxPreviewLength } = applyProfileMetadataCaps(
4404
+ 2e3,
4405
+ 500,
4406
+ resolved
4407
+ );
4408
+ const redactor = new Redactor({ extraKeys: resolved.extraKeys });
4409
+ return events.map((event) => {
4410
+ switch (event.event) {
4411
+ case "run_started":
4412
+ return {
4413
+ ...event,
4414
+ name: truncateStringForProfile(
4415
+ event.name,
4416
+ "name",
4417
+ maxMetadataValueLength,
4418
+ maxPreviewLength
4419
+ ),
4420
+ ...event.metadata !== void 0 ? {
4421
+ metadata: redactEventAttributes(
4422
+ event.metadata,
4423
+ redactor,
4424
+ maxMetadataValueLength,
4425
+ maxPreviewLength
4426
+ )
4427
+ } : {}
4428
+ };
4429
+ case "step_started":
4430
+ return {
4431
+ ...event,
4432
+ name: truncateStringForProfile(
4433
+ event.name,
4434
+ "name",
4435
+ maxMetadataValueLength,
4436
+ maxPreviewLength
4437
+ ),
4438
+ ...event.metadata !== void 0 ? {
4439
+ metadata: redactEventAttributes(
4440
+ event.metadata,
4441
+ redactor,
4442
+ maxMetadataValueLength,
4443
+ maxPreviewLength
4444
+ )
4445
+ } : {}
4446
+ };
4447
+ case "run_completed":
4448
+ case "step_completed":
4449
+ return {
4450
+ ...event,
4451
+ ...event.error !== void 0 ? {
4452
+ error: redactErrorInfo(
4453
+ event.error,
4454
+ redactor,
4455
+ maxMetadataValueLength,
4456
+ maxPreviewLength
4457
+ )
4458
+ } : {}
4459
+ };
4460
+ }
4461
+ });
4462
+ }
4079
4463
  function redactRunTreeForExport(tree, options) {
4080
4464
  const profile = options?.redactionProfile ?? "local";
4081
4465
  if (profile === "local") {
@@ -4139,12 +4523,15 @@ footer{margin-top:2rem;font-size:0.85rem;color:#555}
4139
4523
  `.trim();
4140
4524
  function buildRunReport(events, options) {
4141
4525
  const profile = options.redactionProfile ?? "local";
4142
- const whatSummary = buildRunWhatSummary(events);
4526
+ const safeEvents = redactTraceEventsForReport(events, {
4527
+ redactionProfile: profile
4528
+ });
4529
+ const whatSummary = buildRunWhatSummary(safeEvents);
4143
4530
  const whatText = renderRunWhat(whatSummary, {
4144
4531
  correlation: options.correlation !== false
4145
4532
  });
4146
- const timelineText = renderTimeline(buildRunTimeline(events));
4147
- const tree = resolveTree(events, profile);
4533
+ const timelineText = renderTimeline(buildRunTimeline(safeEvents));
4534
+ const tree = resolveTree(safeEvents, profile);
4148
4535
  const exportOpts = {
4149
4536
  includeMetadata: false,
4150
4537
  includeAttributes: options.includeAttributes === true,
@@ -4225,6 +4612,8 @@ ${attrsSection}
4225
4612
  fileExtension: ".html"
4226
4613
  };
4227
4614
  }
4615
+
4616
+ // packages/core/src/stats.ts
4228
4617
  function percentile(sorted, p) {
4229
4618
  if (sorted.length === 0) return void 0;
4230
4619
  const idx = Math.min(
@@ -4235,19 +4624,10 @@ function percentile(sorted, p) {
4235
4624
  }
4236
4625
  async function readRunStartedMetadata(filePath) {
4237
4626
  try {
4238
- const raw = await promises.readFile(filePath, "utf-8");
4239
- for (const line of raw.split(/\r?\n/)) {
4240
- const trimmed = line.trim();
4241
- if (trimmed === "") continue;
4242
- let parsed;
4243
- try {
4244
- parsed = JSON.parse(trimmed);
4245
- } catch {
4246
- continue;
4247
- }
4248
- if (!isTraceEvent(parsed)) continue;
4249
- if (parsed.event !== "run_started") continue;
4250
- const rs = parsed;
4627
+ const events = await readTraceEventsFromFile(filePath);
4628
+ for (const event of events) {
4629
+ if (event.event !== "run_started") continue;
4630
+ const rs = event;
4251
4631
  if (rs.metadata && typeof rs.metadata === "object") {
4252
4632
  return rs.metadata;
4253
4633
  }
@@ -4306,7 +4686,7 @@ async function buildTraceStats(metas, options) {
4306
4686
  });
4307
4687
  }
4308
4688
  try {
4309
- const events = await readTraceEvents(m.runId, options.traceDir);
4689
+ const events = await readTraceEventsFromFile(m.filePath);
4310
4690
  if (events.length === 0) continue;
4311
4691
  const summary = buildRunSummary(events);
4312
4692
  totalSteps += summary.totalSteps;
@@ -4494,7 +4874,7 @@ async function searchTraces(metas, options) {
4494
4874
  if (options.status && m.status !== options.status) continue;
4495
4875
  let events = [];
4496
4876
  try {
4497
- events = await readTraceEvents(m.runId, options.traceDir);
4877
+ events = await readTraceEventsFromFile(m.filePath);
4498
4878
  } catch {
4499
4879
  continue;
4500
4880
  }
@@ -4630,7 +5010,7 @@ var KNOWN_EVENTS = /* @__PURE__ */ new Set([
4630
5010
  "step_started",
4631
5011
  "step_completed"
4632
5012
  ]);
4633
- function isRecord11(value) {
5013
+ function isRecord12(value) {
4634
5014
  return typeof value === "object" && value !== null && !Array.isArray(value);
4635
5015
  }
4636
5016
  function safeParse(line) {
@@ -4652,7 +5032,7 @@ async function isAgentInspectTrace(filePath) {
4652
5032
  if (trimmed === "") continue;
4653
5033
  const parsed = safeParse(trimmed);
4654
5034
  if (!parsed) continue;
4655
- if (!isRecord11(parsed)) continue;
5035
+ if (!isRecord12(parsed)) continue;
4656
5036
  checked += 1;
4657
5037
  if (isTraceEvent(parsed)) return true;
4658
5038
  const ev = parsed.event;
@@ -4667,64 +5047,2417 @@ async function isAgentInspectTrace(filePath) {
4667
5047
  return false;
4668
5048
  }
4669
5049
  }
4670
-
4671
- // packages/core/src/diff/comparable.ts
4672
- function extractOutputPreview(meta) {
4673
- if (meta === void 0) return void 0;
4674
- if ("outputPreview" in meta) return meta.outputPreview;
4675
- if ("resultPreview" in meta) return meta.resultPreview;
4676
- return void 0;
4677
- }
4678
- function mapStepStatus2(s) {
4679
- if (s === void 0) return "running";
4680
- return s;
5050
+ function invoke2(fn) {
5051
+ return new Promise((resolve, reject) => {
5052
+ try {
5053
+ Promise.resolve(fn()).then(resolve, reject);
5054
+ } catch (error) {
5055
+ reject(error);
5056
+ }
5057
+ });
4681
5058
  }
4682
- function manualTraceEventsToComparableRun(events) {
4683
- const started = events.find((e) => e.event === "run_started");
4684
- if (!started || started.event !== "run_started") {
4685
- throw new Error("Invalid trace: missing run_started");
5059
+ function normalizeError(error) {
5060
+ if (error instanceof Error && error.message.trim() !== "") {
5061
+ return error.message;
4686
5062
  }
4687
- const rs = started;
4688
- const runId = rs.runId;
4689
- const completedAll = events.filter((e) => e.event === "run_completed");
4690
- const lastCompleted = completedAll[completedAll.length - 1];
4691
- let runStatus;
4692
- if (lastCompleted === void 0) runStatus = "running";
4693
- else runStatus = lastCompleted.status;
4694
- const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
4695
- const steps = /* @__PURE__ */ new Map();
4696
- let order = 0;
4697
- for (const e of events) {
4698
- if (e.event !== "step_started") continue;
4699
- const s = e;
4700
- const meta = s.metadata ? { ...s.metadata } : void 0;
4701
- steps.set(s.stepId, {
4702
- id: s.stepId,
4703
- parentId: s.parentId,
4704
- name: s.name,
4705
- type: s.type,
4706
- order: order++,
4707
- timestamp: s.timestamp,
4708
- metadata: meta
4709
- });
5063
+ if (typeof error === "string" && error.trim() !== "") {
5064
+ return error;
4710
5065
  }
4711
- for (const e of events) {
4712
- if (e.event !== "step_completed") continue;
4713
- const acc = steps.get(e.stepId);
4714
- if (!acc) continue;
4715
- acc.status = e.status;
4716
- acc.durationMs = e.durationMs;
4717
- if (e.error?.message) acc.errorMsg = e.error.message;
4718
- const extra = e;
4719
- if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
4720
- acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
5066
+ return "Unknown inspector runtime error";
5067
+ }
5068
+ var runtimeSequence = 0;
5069
+ function createRuntimeId() {
5070
+ runtimeSequence += 1;
5071
+ return `runtime_${runtimeSequence.toString(36)}`;
5072
+ }
5073
+ function publicContext(store) {
5074
+ return {
5075
+ runtimeId: store.runtimeId,
5076
+ runId: store.runId,
5077
+ runName: store.runName,
5078
+ traceDir: store.traceDir,
5079
+ silent: store.silent,
5080
+ metadata: store.metadata
5081
+ };
5082
+ }
5083
+ function createInspectorRuntime(options = {}) {
5084
+ const storage2 = new async_hooks.AsyncLocalStorage();
5085
+ const enabled = options.enabled ?? true;
5086
+ const runtimeId = createRuntimeId();
5087
+ const traceSafety = options.traceSafety ?? resolveTraceSafetyOptions();
5088
+ let closed = false;
5089
+ let instrumentationErrors = 0;
5090
+ let lastInstrumentationError;
5091
+ function recordInstrumentationError(error) {
5092
+ instrumentationErrors += 1;
5093
+ lastInstrumentationError = normalizeError(error);
5094
+ }
5095
+ function currentStore() {
5096
+ try {
5097
+ return storage2.getStore();
5098
+ } catch (error) {
5099
+ recordInstrumentationError(error);
5100
+ return void 0;
4721
5101
  }
4722
5102
  }
4723
- const nodes = /* @__PURE__ */ new Map();
4724
- for (const acc of steps.values()) {
4725
- let meta = acc.metadata ? { ...acc.metadata } : void 0;
4726
- if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
4727
- meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
5103
+ const runtime = {
5104
+ runtimeId,
5105
+ enabled,
5106
+ runWithContext(context, fn) {
5107
+ if (!enabled) return invoke2(fn);
5108
+ const store = {
5109
+ runtimeId,
5110
+ runId: context.runId,
5111
+ runName: context.runName,
5112
+ traceDir: context.traceDir,
5113
+ silent: context.silent,
5114
+ metadata: context.metadata,
5115
+ traceSafety,
5116
+ currentDepth: 0
5117
+ };
5118
+ return new Promise((resolve, reject) => {
5119
+ storage2.run(store, () => {
5120
+ invoke2(fn).then(resolve, reject);
5121
+ });
5122
+ });
5123
+ },
5124
+ runWithStepContext(stepId, fn) {
5125
+ if (!enabled) return invoke2(fn);
5126
+ const parent = currentStore();
5127
+ if (!parent) return invoke2(fn);
5128
+ const store = {
5129
+ runtimeId,
5130
+ runId: parent.runId,
5131
+ runName: parent.runName,
5132
+ traceDir: parent.traceDir,
5133
+ silent: parent.silent,
5134
+ metadata: parent.metadata,
5135
+ traceSafety: parent.traceSafety,
5136
+ currentStepId: stepId,
5137
+ currentDepth: parent.currentDepth + 1
5138
+ };
5139
+ return new Promise((resolve, reject) => {
5140
+ storage2.run(store, () => {
5141
+ invoke2(fn).then(resolve, reject);
5142
+ });
5143
+ });
5144
+ },
5145
+ getCurrentContext() {
5146
+ const store = currentStore();
5147
+ return store ? publicContext(store) : void 0;
5148
+ },
5149
+ getCurrentCorrelationMetadata() {
5150
+ return extractCorrelationMetadata(currentStore()?.metadata);
5151
+ },
5152
+ getCurrentStepId() {
5153
+ return currentStore()?.currentStepId;
5154
+ },
5155
+ getCurrentDepth() {
5156
+ const depth = currentStore()?.currentDepth;
5157
+ return typeof depth === "number" && Number.isFinite(depth) ? depth : 0;
5158
+ },
5159
+ getTraceSafety() {
5160
+ return traceSafety;
5161
+ },
5162
+ async write(event) {
5163
+ if (!enabled || closed || !options.writer) return;
5164
+ try {
5165
+ const safe = preparePersistedInspectEventForWrite(event, traceSafety);
5166
+ if (safe === void 0) {
5167
+ recordInstrumentationError("Invalid persisted inspect event");
5168
+ return;
5169
+ }
5170
+ await options.writer.write(safe);
5171
+ } catch (error) {
5172
+ recordInstrumentationError(error);
5173
+ }
5174
+ },
5175
+ async flush() {
5176
+ if (!options.writer) return;
5177
+ try {
5178
+ await options.writer.flush?.();
5179
+ } catch (error) {
5180
+ recordInstrumentationError(error);
5181
+ }
5182
+ },
5183
+ async close() {
5184
+ if (closed) return;
5185
+ try {
5186
+ await options.writer?.close?.();
5187
+ } catch (error) {
5188
+ recordInstrumentationError(error);
5189
+ } finally {
5190
+ closed = true;
5191
+ }
5192
+ },
5193
+ getDiagnostics() {
5194
+ const diagnostics = {
5195
+ instrumentationErrors
5196
+ };
5197
+ if (lastInstrumentationError !== void 0) {
5198
+ diagnostics.lastInstrumentationError = lastInstrumentationError;
5199
+ }
5200
+ const writerStats = options.writer?.getStats?.();
5201
+ if (writerStats !== void 0) {
5202
+ diagnostics.writerStats = writerStats;
5203
+ }
5204
+ return diagnostics;
5205
+ }
5206
+ };
5207
+ return runtime;
5208
+ }
5209
+
5210
+ // packages/core/src/inspector.ts
5211
+ function normalizeName(name, fallback) {
5212
+ if (typeof name !== "string" || name.trim() === "") return fallback;
5213
+ return truncateName(name.trim(), 100);
5214
+ }
5215
+ function nowIso() {
5216
+ return (/* @__PURE__ */ new Date()).toISOString();
5217
+ }
5218
+ function durationMs(startedAt, endedAt) {
5219
+ return Math.max(0, Date.parse(endedAt) - Date.parse(startedAt));
5220
+ }
5221
+ function mergeMetadata(base, override) {
5222
+ if (base === void 0 && override === void 0) return void 0;
5223
+ return {
5224
+ ...base ?? {},
5225
+ ...override ?? {}
5226
+ };
5227
+ }
5228
+ function toPersistedError(error) {
5229
+ if (error instanceof Error) {
5230
+ return {
5231
+ name: error.name,
5232
+ message: error.message
5233
+ };
5234
+ }
5235
+ if (typeof error === "string") {
5236
+ return { message: error };
5237
+ }
5238
+ return { message: "Unknown error" };
5239
+ }
5240
+ function summarizeValue(value) {
5241
+ if (value === null) return { type: "null" };
5242
+ if (Array.isArray(value)) return { type: "array", length: value.length };
5243
+ if (typeof value === "string") return { type: "string", length: value.length };
5244
+ if (typeof value === "number") {
5245
+ return { type: "number", finite: Number.isFinite(value) };
5246
+ }
5247
+ if (typeof value === "bigint") return { type: "bigint" };
5248
+ if (typeof value === "boolean") return { type: "boolean" };
5249
+ if (typeof value === "undefined") return { type: "undefined" };
5250
+ if (typeof value === "symbol") return { type: "symbol" };
5251
+ if (typeof value === "function") {
5252
+ return { type: "function", name: value.name || void 0 };
5253
+ }
5254
+ if (typeof value === "object") {
5255
+ const record = value;
5256
+ let keyCount;
5257
+ try {
5258
+ keyCount = Object.keys(record).length;
5259
+ } catch {
5260
+ keyCount = void 0;
5261
+ }
5262
+ return {
5263
+ type: "object",
5264
+ constructorName: value?.constructor?.name,
5265
+ ...keyCount !== void 0 ? { keyCount } : {}
5266
+ };
5267
+ }
5268
+ return { type: typeof value };
5269
+ }
5270
+ function summarizeCapturedError(error) {
5271
+ if (error instanceof Error) {
5272
+ return { type: "error", name: error.name };
5273
+ }
5274
+ return summarizeValue(error);
5275
+ }
5276
+ function stepTypeToKind(type) {
5277
+ switch (type) {
5278
+ case "llm":
5279
+ return "LLM";
5280
+ case "tool":
5281
+ return "TOOL";
5282
+ case "decision":
5283
+ return "DECISION";
5284
+ case "run":
5285
+ return "RUN";
5286
+ default:
5287
+ return "LOGIC";
5288
+ }
5289
+ }
5290
+ function createInspector(options = {}) {
5291
+ const traceSafety = options.traceSafety ?? resolveTraceSafetyOptions({
5292
+ redactionProfile: options.redactionProfile
5293
+ });
5294
+ const runtime = createInspectorRuntime({
5295
+ enabled: options.enabled,
5296
+ writer: options.writer,
5297
+ traceSafety
5298
+ });
5299
+ async function write(event) {
5300
+ const safe = preparePersistedInspectEventForWrite(event, traceSafety);
5301
+ if (safe !== void 0) {
5302
+ await runtime.write(safe);
5303
+ }
5304
+ }
5305
+ async function run(name, fn, runOptions = {}) {
5306
+ if (typeof fn !== "function") {
5307
+ throw new TypeError("inspector.run requires `fn` to be a function");
5308
+ }
5309
+ if (options.enabled === false) {
5310
+ return Promise.resolve(fn());
5311
+ }
5312
+ const runName = normalizeName(name, "unnamed-run");
5313
+ const runId = runOptions.runId ?? createRunId();
5314
+ const traceDir = runOptions.traceDir ?? options.traceDir ?? getDefaultTraceDir();
5315
+ const metadata = mergeMetadata(options.metadata, runOptions.metadata);
5316
+ const startedAt = nowIso();
5317
+ return runtime.runWithContext(
5318
+ {
5319
+ runId,
5320
+ runName,
5321
+ traceDir,
5322
+ silent: runOptions.silent ?? options.silent ?? true,
5323
+ metadata
5324
+ },
5325
+ async () => {
5326
+ await write({
5327
+ schemaVersion: "0.2",
5328
+ eventId: `${runId}_started`,
5329
+ runId,
5330
+ kind: "RUN",
5331
+ name: runName,
5332
+ status: "running",
5333
+ timestamp: startedAt,
5334
+ startedAt,
5335
+ confidence: "explicit",
5336
+ source: { type: "manual", name: "createInspector" },
5337
+ attributes: {
5338
+ legacyEvent: "run_started",
5339
+ ...metadata !== void 0 ? { metadata } : {}
5340
+ }
5341
+ });
5342
+ try {
5343
+ const result = await Promise.resolve(fn());
5344
+ const endedAt = nowIso();
5345
+ await write({
5346
+ schemaVersion: "0.2",
5347
+ eventId: `${runId}_completed`,
5348
+ runId,
5349
+ kind: "RUN",
5350
+ name: runName,
5351
+ status: "ok",
5352
+ timestamp: endedAt,
5353
+ endedAt,
5354
+ durationMs: durationMs(startedAt, endedAt),
5355
+ confidence: "explicit",
5356
+ source: { type: "manual", name: "createInspector" },
5357
+ attributes: { legacyEvent: "run_completed" },
5358
+ ...options.capture?.onSuccess === "metadata-only" ? { outputSummary: summarizeValue(result) } : {}
5359
+ });
5360
+ return result;
5361
+ } catch (error) {
5362
+ const endedAt = nowIso();
5363
+ await write({
5364
+ schemaVersion: "0.2",
5365
+ eventId: `${runId}_completed`,
5366
+ runId,
5367
+ kind: "RUN",
5368
+ name: runName,
5369
+ status: "error",
5370
+ timestamp: endedAt,
5371
+ endedAt,
5372
+ durationMs: durationMs(startedAt, endedAt),
5373
+ confidence: "explicit",
5374
+ source: { type: "manual", name: "createInspector" },
5375
+ attributes: { legacyEvent: "run_completed" },
5376
+ ...options.capture?.onError === "metadata-only" ? { outputSummary: summarizeCapturedError(error) } : {},
5377
+ error: toPersistedError(error)
5378
+ });
5379
+ throw error;
5380
+ }
5381
+ }
5382
+ );
5383
+ }
5384
+ async function step2(name, fn, stepOptions = {}) {
5385
+ if (typeof fn !== "function") {
5386
+ throw new TypeError("inspector.step requires `fn` to be a function");
5387
+ }
5388
+ if (options.enabled === false || !runtime.getCurrentContext()) {
5389
+ return Promise.resolve(fn());
5390
+ }
5391
+ const context = runtime.getCurrentContext();
5392
+ const stepName = normalizeName(name, "unnamed-step");
5393
+ const stepId = createStepId();
5394
+ const parentId = runtime.getCurrentStepId();
5395
+ const stepType = stepOptions.type ?? "logic";
5396
+ const startedAt = nowIso();
5397
+ const attributes = {
5398
+ legacyEvent: "step_started",
5399
+ stepId,
5400
+ stepType,
5401
+ ...stepOptions.metadata !== void 0 ? { metadata: stepOptions.metadata } : {}
5402
+ };
5403
+ await write({
5404
+ schemaVersion: "0.2",
5405
+ eventId: `${stepId}_started`,
5406
+ runId: context.runId,
5407
+ ...parentId !== void 0 ? { parentId } : {},
5408
+ kind: stepTypeToKind(stepType),
5409
+ name: stepName,
5410
+ status: "running",
5411
+ timestamp: startedAt,
5412
+ startedAt,
5413
+ confidence: "explicit",
5414
+ source: { type: "manual", name: "createInspector" },
5415
+ attributes
5416
+ });
5417
+ return runtime.runWithStepContext(stepId, async () => {
5418
+ try {
5419
+ const result = await Promise.resolve(fn());
5420
+ const endedAt = nowIso();
5421
+ await write({
5422
+ schemaVersion: "0.2",
5423
+ eventId: `${stepId}_completed`,
5424
+ runId: context.runId,
5425
+ kind: stepTypeToKind(stepType),
5426
+ name: stepName,
5427
+ status: "ok",
5428
+ timestamp: endedAt,
5429
+ endedAt,
5430
+ durationMs: durationMs(startedAt, endedAt),
5431
+ confidence: "explicit",
5432
+ source: { type: "manual", name: "createInspector" },
5433
+ attributes: {
5434
+ legacyEvent: "step_completed",
5435
+ stepId,
5436
+ stepType
5437
+ },
5438
+ ...options.capture?.onSuccess === "metadata-only" ? { outputSummary: summarizeValue(result) } : {}
5439
+ });
5440
+ return result;
5441
+ } catch (error) {
5442
+ const endedAt = nowIso();
5443
+ await write({
5444
+ schemaVersion: "0.2",
5445
+ eventId: `${stepId}_completed`,
5446
+ runId: context.runId,
5447
+ kind: stepTypeToKind(stepType),
5448
+ name: stepName,
5449
+ status: "error",
5450
+ timestamp: endedAt,
5451
+ endedAt,
5452
+ durationMs: durationMs(startedAt, endedAt),
5453
+ confidence: "explicit",
5454
+ source: { type: "manual", name: "createInspector" },
5455
+ attributes: {
5456
+ legacyEvent: "step_completed",
5457
+ stepId,
5458
+ stepType
5459
+ },
5460
+ ...options.capture?.onError === "metadata-only" ? { outputSummary: summarizeCapturedError(error) } : {},
5461
+ error: toPersistedError(error)
5462
+ });
5463
+ throw error;
5464
+ }
5465
+ });
5466
+ }
5467
+ const inspector = {
5468
+ runtime,
5469
+ run,
5470
+ step: step2,
5471
+ tool(name, fn, toolOptions) {
5472
+ const toolName = normalizeName(name, "unknown-tool");
5473
+ return step2(`tool:${toolName}`, fn, {
5474
+ ...toolOptions,
5475
+ type: "tool",
5476
+ metadata: {
5477
+ ...toolOptions?.metadata ?? {},
5478
+ toolName
5479
+ }
5480
+ });
5481
+ },
5482
+ llm(name, fn, llmOptions) {
5483
+ const model = normalizeName(name, "unknown-model");
5484
+ return step2(`llm:${model}`, fn, {
5485
+ ...llmOptions,
5486
+ type: "llm",
5487
+ metadata: {
5488
+ ...llmOptions?.metadata ?? {},
5489
+ model
5490
+ }
5491
+ });
5492
+ },
5493
+ observe(name, fn, observeOptions) {
5494
+ return async (...args) => step2(name, () => Promise.resolve(fn(...args)), observeOptions);
5495
+ },
5496
+ getDiagnostics() {
5497
+ return runtime.getDiagnostics();
5498
+ },
5499
+ flush() {
5500
+ return runtime.flush();
5501
+ },
5502
+ close() {
5503
+ return runtime.close();
5504
+ }
5505
+ };
5506
+ return inspector;
5507
+ }
5508
+ var DEFAULT_TRACE_SAFETY = resolveTraceSafetyOptions();
5509
+ function createInitialStats() {
5510
+ return {
5511
+ writtenEvents: 0,
5512
+ droppedEvents: 0,
5513
+ flushCount: 0
5514
+ };
5515
+ }
5516
+ function markFlush(stats) {
5517
+ stats.flushCount += 1;
5518
+ stats.lastFlushAt = (/* @__PURE__ */ new Date()).toISOString();
5519
+ }
5520
+ function cloneStats(stats) {
5521
+ return { ...stats };
5522
+ }
5523
+ function normalizeError2(error) {
5524
+ if (error instanceof Error && error.message.trim() !== "") {
5525
+ return error.message;
5526
+ }
5527
+ if (typeof error === "string" && error.trim() !== "") {
5528
+ return error;
5529
+ }
5530
+ return "Unknown trace writer error";
5531
+ }
5532
+ function recordDropped(stats, error) {
5533
+ stats.droppedEvents += 1;
5534
+ stats.lastError = normalizeError2(error);
5535
+ }
5536
+ function prepareWriterEvent(event) {
5537
+ return preparePersistedInspectEventForWrite(event, DEFAULT_TRACE_SAFETY);
5538
+ }
5539
+ function resolveFilePath(event, options) {
5540
+ if (options.filePath && options.filePath.trim() !== "") {
5541
+ return path__default.default.resolve(options.filePath);
5542
+ }
5543
+ return getTraceFilePath(event.runId, options.dir);
5544
+ }
5545
+ function serializeEvent2(event) {
5546
+ return `${JSON.stringify(event)}
5547
+ `;
5548
+ }
5549
+ async function appendEventLine(event, options) {
5550
+ const filePath = resolveFilePath(event, options);
5551
+ await promises.mkdir(path__default.default.dirname(filePath), { recursive: true });
5552
+ await promises.appendFile(filePath, serializeEvent2(event), "utf-8");
5553
+ }
5554
+ async function appendEventBatch(events, options) {
5555
+ const byPath = /* @__PURE__ */ new Map();
5556
+ let dropped = 0;
5557
+ let lastError;
5558
+ for (const event of events) {
5559
+ try {
5560
+ const filePath = resolveFilePath(event, options);
5561
+ const line = serializeEvent2(event);
5562
+ const lines = byPath.get(filePath);
5563
+ if (lines) {
5564
+ lines.push(line);
5565
+ } else {
5566
+ byPath.set(filePath, [line]);
5567
+ }
5568
+ } catch (error) {
5569
+ dropped += 1;
5570
+ lastError = normalizeError2(error);
5571
+ }
5572
+ }
5573
+ let written = 0;
5574
+ for (const [filePath, lines] of byPath) {
5575
+ try {
5576
+ await promises.mkdir(path__default.default.dirname(filePath), { recursive: true });
5577
+ await promises.appendFile(filePath, lines.join(""), "utf-8");
5578
+ written += lines.length;
5579
+ } catch (error) {
5580
+ dropped += lines.length;
5581
+ lastError = normalizeError2(error);
5582
+ }
5583
+ }
5584
+ return lastError ? { written, dropped, lastError } : { written, dropped };
5585
+ }
5586
+ function memoryWriter() {
5587
+ const events = [];
5588
+ const stats = createInitialStats();
5589
+ return {
5590
+ async write(event) {
5591
+ const safe = prepareWriterEvent(event);
5592
+ if (safe === void 0) {
5593
+ recordDropped(stats, "Invalid persisted inspect event");
5594
+ return;
5595
+ }
5596
+ events.push(safe);
5597
+ stats.writtenEvents += 1;
5598
+ },
5599
+ async flush() {
5600
+ markFlush(stats);
5601
+ },
5602
+ async close() {
5603
+ },
5604
+ getStats() {
5605
+ return cloneStats(stats);
5606
+ },
5607
+ getEvents() {
5608
+ return events.map((event) => structuredClone(event));
5609
+ },
5610
+ clear() {
5611
+ events.length = 0;
5612
+ }
5613
+ };
5614
+ }
5615
+ function nullWriter() {
5616
+ const stats = createInitialStats();
5617
+ return {
5618
+ async write() {
5619
+ stats.writtenEvents += 1;
5620
+ },
5621
+ async flush() {
5622
+ markFlush(stats);
5623
+ },
5624
+ async close() {
5625
+ },
5626
+ getStats() {
5627
+ return cloneStats(stats);
5628
+ }
5629
+ };
5630
+ }
5631
+ function fileWriter(options = {}) {
5632
+ const stats = createInitialStats();
5633
+ let closed = false;
5634
+ let queue = Promise.resolve();
5635
+ const enqueue = (event) => {
5636
+ const operation = queue.then(async () => {
5637
+ if (closed) {
5638
+ recordDropped(stats, "Trace writer is closed");
5639
+ return;
5640
+ }
5641
+ try {
5642
+ await appendEventLine(event, options);
5643
+ stats.writtenEvents += 1;
5644
+ } catch (error) {
5645
+ recordDropped(stats, error);
5646
+ }
5647
+ });
5648
+ queue = operation.catch(() => {
5649
+ });
5650
+ return operation.catch(() => {
5651
+ });
5652
+ };
5653
+ return {
5654
+ write(event) {
5655
+ const safe = prepareWriterEvent(event);
5656
+ if (safe === void 0) {
5657
+ recordDropped(stats, "Invalid persisted inspect event");
5658
+ return Promise.resolve();
5659
+ }
5660
+ return enqueue(safe);
5661
+ },
5662
+ async flush() {
5663
+ await queue;
5664
+ markFlush(stats);
5665
+ },
5666
+ async close() {
5667
+ if (closed) return;
5668
+ await queue;
5669
+ closed = true;
5670
+ },
5671
+ getStats() {
5672
+ return cloneStats(stats);
5673
+ }
5674
+ };
5675
+ }
5676
+ function positiveInteger(value, fallback) {
5677
+ if (value === void 0) return fallback;
5678
+ if (!Number.isFinite(value) || value <= 0) return fallback;
5679
+ return Math.floor(value);
5680
+ }
5681
+ function nonNegativeInteger(value, fallback) {
5682
+ if (value === void 0) return fallback;
5683
+ if (!Number.isFinite(value) || value < 0) return fallback;
5684
+ return Math.floor(value);
5685
+ }
5686
+ function bufferedFileWriter(options = {}) {
5687
+ const stats = createInitialStats();
5688
+ const maxQueueSize = positiveInteger(options.maxQueueSize, 1e3);
5689
+ const flushIntervalMs = nonNegativeInteger(options.flushIntervalMs, 250);
5690
+ const maxBatchSize = positiveInteger(options.maxBatchSize, 100);
5691
+ const overflow = options.overflow ?? "drop-oldest";
5692
+ const pending = [];
5693
+ let closed = false;
5694
+ let timer;
5695
+ let chain = Promise.resolve();
5696
+ const clearTimer = () => {
5697
+ if (timer !== void 0) {
5698
+ clearTimeout(timer);
5699
+ timer = void 0;
5700
+ }
5701
+ };
5702
+ const scheduleFlush = () => {
5703
+ if (closed || timer !== void 0 || pending.length === 0) return;
5704
+ timer = setTimeout(() => {
5705
+ timer = void 0;
5706
+ void drain(false);
5707
+ }, flushIntervalMs);
5708
+ if (timer && typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") {
5709
+ timer.unref();
5710
+ }
5711
+ };
5712
+ const drainBatch = async (drainAll) => {
5713
+ clearTimer();
5714
+ do {
5715
+ const batch = pending.splice(0, maxBatchSize);
5716
+ if (batch.length === 0) break;
5717
+ const result = await appendEventBatch(batch, options);
5718
+ stats.writtenEvents += result.written;
5719
+ stats.droppedEvents += result.dropped;
5720
+ if (result.lastError) {
5721
+ stats.lastError = result.lastError;
5722
+ }
5723
+ } while (drainAll && pending.length > 0);
5724
+ if (pending.length > 0) scheduleFlush();
5725
+ };
5726
+ const drain = (drainAll) => {
5727
+ const operation = chain.then(() => drainBatch(drainAll));
5728
+ chain = operation.catch(() => {
5729
+ });
5730
+ return operation.catch(() => {
5731
+ });
5732
+ };
5733
+ return {
5734
+ async write(event) {
5735
+ if (closed) {
5736
+ recordDropped(stats, "Trace writer is closed");
5737
+ return;
5738
+ }
5739
+ const safe = prepareWriterEvent(event);
5740
+ if (safe === void 0) {
5741
+ recordDropped(stats, "Invalid persisted inspect event");
5742
+ return;
5743
+ }
5744
+ if (pending.length >= maxQueueSize) {
5745
+ if (overflow === "drop-newest") {
5746
+ recordDropped(stats, "Trace writer queue overflow");
5747
+ return;
5748
+ }
5749
+ pending.shift();
5750
+ recordDropped(stats, "Trace writer queue overflow");
5751
+ }
5752
+ try {
5753
+ pending.push(safe);
5754
+ } catch (error) {
5755
+ recordDropped(stats, error);
5756
+ return;
5757
+ }
5758
+ scheduleFlush();
5759
+ },
5760
+ async flush() {
5761
+ await drain(true);
5762
+ markFlush(stats);
5763
+ },
5764
+ async close() {
5765
+ if (closed) return;
5766
+ await drain(true);
5767
+ closed = true;
5768
+ clearTimer();
5769
+ },
5770
+ getStats() {
5771
+ return cloneStats(stats);
5772
+ }
5773
+ };
5774
+ }
5775
+ function compositeWriter(writersOrOptions) {
5776
+ const stats = createInitialStats();
5777
+ const writers = Array.isArray(writersOrOptions) ? [...writersOrOptions] : [...writersOrOptions.writers];
5778
+ let closed = false;
5779
+ const recordChildFailure = (error) => {
5780
+ stats.droppedEvents += 1;
5781
+ stats.lastError = normalizeError2(error);
5782
+ };
5783
+ return {
5784
+ async write(event) {
5785
+ if (closed) {
5786
+ recordDropped(stats, "Trace writer is closed");
5787
+ return;
5788
+ }
5789
+ const safe = prepareWriterEvent(event);
5790
+ if (safe === void 0) {
5791
+ recordDropped(stats, "Invalid persisted inspect event");
5792
+ return;
5793
+ }
5794
+ const childResults = await Promise.all(
5795
+ writers.map(async (writer) => {
5796
+ try {
5797
+ await writer.write(structuredClone(safe));
5798
+ return true;
5799
+ } catch (error) {
5800
+ recordChildFailure(error);
5801
+ return false;
5802
+ }
5803
+ })
5804
+ );
5805
+ if (childResults.some(Boolean)) {
5806
+ stats.writtenEvents += 1;
5807
+ } else {
5808
+ recordDropped(stats, "No composite trace writer accepted the event");
5809
+ }
5810
+ },
5811
+ async flush() {
5812
+ await Promise.all(
5813
+ writers.map(async (writer) => {
5814
+ try {
5815
+ await writer.flush?.();
5816
+ } catch (error) {
5817
+ stats.lastError = normalizeError2(error);
5818
+ }
5819
+ })
5820
+ );
5821
+ markFlush(stats);
5822
+ },
5823
+ async close() {
5824
+ if (closed) return;
5825
+ await Promise.all(
5826
+ writers.map(async (writer) => {
5827
+ try {
5828
+ await writer.close?.();
5829
+ } catch (error) {
5830
+ stats.lastError = normalizeError2(error);
5831
+ }
5832
+ })
5833
+ );
5834
+ closed = true;
5835
+ },
5836
+ getStats() {
5837
+ return cloneStats(stats);
5838
+ }
5839
+ };
5840
+ }
5841
+ var DEFAULT_MAX_TRACE_INPUT_BYTES = 10 * 1024 * 1024;
5842
+ var MIN_DETECTION_CONFIDENCE = 0.5;
5843
+ var AMBIGUOUS_CONFIDENCE_DELTA = 0.05;
5844
+ var resolvedInputCache = /* @__PURE__ */ new WeakMap();
5845
+ var OPENINFERENCE_READER_FORMAT = "openinference-json";
5846
+ var OTLP_READER_FORMAT = "otlp-json";
5847
+ var OPENINFERENCE_SPAN_KEYS = /* @__PURE__ */ new Set([
5848
+ "trace_id",
5849
+ "traceId",
5850
+ "span_id",
5851
+ "spanId",
5852
+ "parent_span_id",
5853
+ "parentSpanId",
5854
+ "name",
5855
+ "start_time_unix_nano",
5856
+ "startTimeUnixNano",
5857
+ "end_time_unix_nano",
5858
+ "endTimeUnixNano",
5859
+ "start_time",
5860
+ "startTime",
5861
+ "end_time",
5862
+ "endTime",
5863
+ "attributes",
5864
+ "status",
5865
+ "kind",
5866
+ "span_kind",
5867
+ "spanKind"
5868
+ ]);
5869
+ var OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS = [
5870
+ "input.value",
5871
+ "output.value",
5872
+ "input.mime_type",
5873
+ "output.mime_type",
5874
+ "llm.input_messages",
5875
+ "llm.output_messages",
5876
+ "llm.prompts",
5877
+ "llm.completions",
5878
+ "retrieval.documents",
5879
+ "reranker.input_documents",
5880
+ "reranker.output_documents",
5881
+ "document.content",
5882
+ "gen_ai.prompt",
5883
+ "gen_ai.completion",
5884
+ "gen_ai.input.messages",
5885
+ "gen_ai.output.messages"
5886
+ ];
5887
+ var OTLP_SPAN_KEYS = /* @__PURE__ */ new Set([
5888
+ "traceId",
5889
+ "spanId",
5890
+ "parentSpanId",
5891
+ "name",
5892
+ "kind",
5893
+ "startTimeUnixNano",
5894
+ "endTimeUnixNano",
5895
+ "attributes",
5896
+ "events",
5897
+ "status",
5898
+ "droppedAttributesCount",
5899
+ "droppedEventsCount",
5900
+ "droppedLinksCount",
5901
+ "links",
5902
+ "flags"
5903
+ ]);
5904
+ var TraceReadError = class extends Error {
5905
+ code;
5906
+ warnings;
5907
+ constructor(code, message, warnings = []) {
5908
+ super(message);
5909
+ this.name = "TraceReadError";
5910
+ this.code = code;
5911
+ this.warnings = warnings;
5912
+ }
5913
+ };
5914
+ function normalizeCandidate(reader, candidate) {
5915
+ const confidence = Number.isFinite(candidate.confidence) ? Math.max(0, Math.min(1, candidate.confidence)) : 0;
5916
+ return {
5917
+ ...candidate,
5918
+ format: candidate.format || reader.format,
5919
+ confidence,
5920
+ readerName: candidate.readerName ?? reader.name
5921
+ };
5922
+ }
5923
+ function sortCandidates(candidates) {
5924
+ return [...candidates].sort((a, b) => {
5925
+ if (b.confidence !== a.confidence) return b.confidence - a.confidence;
5926
+ return a.format.localeCompare(b.format);
5927
+ });
5928
+ }
5929
+ function collectWarnings(candidates) {
5930
+ return candidates.flatMap((candidate) => candidate.warnings ?? []);
5931
+ }
5932
+ function dedupeWarnings(warnings) {
5933
+ const seen = /* @__PURE__ */ new Set();
5934
+ const out = [];
5935
+ for (const warning of warnings) {
5936
+ const key = [
5937
+ warning.code,
5938
+ warning.message,
5939
+ warning.severity ?? "",
5940
+ warning.sourceFile ?? "",
5941
+ warning.line ?? "",
5942
+ warning.field ?? ""
5943
+ ].join("\0");
5944
+ if (seen.has(key)) continue;
5945
+ seen.add(key);
5946
+ out.push(warning);
5947
+ }
5948
+ return out;
5949
+ }
5950
+ function attachSingleSourceFile(warnings, resolved) {
5951
+ if (resolved.sourceFiles.length !== 1) return [...warnings];
5952
+ const [sourceFile] = resolved.sourceFiles;
5953
+ return warnings.map((warning) => ({
5954
+ ...warning,
5955
+ sourceFile: warning.sourceFile ?? sourceFile
5956
+ }));
5957
+ }
5958
+ function findReaderByFormat(format, readers) {
5959
+ return readers.find((reader) => reader.format === format);
5960
+ }
5961
+ async function jsonlFilesInDirectory(dirPath) {
5962
+ const entries = await promises.readdir(dirPath, { withFileTypes: true });
5963
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
5964
+ }
5965
+ async function resolveInput(input) {
5966
+ const cached = resolvedInputCache.get(input);
5967
+ if (cached) return cached;
5968
+ const promise = resolveInputUncached(input);
5969
+ resolvedInputCache.set(input, promise);
5970
+ return promise;
5971
+ }
5972
+ function assertInputWithinBounds(content, sourceFile) {
5973
+ const bytes = Buffer.byteLength(content, "utf8");
5974
+ if (bytes <= DEFAULT_MAX_TRACE_INPUT_BYTES) return;
5975
+ throw new TraceReadError("unsupported_format", "Trace input exceeds the local reader size limit.", [
5976
+ {
5977
+ code: "input_too_large",
5978
+ message: `Trace input is ${bytes} bytes; max is ${DEFAULT_MAX_TRACE_INPUT_BYTES} bytes.`,
5979
+ severity: "error",
5980
+ ...sourceFile !== void 0 ? { sourceFile } : {}
5981
+ }
5982
+ ]);
5983
+ }
5984
+ async function resolveInputUncached(input) {
5985
+ if (input.type === "string") {
5986
+ assertInputWithinBounds(input.content);
5987
+ return { content: input.content, sourceFiles: [] };
5988
+ }
5989
+ if (input.type === "buffer") {
5990
+ const content = input.content.toString("utf-8");
5991
+ assertInputWithinBounds(content);
5992
+ return { content, sourceFiles: [] };
5993
+ }
5994
+ if (input.type === "file") {
5995
+ const content = await promises.readFile(input.path, "utf-8");
5996
+ assertInputWithinBounds(content, input.path);
5997
+ return { content, sourceFiles: [input.path] };
5998
+ }
5999
+ if (input.type === "directory") {
6000
+ const files = await jsonlFilesInDirectory(input.path);
6001
+ const parts = await Promise.all(
6002
+ files.map(async (file) => (await promises.readFile(file, "utf-8")).trimEnd())
6003
+ );
6004
+ const content = parts.filter((part) => part.trim() !== "").join("\n");
6005
+ assertInputWithinBounds(content, input.path);
6006
+ return {
6007
+ content,
6008
+ sourceFiles: files
6009
+ };
6010
+ }
6011
+ return void 0;
6012
+ }
6013
+ function detectJsonlFormat(content) {
6014
+ let saw01 = false;
6015
+ let saw02 = false;
6016
+ let validRows = 0;
6017
+ let invalidJsonRows = 0;
6018
+ let unknownSchemaRows = 0;
6019
+ let firstInvalidJsonLine;
6020
+ let firstUnknownSchemaLine;
6021
+ let lineNumber = 0;
6022
+ for (const line of content.split(/\r?\n/)) {
6023
+ lineNumber += 1;
6024
+ const trimmed = line.trim();
6025
+ if (trimmed === "") continue;
6026
+ let parsed;
6027
+ try {
6028
+ parsed = JSON.parse(trimmed);
6029
+ } catch {
6030
+ invalidJsonRows += 1;
6031
+ firstInvalidJsonLine ??= lineNumber;
6032
+ continue;
6033
+ }
6034
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && "schemaVersion" in parsed) {
6035
+ const version = parsed.schemaVersion;
6036
+ if (version === "0.1") {
6037
+ saw01 = true;
6038
+ validRows += 1;
6039
+ continue;
6040
+ }
6041
+ if (version === "0.2") {
6042
+ saw02 = true;
6043
+ validRows += 1;
6044
+ continue;
6045
+ }
6046
+ }
6047
+ unknownSchemaRows += 1;
6048
+ firstUnknownSchemaLine ??= lineNumber;
6049
+ }
6050
+ const warnings = [];
6051
+ if (invalidJsonRows > 0) {
6052
+ warnings.push({
6053
+ code: "invalid_jsonl_rows",
6054
+ message: `Skipped ${invalidJsonRows} invalid JSONL row(s) during format detection.`,
6055
+ severity: "warning",
6056
+ ...firstInvalidJsonLine !== void 0 ? { line: firstInvalidJsonLine } : {}
6057
+ });
6058
+ }
6059
+ if (unknownSchemaRows > 0) {
6060
+ warnings.push({
6061
+ code: "unknown_schema_rows",
6062
+ message: `Skipped ${unknownSchemaRows} row(s) with unknown schemaVersion during format detection.`,
6063
+ severity: "warning",
6064
+ ...firstUnknownSchemaLine !== void 0 ? { line: firstUnknownSchemaLine } : {}
6065
+ });
6066
+ }
6067
+ let format = "empty";
6068
+ if (saw01 && saw02) format = "mixed";
6069
+ else if (saw01) format = "0.1";
6070
+ else if (saw02) format = "0.2";
6071
+ return { format, validRows, warnings };
6072
+ }
6073
+ function agentInspectFormatLabel(format) {
6074
+ switch (format) {
6075
+ case "0.1":
6076
+ return "agent-inspect-v0.1-jsonl";
6077
+ case "0.2":
6078
+ return "agent-inspect-v0.2-jsonl";
6079
+ case "mixed":
6080
+ return "agent-inspect-mixed-jsonl";
6081
+ default:
6082
+ return "agent-inspect-jsonl";
6083
+ }
6084
+ }
6085
+ function persistedEventsForParsedTrace(parsed) {
6086
+ if (parsed.format === "0.2" && parsed.persisted.length > 0) {
6087
+ return [...parsed.persisted];
6088
+ }
6089
+ if (parsed.format === "mixed" && parsed.rows.length > 0) {
6090
+ return parsed.rows.map((row, index) => {
6091
+ if (row.format === "0.2") return row.event;
6092
+ return traceEventToPersistedInspectEvent(row.event, {
6093
+ eventIndex: index,
6094
+ sourceName: "agent-inspect-jsonl-reader"
6095
+ });
6096
+ });
6097
+ }
6098
+ return traceEventsToPersistedInspectEvents(parsed.events, {
6099
+ sourceName: "agent-inspect-jsonl-reader"
6100
+ });
6101
+ }
6102
+ function isRecord13(value) {
6103
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6104
+ }
6105
+ function isNonEmptyString3(value) {
6106
+ return typeof value === "string" && value.trim() !== "";
6107
+ }
6108
+ function readStringField(record, keys) {
6109
+ for (const key of keys) {
6110
+ const value = record[key];
6111
+ if (isNonEmptyString3(value)) return value;
6112
+ }
6113
+ return void 0;
6114
+ }
6115
+ function readRecordField(record, key) {
6116
+ const value = record[key];
6117
+ return isRecord13(value) ? value : void 0;
6118
+ }
6119
+ function parseJsonDocument(content) {
6120
+ return JSON.parse(content);
6121
+ }
6122
+ function looksLikeOpenInferenceSpan(value) {
6123
+ if (!isRecord13(value)) return false;
6124
+ const attributes = readRecordField(value, "attributes");
6125
+ return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
6126
+ }
6127
+ function extractOpenInferenceDocument(root) {
6128
+ const warnings = [];
6129
+ const unsupportedFields = [];
6130
+ if (Array.isArray(root)) {
6131
+ const spans = root.filter(looksLikeOpenInferenceSpan);
6132
+ if (spans.length === 0) return void 0;
6133
+ if (spans.length !== root.length) {
6134
+ warnings.push({
6135
+ code: "openinference_skipped_items",
6136
+ message: "Skipped non-span item(s) in OpenInference span array.",
6137
+ severity: "warning"
6138
+ });
6139
+ }
6140
+ return {
6141
+ spans,
6142
+ confidence: 0.82,
6143
+ description: "OpenInference span array",
6144
+ warnings,
6145
+ unsupportedFields
6146
+ };
6147
+ }
6148
+ if (!isRecord13(root)) return void 0;
6149
+ const rootFormat = root.format;
6150
+ const rootCompatibility = root.compatibility;
6151
+ const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
6152
+ if (Array.isArray(root.spans)) {
6153
+ const spans = root.spans.filter(looksLikeOpenInferenceSpan);
6154
+ if (spans.length === 0 && (rootFormat === "openinference" || rootCompatibility === "openinference-compatible")) {
6155
+ warnings.push({
6156
+ code: "openinference_no_valid_spans",
6157
+ message: "OpenInference document did not contain any valid spans.",
6158
+ severity: "error"
6159
+ });
6160
+ return {
6161
+ spans,
6162
+ confidence: 0.7,
6163
+ description: "Malformed OpenInference document",
6164
+ version,
6165
+ warnings,
6166
+ unsupportedFields
6167
+ };
6168
+ }
6169
+ if (spans.length === 0) return void 0;
6170
+ if (spans.length !== root.spans.length) {
6171
+ warnings.push({
6172
+ code: "openinference_skipped_spans",
6173
+ message: "Skipped invalid OpenInference span item(s).",
6174
+ severity: "warning"
6175
+ });
6176
+ }
6177
+ return {
6178
+ spans,
6179
+ confidence: rootFormat === "openinference" || rootCompatibility === "openinference-compatible" ? 0.9 : 0.84,
6180
+ description: rootFormat === "openinference" || rootCompatibility === "openinference-compatible" ? "OpenInference document" : "OpenInference spans document",
6181
+ version,
6182
+ warnings,
6183
+ unsupportedFields
6184
+ };
6185
+ }
6186
+ if (Array.isArray(root.data)) {
6187
+ const spans = root.data.filter(looksLikeOpenInferenceSpan);
6188
+ if (spans.length === 0) return void 0;
6189
+ if (spans.length !== root.data.length) {
6190
+ warnings.push({
6191
+ code: "openinference_skipped_data_items",
6192
+ message: "Skipped non-span item(s) in OpenInference data array.",
6193
+ severity: "warning"
6194
+ });
6195
+ }
6196
+ return {
6197
+ spans,
6198
+ confidence: 0.8,
6199
+ description: "OpenInference data document",
6200
+ version,
6201
+ warnings,
6202
+ unsupportedFields
6203
+ };
6204
+ }
6205
+ if (looksLikeOpenInferenceSpan(root)) {
6206
+ return {
6207
+ spans: [root],
6208
+ confidence: 0.76,
6209
+ description: "OpenInference single span",
6210
+ version,
6211
+ warnings,
6212
+ unsupportedFields
6213
+ };
6214
+ }
6215
+ if (rootFormat === "openinference" || rootCompatibility === "openinference-compatible") {
6216
+ warnings.push({
6217
+ code: "openinference_missing_spans",
6218
+ message: "OpenInference document is missing a spans array.",
6219
+ severity: "error"
6220
+ });
6221
+ return {
6222
+ spans: [],
6223
+ confidence: 0.7,
6224
+ description: "Malformed OpenInference document",
6225
+ version,
6226
+ warnings,
6227
+ unsupportedFields
6228
+ };
6229
+ }
6230
+ return void 0;
6231
+ }
6232
+ function parseUnixNanoToIso(value) {
6233
+ if (typeof value === "bigint" && value >= 0n) {
6234
+ return new Date(Number(value / 1000000n)).toISOString();
6235
+ }
6236
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
6237
+ return new Date(Math.floor(value / 1e6)).toISOString();
6238
+ }
6239
+ if (typeof value === "string" && /^\d+$/.test(value)) {
6240
+ return new Date(Number(BigInt(value) / 1000000n)).toISOString();
6241
+ }
6242
+ return void 0;
6243
+ }
6244
+ function parseIsoTime(value) {
6245
+ if (!isNonEmptyString3(value)) return void 0;
6246
+ const ms = Date.parse(value);
6247
+ if (!Number.isFinite(ms)) return void 0;
6248
+ return new Date(ms).toISOString();
6249
+ }
6250
+ function readOpenInferenceTimestamp(span, nanoKeys, isoKeys) {
6251
+ for (const key of nanoKeys) {
6252
+ const iso = parseUnixNanoToIso(span[key]);
6253
+ if (iso !== void 0) return iso;
6254
+ }
6255
+ for (const key of isoKeys) {
6256
+ const iso = parseIsoTime(span[key]);
6257
+ if (iso !== void 0) return iso;
6258
+ }
6259
+ return void 0;
6260
+ }
6261
+ function durationBetweenIso(startedAt, endedAt) {
6262
+ if (startedAt === void 0 || endedAt === void 0) return void 0;
6263
+ const startMs = Date.parse(startedAt);
6264
+ const endMs = Date.parse(endedAt);
6265
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs < startMs) {
6266
+ return void 0;
6267
+ }
6268
+ return endMs - startMs;
6269
+ }
6270
+ function isSensitiveOpenInferenceAttribute(key) {
6271
+ return OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS.some(
6272
+ (sensitiveKey) => key === sensitiveKey || key.startsWith(`${sensitiveKey}.`) || key.endsWith(".message.content") || key.endsWith(".document.content")
6273
+ );
6274
+ }
6275
+ function summarizeAttributeValue(value) {
6276
+ if (typeof value === "string") {
6277
+ return { type: "string", length: value.length };
6278
+ }
6279
+ if (typeof value === "number") {
6280
+ return { type: "number", finite: Number.isFinite(value) };
6281
+ }
6282
+ if (typeof value === "boolean") {
6283
+ return { type: "boolean" };
6284
+ }
6285
+ if (Array.isArray(value)) {
6286
+ return { type: "array", length: value.length };
6287
+ }
6288
+ if (isRecord13(value)) {
6289
+ return { type: "object", keyCount: Object.keys(value).length };
6290
+ }
6291
+ if (value === null) {
6292
+ return { type: "null" };
6293
+ }
6294
+ return { type: typeof value };
6295
+ }
6296
+ function sanitizeOpenInferenceAttributes(attributes, pathPrefix) {
6297
+ const out = {};
6298
+ const warnings = [];
6299
+ const unsupportedFields = [];
6300
+ const summarizedKeys = [];
6301
+ for (const [key, value] of Object.entries(attributes)) {
6302
+ if (isSensitiveOpenInferenceAttribute(key)) {
6303
+ summarizedKeys.push(key);
6304
+ out[`${key}.summary`] = summarizeAttributeValue(value);
6305
+ unsupportedFields.push(`${pathPrefix}.attributes.${key}`);
6306
+ continue;
6307
+ }
6308
+ out[key] = value;
6309
+ }
6310
+ if (summarizedKeys.length > 0) {
6311
+ out["openinference.summarized_attributes"] = summarizedKeys;
6312
+ warnings.push({
6313
+ code: "openinference_sensitive_attribute_summarized",
6314
+ message: "OpenInference prompt/output/document attribute(s) were summarized instead of copied verbatim.",
6315
+ severity: "warning"
6316
+ });
6317
+ }
6318
+ return { attributes: out, warnings, unsupportedFields };
6319
+ }
6320
+ function mapOpenInferenceKind(span, attributes, pathPrefix) {
6321
+ const warnings = [];
6322
+ const agentInspectKind = attributes["agent_inspect.kind"];
6323
+ if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
6324
+ return { kind: agentInspectKind, warnings };
6325
+ }
6326
+ const rawKind = readStringField(span, ["kind", "span_kind", "spanKind"]) ?? (typeof attributes["openinference.span.kind"] === "string" ? attributes["openinference.span.kind"] : void 0);
6327
+ const normalized = rawKind?.toUpperCase();
6328
+ switch (normalized) {
6329
+ case "LLM":
6330
+ return { kind: "LLM", warnings };
6331
+ case "TOOL":
6332
+ return { kind: "TOOL", warnings };
6333
+ case "CHAIN":
6334
+ return { kind: "CHAIN", warnings };
6335
+ case "RETRIEVER":
6336
+ return { kind: "RETRIEVER", warnings };
6337
+ case "AGENT":
6338
+ return { kind: "AGENT", warnings };
6339
+ case "EMBEDDING":
6340
+ warnings.push({
6341
+ code: "openinference_kind_semantic_loss",
6342
+ message: "OpenInference EMBEDDING span kind mapped to AgentInspect LLM.",
6343
+ severity: "warning",
6344
+ field: `${pathPrefix}.attributes.openinference.span.kind`
6345
+ });
6346
+ return { kind: "LLM", warnings };
6347
+ case "RERANKER":
6348
+ warnings.push({
6349
+ code: "openinference_kind_semantic_loss",
6350
+ message: "OpenInference RERANKER span kind mapped to AgentInspect RETRIEVER.",
6351
+ severity: "warning",
6352
+ field: `${pathPrefix}.attributes.openinference.span.kind`
6353
+ });
6354
+ return { kind: "RETRIEVER", warnings };
6355
+ case "UNKNOWN":
6356
+ case void 0:
6357
+ warnings.push({
6358
+ code: "openinference_kind_unknown",
6359
+ message: "OpenInference span kind was missing or unknown; mapped to AgentInspect LOGIC.",
6360
+ severity: "warning",
6361
+ field: `${pathPrefix}.attributes.openinference.span.kind`
6362
+ });
6363
+ return { kind: "LOGIC", warnings };
6364
+ default:
6365
+ warnings.push({
6366
+ code: "openinference_kind_unsupported",
6367
+ message: `Unsupported OpenInference span kind "${rawKind}" mapped to AgentInspect LOGIC.`,
6368
+ severity: "warning",
6369
+ field: `${pathPrefix}.attributes.openinference.span.kind`
6370
+ });
6371
+ return { kind: "LOGIC", warnings };
6372
+ }
6373
+ }
6374
+ function mapOpenInferenceStatus(status) {
6375
+ if (!isRecord13(status)) return void 0;
6376
+ const rawCode = status.code;
6377
+ if (typeof rawCode !== "string") return void 0;
6378
+ switch (rawCode.toUpperCase()) {
6379
+ case "OK":
6380
+ return "ok";
6381
+ case "ERROR":
6382
+ return "error";
6383
+ case "UNSET":
6384
+ return "unknown";
6385
+ default:
6386
+ return "unknown";
6387
+ }
6388
+ }
6389
+ function readOpenInferenceTokenUsage(attributes) {
6390
+ const prompt = attributes["llm.token_count.prompt"];
6391
+ const completion = attributes["llm.token_count.completion"];
6392
+ const total = attributes["llm.token_count.total"];
6393
+ const cached = attributes["llm.token_count.prompt_details.cache_read"];
6394
+ const usage = {};
6395
+ if (typeof prompt === "number" && Number.isFinite(prompt) && prompt >= 0) {
6396
+ usage.input = prompt;
6397
+ }
6398
+ if (typeof completion === "number" && Number.isFinite(completion) && completion >= 0) {
6399
+ usage.output = completion;
6400
+ }
6401
+ if (typeof total === "number" && Number.isFinite(total) && total >= 0) {
6402
+ usage.total = total;
6403
+ }
6404
+ if (typeof cached === "number" && Number.isFinite(cached) && cached >= 0) {
6405
+ usage.cached = cached;
6406
+ }
6407
+ if (usage.total === void 0 && usage.input !== void 0 && usage.output !== void 0) {
6408
+ usage.total = usage.input + usage.output;
6409
+ }
6410
+ return Object.keys(usage).length > 0 ? usage : void 0;
6411
+ }
6412
+ function readOpenInferenceConfidence(attributes) {
6413
+ const confidence = attributes["agent_inspect.confidence"];
6414
+ if (confidence === "explicit" || confidence === "correlated" || confidence === "heuristic" || confidence === "unknown") {
6415
+ return confidence;
6416
+ }
6417
+ return "correlated";
6418
+ }
6419
+ function mapOpenInferenceSpan(span, index, version) {
6420
+ const pathPrefix = `spans[${index}]`;
6421
+ const warnings = [];
6422
+ const unsupportedFields = [];
6423
+ const rawAttributes = readRecordField(span, "attributes") ?? {};
6424
+ const sanitized = sanitizeOpenInferenceAttributes(rawAttributes, pathPrefix);
6425
+ warnings.push(...sanitized.warnings);
6426
+ unsupportedFields.push(...sanitized.unsupportedFields);
6427
+ const attributes = { ...sanitized.attributes };
6428
+ for (const [key, value] of Object.entries(span)) {
6429
+ if (OPENINFERENCE_SPAN_KEYS.has(key)) continue;
6430
+ unsupportedFields.push(`${pathPrefix}.${key}`);
6431
+ if (value === null || typeof value !== "object") {
6432
+ attributes[`openinference.${key}`] = value;
6433
+ } else {
6434
+ attributes[`openinference.${key}.summary`] = summarizeAttributeValue(value);
6435
+ warnings.push({
6436
+ code: "openinference_unsupported_field_summarized",
6437
+ message: `Unsupported OpenInference span field "${key}" was summarized.`,
6438
+ severity: "warning",
6439
+ field: `${pathPrefix}.${key}`
6440
+ });
6441
+ }
6442
+ }
6443
+ const traceId = readStringField(span, ["trace_id", "traceId"]) ?? `trace-${index}`;
6444
+ const spanId = readStringField(span, ["span_id", "spanId"]) ?? `span-${index}`;
6445
+ const parentSpanId = readStringField(span, ["parent_span_id", "parentSpanId"]);
6446
+ const name = readStringField(span, ["name"]) ?? spanId;
6447
+ const startedAt = readOpenInferenceTimestamp(
6448
+ span,
6449
+ ["start_time_unix_nano", "startTimeUnixNano"],
6450
+ ["start_time", "startTime"]
6451
+ );
6452
+ const endedAt = readOpenInferenceTimestamp(
6453
+ span,
6454
+ ["end_time_unix_nano", "endTimeUnixNano"],
6455
+ ["end_time", "endTime"]
6456
+ );
6457
+ const timestamp = startedAt ?? "1970-01-01T00:00:00.000Z";
6458
+ if (startedAt === void 0) {
6459
+ warnings.push({
6460
+ code: "openinference_missing_start_time",
6461
+ message: "OpenInference span is missing a valid start time; using Unix epoch.",
6462
+ severity: "warning",
6463
+ field: `${pathPrefix}.start_time_unix_nano`
6464
+ });
6465
+ unsupportedFields.push(`${pathPrefix}.start_time_unix_nano`);
6466
+ }
6467
+ const { kind, warnings: kindWarnings } = mapOpenInferenceKind(
6468
+ span,
6469
+ rawAttributes,
6470
+ pathPrefix
6471
+ );
6472
+ warnings.push(...kindWarnings);
6473
+ const status = mapOpenInferenceStatus(span.status);
6474
+ const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
6475
+ const errorMessage = isRecord13(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
6476
+ const event = {
6477
+ schemaVersion: "0.2",
6478
+ eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
6479
+ runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
6480
+ kind,
6481
+ name,
6482
+ timestamp,
6483
+ confidence: readOpenInferenceConfidence(rawAttributes),
6484
+ source: {
6485
+ type: "otel",
6486
+ name: "openinference",
6487
+ ...version !== void 0 ? { version } : {}
6488
+ },
6489
+ attributes,
6490
+ trace: {
6491
+ traceId,
6492
+ spanId,
6493
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
6494
+ }
6495
+ };
6496
+ if (status !== void 0) {
6497
+ event.status = status;
6498
+ }
6499
+ if (startedAt !== void 0) {
6500
+ event.startedAt = startedAt;
6501
+ }
6502
+ if (endedAt !== void 0) {
6503
+ event.endedAt = endedAt;
6504
+ }
6505
+ const durationMs2 = durationBetweenIso(startedAt, endedAt);
6506
+ if (durationMs2 !== void 0) {
6507
+ event.durationMs = durationMs2;
6508
+ }
6509
+ if (tokenUsage !== void 0) {
6510
+ event.tokenUsage = tokenUsage;
6511
+ }
6512
+ if (status === "error") {
6513
+ event.error = {
6514
+ message: errorMessage !== void 0 && errorMessage.trim() !== "" ? errorMessage : "OpenInference span error"
6515
+ };
6516
+ }
6517
+ return {
6518
+ event,
6519
+ warnings,
6520
+ unsupportedFields,
6521
+ spanId,
6522
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
6523
+ };
6524
+ }
6525
+ function mapOpenInferenceEvents(document) {
6526
+ const mapped = document.spans.map(
6527
+ (span, index) => mapOpenInferenceSpan(span, index, document.version)
6528
+ );
6529
+ const spanIdToEventId = new Map(
6530
+ mapped.map((span) => [span.spanId, span.event.eventId])
6531
+ );
6532
+ for (const span of mapped) {
6533
+ if (span.parentSpanId === void 0) continue;
6534
+ span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
6535
+ }
6536
+ return {
6537
+ events: mapped.map((span) => span.event),
6538
+ warnings: mapped.flatMap((span) => span.warnings),
6539
+ unsupportedFields: mapped.flatMap((span) => span.unsupportedFields)
6540
+ };
6541
+ }
6542
+ var openInferenceJsonReader = {
6543
+ format: OPENINFERENCE_READER_FORMAT,
6544
+ name: "OpenInference JSON",
6545
+ async detect(input) {
6546
+ const resolved = await resolveInput(input);
6547
+ if (!resolved) return void 0;
6548
+ let parsed;
6549
+ try {
6550
+ parsed = parseJsonDocument(resolved.content);
6551
+ } catch {
6552
+ return void 0;
6553
+ }
6554
+ const document = extractOpenInferenceDocument(parsed);
6555
+ if (!document) return void 0;
6556
+ return {
6557
+ format: OPENINFERENCE_READER_FORMAT,
6558
+ confidence: document.confidence,
6559
+ readerName: "OpenInference JSON",
6560
+ description: document.description,
6561
+ warnings: attachSingleSourceFile(document.warnings, resolved)
6562
+ };
6563
+ },
6564
+ async read(input) {
6565
+ const resolved = await resolveInput(input);
6566
+ if (!resolved) {
6567
+ throw new TraceReadError(
6568
+ "unsupported_format",
6569
+ "OpenInference JSON reader requires file, string, or buffer input."
6570
+ );
6571
+ }
6572
+ let parsed;
6573
+ try {
6574
+ parsed = parseJsonDocument(resolved.content);
6575
+ } catch {
6576
+ throw new TraceReadError("unsupported_format", "OpenInference JSON input is not valid JSON.", [
6577
+ {
6578
+ code: "openinference_invalid_json",
6579
+ message: "OpenInference JSON reader could not parse the input as JSON.",
6580
+ severity: "error"
6581
+ }
6582
+ ]);
6583
+ }
6584
+ const document = extractOpenInferenceDocument(parsed);
6585
+ if (!document || document.spans.length === 0) {
6586
+ throw new TraceReadError(
6587
+ "unsupported_format",
6588
+ "No valid OpenInference spans found.",
6589
+ attachSingleSourceFile(
6590
+ document?.warnings ?? [
6591
+ {
6592
+ code: "openinference_no_valid_spans",
6593
+ message: "OpenInference JSON input did not contain valid spans.",
6594
+ severity: "error"
6595
+ }
6596
+ ],
6597
+ resolved
6598
+ )
6599
+ );
6600
+ }
6601
+ const mapped = mapOpenInferenceEvents(document);
6602
+ const warnings = attachSingleSourceFile(
6603
+ [...document.warnings, ...mapped.warnings],
6604
+ resolved
6605
+ );
6606
+ const unsupportedFields = [
6607
+ ...document.unsupportedFields,
6608
+ ...mapped.unsupportedFields
6609
+ ].sort((a, b) => a.localeCompare(b));
6610
+ return {
6611
+ format: OPENINFERENCE_READER_FORMAT,
6612
+ events: mapped.events,
6613
+ runs: persistedInspectEventsToRunTrees(mapped.events, { skipInvalid: true }),
6614
+ warnings,
6615
+ unsupportedFields,
6616
+ sourceFiles: resolved.sourceFiles
6617
+ };
6618
+ }
6619
+ };
6620
+ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
6621
+ if (!isRecord13(value)) {
6622
+ unsupportedFields.push(field);
6623
+ warnings.push({
6624
+ code: "otlp_attribute_value_invalid",
6625
+ message: "OTLP attribute value was not an AnyValue object.",
6626
+ severity: "warning",
6627
+ field
6628
+ });
6629
+ return void 0;
6630
+ }
6631
+ if (typeof value.stringValue === "string") return value.stringValue;
6632
+ if (typeof value.boolValue === "boolean") return value.boolValue;
6633
+ if (typeof value.intValue === "number" && Number.isFinite(value.intValue)) {
6634
+ return value.intValue;
6635
+ }
6636
+ if (typeof value.intValue === "string" && value.intValue.trim() !== "") {
6637
+ const n = Number(value.intValue);
6638
+ if (Number.isFinite(n)) return n;
6639
+ }
6640
+ if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
6641
+ return value.doubleValue;
6642
+ }
6643
+ if (isRecord13(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
6644
+ return value.arrayValue.values.map(
6645
+ (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
6646
+ );
6647
+ }
6648
+ if (isRecord13(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
6649
+ const out = {};
6650
+ for (const [index, item] of value.kvlistValue.values.entries()) {
6651
+ if (!isRecord13(item) || typeof item.key !== "string") {
6652
+ unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
6653
+ continue;
6654
+ }
6655
+ out[item.key] = parseOtlpAnyValue(
6656
+ item.value,
6657
+ `${field}.kvlistValue.values[${index}].value`,
6658
+ warnings,
6659
+ unsupportedFields
6660
+ );
6661
+ }
6662
+ return out;
6663
+ }
6664
+ if (typeof value.bytesValue === "string") {
6665
+ unsupportedFields.push(field);
6666
+ warnings.push({
6667
+ code: "otlp_bytes_value_summarized",
6668
+ message: "OTLP bytesValue attribute was summarized instead of decoded.",
6669
+ severity: "warning",
6670
+ field
6671
+ });
6672
+ return { type: "bytes", length: value.bytesValue.length };
6673
+ }
6674
+ unsupportedFields.push(field);
6675
+ warnings.push({
6676
+ code: "otlp_attribute_value_unsupported",
6677
+ message: "OTLP attribute value used an unsupported AnyValue shape.",
6678
+ severity: "warning",
6679
+ field
6680
+ });
6681
+ return void 0;
6682
+ }
6683
+ function parseOtlpAttributes(value, pathPrefix) {
6684
+ const attributes = {};
6685
+ const warnings = [];
6686
+ const unsupportedFields = [];
6687
+ if (value === void 0) {
6688
+ return { attributes, warnings, unsupportedFields };
6689
+ }
6690
+ if (!Array.isArray(value)) {
6691
+ unsupportedFields.push(pathPrefix);
6692
+ warnings.push({
6693
+ code: "otlp_attributes_invalid",
6694
+ message: "OTLP attributes field was not an array.",
6695
+ severity: "warning",
6696
+ field: pathPrefix
6697
+ });
6698
+ return { attributes, warnings, unsupportedFields };
6699
+ }
6700
+ for (const [index, item] of value.entries()) {
6701
+ const field = `${pathPrefix}[${index}]`;
6702
+ if (!isRecord13(item) || typeof item.key !== "string") {
6703
+ unsupportedFields.push(field);
6704
+ warnings.push({
6705
+ code: "otlp_attribute_invalid",
6706
+ message: "Skipped OTLP attribute without a string key.",
6707
+ severity: "warning",
6708
+ field
6709
+ });
6710
+ continue;
6711
+ }
6712
+ const parsed = parseOtlpAnyValue(
6713
+ item.value,
6714
+ `${field}.value`,
6715
+ warnings,
6716
+ unsupportedFields
6717
+ );
6718
+ if (parsed !== void 0) {
6719
+ attributes[item.key] = parsed;
6720
+ }
6721
+ }
6722
+ return { attributes, warnings, unsupportedFields };
6723
+ }
6724
+ function looksLikeOtlpSpan(value) {
6725
+ return isRecord13(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
6726
+ }
6727
+ function extractOtlpDocument(root) {
6728
+ if (!isRecord13(root) || !Array.isArray(root.resourceSpans)) return void 0;
6729
+ const spans = [];
6730
+ const warnings = [];
6731
+ const unsupportedFields = [];
6732
+ for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
6733
+ const resourcePath = `resourceSpans[${resourceIndex}]`;
6734
+ if (!isRecord13(resourceSpan)) {
6735
+ unsupportedFields.push(resourcePath);
6736
+ continue;
6737
+ }
6738
+ const resource = readRecordField(resourceSpan, "resource");
6739
+ const resourceParsed = parseOtlpAttributes(
6740
+ resource?.attributes,
6741
+ `${resourcePath}.resource.attributes`
6742
+ );
6743
+ warnings.push(...resourceParsed.warnings);
6744
+ unsupportedFields.push(...resourceParsed.unsupportedFields);
6745
+ if (!Array.isArray(resourceSpan.scopeSpans)) {
6746
+ unsupportedFields.push(`${resourcePath}.scopeSpans`);
6747
+ warnings.push({
6748
+ code: "otlp_scope_spans_missing",
6749
+ message: "OTLP resourceSpans entry did not contain a scopeSpans array.",
6750
+ severity: "warning",
6751
+ field: `${resourcePath}.scopeSpans`
6752
+ });
6753
+ continue;
6754
+ }
6755
+ for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
6756
+ const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
6757
+ if (!isRecord13(scopeSpan)) {
6758
+ unsupportedFields.push(scopePath);
6759
+ continue;
6760
+ }
6761
+ const scope = readRecordField(scopeSpan, "scope");
6762
+ const scopeParsed = parseOtlpAttributes(
6763
+ scope?.attributes,
6764
+ `${scopePath}.scope.attributes`
6765
+ );
6766
+ warnings.push(...scopeParsed.warnings);
6767
+ unsupportedFields.push(...scopeParsed.unsupportedFields);
6768
+ if (!Array.isArray(scopeSpan.spans)) {
6769
+ unsupportedFields.push(`${scopePath}.spans`);
6770
+ warnings.push({
6771
+ code: "otlp_spans_missing",
6772
+ message: "OTLP scopeSpans entry did not contain a spans array.",
6773
+ severity: "warning",
6774
+ field: `${scopePath}.spans`
6775
+ });
6776
+ continue;
6777
+ }
6778
+ for (const [spanIndex, span] of scopeSpan.spans.entries()) {
6779
+ const spanPath = `${scopePath}.spans[${spanIndex}]`;
6780
+ if (!looksLikeOtlpSpan(span)) {
6781
+ unsupportedFields.push(spanPath);
6782
+ warnings.push({
6783
+ code: "otlp_invalid_span",
6784
+ message: "Skipped OTLP span without required traceId, spanId, or name.",
6785
+ severity: "warning",
6786
+ field: spanPath
6787
+ });
6788
+ continue;
6789
+ }
6790
+ spans.push({
6791
+ span,
6792
+ resourceAttributes: resourceParsed.attributes,
6793
+ scopeAttributes: scopeParsed.attributes,
6794
+ scopeName: readStringField(scope ?? {}, ["name"]),
6795
+ scopeVersion: readStringField(scope ?? {}, ["version"]),
6796
+ pathPrefix: spanPath
6797
+ });
6798
+ }
6799
+ }
6800
+ }
6801
+ if (spans.length === 0) {
6802
+ warnings.push({
6803
+ code: "otlp_no_valid_spans",
6804
+ message: "OTLP JSON payload did not contain any valid spans.",
6805
+ severity: "error"
6806
+ });
6807
+ return {
6808
+ spans,
6809
+ confidence: 0.7,
6810
+ description: "Malformed OTLP JSON trace payload",
6811
+ warnings,
6812
+ unsupportedFields
6813
+ };
6814
+ }
6815
+ return {
6816
+ spans,
6817
+ confidence: 0.93,
6818
+ description: "OTLP JSON trace payload",
6819
+ warnings,
6820
+ unsupportedFields
6821
+ };
6822
+ }
6823
+ function mapOtlpStatus(status) {
6824
+ if (!isRecord13(status)) return void 0;
6825
+ const rawCode = status.code;
6826
+ if (typeof rawCode !== "string") return void 0;
6827
+ switch (rawCode.toUpperCase()) {
6828
+ case "STATUS_CODE_OK":
6829
+ case "OK":
6830
+ return "ok";
6831
+ case "STATUS_CODE_ERROR":
6832
+ case "ERROR":
6833
+ return "error";
6834
+ case "STATUS_CODE_UNSET":
6835
+ case "UNSET":
6836
+ return "unknown";
6837
+ default:
6838
+ return "unknown";
6839
+ }
6840
+ }
6841
+ function readOtlpKind(attributes, pathPrefix) {
6842
+ const warnings = [];
6843
+ const agentInspectKind = attributes["agent_inspect.kind"];
6844
+ if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
6845
+ return { kind: agentInspectKind, warnings };
6846
+ }
6847
+ const operation = attributes["gen_ai.operation.name"];
6848
+ if (typeof operation === "string") {
6849
+ switch (operation) {
6850
+ case "generate_content":
6851
+ case "chat":
6852
+ return { kind: "LLM", warnings };
6853
+ case "execute_tool":
6854
+ return { kind: "TOOL", warnings };
6855
+ case "invoke_agent":
6856
+ return { kind: "AGENT", warnings };
6857
+ default:
6858
+ warnings.push({
6859
+ code: "otlp_gen_ai_operation_semantic_loss",
6860
+ message: `OTLP GenAI operation "${operation}" mapped to AgentInspect LOGIC.`,
6861
+ severity: "warning",
6862
+ field: `${pathPrefix}.attributes.gen_ai.operation.name`
6863
+ });
6864
+ return { kind: "LOGIC", warnings };
6865
+ }
6866
+ }
6867
+ warnings.push({
6868
+ code: "otlp_kind_unknown",
6869
+ message: "OTLP span had no AgentInspect kind or GenAI operation; mapped to LOGIC.",
6870
+ severity: "warning",
6871
+ field: `${pathPrefix}.attributes`
6872
+ });
6873
+ return { kind: "LOGIC", warnings };
6874
+ }
6875
+ function readOtlpTokenUsage(attributes) {
6876
+ const input = attributes["gen_ai.usage.input_tokens"];
6877
+ const output = attributes["gen_ai.usage.output_tokens"];
6878
+ const usage = {};
6879
+ if (typeof input === "number" && Number.isFinite(input) && input >= 0) {
6880
+ usage.input = input;
6881
+ }
6882
+ if (typeof output === "number" && Number.isFinite(output) && output >= 0) {
6883
+ usage.output = output;
6884
+ }
6885
+ if (usage.input !== void 0 && usage.output !== void 0) {
6886
+ usage.total = usage.input + usage.output;
6887
+ }
6888
+ return Object.keys(usage).length > 0 ? usage : void 0;
6889
+ }
6890
+ function readOtlpConfidence(attributes) {
6891
+ return readOpenInferenceConfidence(attributes);
6892
+ }
6893
+ function sanitizeOtlpAttributes(attributes, pathPrefix) {
6894
+ const ownerPath = pathPrefix.endsWith(".attributes") ? pathPrefix.slice(0, -".attributes".length) : pathPrefix;
6895
+ const sanitized = sanitizeOpenInferenceAttributes(attributes, ownerPath);
6896
+ return {
6897
+ ...sanitized,
6898
+ warnings: sanitized.warnings.map(
6899
+ (warning) => warning.code === "openinference_sensitive_attribute_summarized" ? {
6900
+ ...warning,
6901
+ code: "otlp_sensitive_attribute_summarized",
6902
+ message: "OTLP prompt/output/document attribute(s) were summarized instead of copied verbatim."
6903
+ } : warning
6904
+ )
6905
+ };
6906
+ }
6907
+ function mapOtlpEvents(value, pathPrefix) {
6908
+ const warnings = [];
6909
+ const unsupportedFields = [];
6910
+ if (value === void 0) return { warnings, unsupportedFields };
6911
+ if (!Array.isArray(value)) {
6912
+ unsupportedFields.push(pathPrefix);
6913
+ warnings.push({
6914
+ code: "otlp_events_invalid",
6915
+ message: "OTLP events field was not an array.",
6916
+ severity: "warning",
6917
+ field: pathPrefix
6918
+ });
6919
+ return { warnings, unsupportedFields };
6920
+ }
6921
+ const events = [];
6922
+ for (const [index, event] of value.entries()) {
6923
+ const eventPath = `${pathPrefix}[${index}]`;
6924
+ if (!isRecord13(event)) {
6925
+ unsupportedFields.push(eventPath);
6926
+ continue;
6927
+ }
6928
+ const parsedAttributes = parseOtlpAttributes(
6929
+ event.attributes,
6930
+ `${eventPath}.attributes`
6931
+ );
6932
+ warnings.push(...parsedAttributes.warnings);
6933
+ unsupportedFields.push(...parsedAttributes.unsupportedFields);
6934
+ const sanitized = sanitizeOtlpAttributes(
6935
+ parsedAttributes.attributes,
6936
+ `${eventPath}.attributes`
6937
+ );
6938
+ warnings.push(...sanitized.warnings);
6939
+ unsupportedFields.push(...sanitized.unsupportedFields);
6940
+ const out = {};
6941
+ const name = readStringField(event, ["name"]);
6942
+ if (name !== void 0) {
6943
+ out.name = name;
6944
+ }
6945
+ const timestamp = parseUnixNanoToIso(event.timeUnixNano);
6946
+ if (timestamp !== void 0) {
6947
+ out.timestamp = timestamp;
6948
+ } else if (event.timeUnixNano !== void 0) {
6949
+ unsupportedFields.push(`${eventPath}.timeUnixNano`);
6950
+ warnings.push({
6951
+ code: "otlp_event_timestamp_invalid",
6952
+ message: "OTLP event timeUnixNano could not be parsed.",
6953
+ severity: "warning",
6954
+ field: `${eventPath}.timeUnixNano`
6955
+ });
6956
+ }
6957
+ if (Object.keys(sanitized.attributes).length > 0) {
6958
+ out.attributes = sanitized.attributes;
6959
+ }
6960
+ events.push(out);
6961
+ }
6962
+ return {
6963
+ events: events.length > 0 ? events : void 0,
6964
+ warnings,
6965
+ unsupportedFields
6966
+ };
6967
+ }
6968
+ function mapOtlpSpan(context) {
6969
+ const { span, pathPrefix } = context;
6970
+ const warnings = [];
6971
+ const unsupportedFields = [];
6972
+ const parsedSpanAttributes = parseOtlpAttributes(
6973
+ span.attributes,
6974
+ `${pathPrefix}.attributes`
6975
+ );
6976
+ warnings.push(...parsedSpanAttributes.warnings);
6977
+ unsupportedFields.push(...parsedSpanAttributes.unsupportedFields);
6978
+ const sanitizedSpanAttributes = sanitizeOtlpAttributes(
6979
+ parsedSpanAttributes.attributes,
6980
+ `${pathPrefix}.attributes`
6981
+ );
6982
+ warnings.push(...sanitizedSpanAttributes.warnings);
6983
+ unsupportedFields.push(...sanitizedSpanAttributes.unsupportedFields);
6984
+ const attributes = {
6985
+ ...sanitizedSpanAttributes.attributes
6986
+ };
6987
+ for (const [key, value] of Object.entries(context.resourceAttributes)) {
6988
+ attributes[`resource.${key}`] = value;
6989
+ }
6990
+ for (const [key, value] of Object.entries(context.scopeAttributes)) {
6991
+ attributes[`scope.${key}`] = value;
6992
+ }
6993
+ if (context.scopeName !== void 0) {
6994
+ attributes["scope.name"] = context.scopeName;
6995
+ }
6996
+ if (context.scopeVersion !== void 0) {
6997
+ attributes["scope.version"] = context.scopeVersion;
6998
+ }
6999
+ for (const [key, value] of Object.entries(span)) {
7000
+ if (OTLP_SPAN_KEYS.has(key)) continue;
7001
+ unsupportedFields.push(`${pathPrefix}.${key}`);
7002
+ if (value === null || typeof value !== "object") {
7003
+ attributes[`otlp.${key}`] = value;
7004
+ } else {
7005
+ attributes[`otlp.${key}.summary`] = summarizeAttributeValue(value);
7006
+ warnings.push({
7007
+ code: "otlp_unsupported_field_summarized",
7008
+ message: `Unsupported OTLP span field "${key}" was summarized.`,
7009
+ severity: "warning",
7010
+ field: `${pathPrefix}.${key}`
7011
+ });
7012
+ }
7013
+ }
7014
+ for (const key of [
7015
+ "droppedAttributesCount",
7016
+ "droppedEventsCount",
7017
+ "droppedLinksCount",
7018
+ "links"
7019
+ ]) {
7020
+ if (span[key] !== void 0) {
7021
+ unsupportedFields.push(`${pathPrefix}.${key}`);
7022
+ warnings.push({
7023
+ code: "otlp_span_field_not_mapped",
7024
+ message: `OTLP span field "${key}" is not represented in AgentInspect events.`,
7025
+ severity: "warning",
7026
+ field: `${pathPrefix}.${key}`
7027
+ });
7028
+ }
7029
+ }
7030
+ const events = mapOtlpEvents(span.events, `${pathPrefix}.events`);
7031
+ warnings.push(...events.warnings);
7032
+ unsupportedFields.push(...events.unsupportedFields);
7033
+ if (events.events !== void 0) {
7034
+ attributes["otlp.events"] = events.events;
7035
+ }
7036
+ const traceId = readStringField(span, ["traceId"]) ?? "trace-unknown";
7037
+ const spanId = readStringField(span, ["spanId"]) ?? "span-unknown";
7038
+ const parentSpanId = readStringField(span, ["parentSpanId"]);
7039
+ const startedAt = readOpenInferenceTimestamp(
7040
+ span,
7041
+ ["startTimeUnixNano"],
7042
+ []
7043
+ );
7044
+ const endedAt = readOpenInferenceTimestamp(span, ["endTimeUnixNano"], []);
7045
+ const timestamp = startedAt ?? "1970-01-01T00:00:00.000Z";
7046
+ if (startedAt === void 0) {
7047
+ unsupportedFields.push(`${pathPrefix}.startTimeUnixNano`);
7048
+ warnings.push({
7049
+ code: "otlp_missing_start_time",
7050
+ message: "OTLP span is missing a valid startTimeUnixNano; using Unix epoch.",
7051
+ severity: "warning",
7052
+ field: `${pathPrefix}.startTimeUnixNano`
7053
+ });
7054
+ }
7055
+ const { kind, warnings: kindWarnings } = readOtlpKind(
7056
+ parsedSpanAttributes.attributes,
7057
+ pathPrefix
7058
+ );
7059
+ warnings.push(...kindWarnings);
7060
+ const status = mapOtlpStatus(span.status);
7061
+ const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
7062
+ const errorMessage = isRecord13(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
7063
+ const event = {
7064
+ schemaVersion: "0.2",
7065
+ eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
7066
+ runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
7067
+ kind,
7068
+ name: readStringField(span, ["name"]) ?? spanId,
7069
+ timestamp,
7070
+ confidence: readOtlpConfidence(parsedSpanAttributes.attributes),
7071
+ source: {
7072
+ type: "otel",
7073
+ name: context.scopeName ?? (typeof context.resourceAttributes["service.name"] === "string" ? context.resourceAttributes["service.name"] : "otlp-json"),
7074
+ ...context.scopeVersion !== void 0 ? { version: context.scopeVersion } : {}
7075
+ },
7076
+ attributes,
7077
+ trace: {
7078
+ traceId,
7079
+ spanId,
7080
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
7081
+ }
7082
+ };
7083
+ if (status !== void 0) {
7084
+ event.status = status;
7085
+ }
7086
+ if (startedAt !== void 0) {
7087
+ event.startedAt = startedAt;
7088
+ }
7089
+ if (endedAt !== void 0) {
7090
+ event.endedAt = endedAt;
7091
+ }
7092
+ const durationMs2 = durationBetweenIso(startedAt, endedAt);
7093
+ if (durationMs2 !== void 0) {
7094
+ event.durationMs = durationMs2;
7095
+ }
7096
+ if (tokenUsage !== void 0) {
7097
+ event.tokenUsage = tokenUsage;
7098
+ }
7099
+ if (status === "error") {
7100
+ event.error = {
7101
+ message: errorMessage !== void 0 && errorMessage.trim() !== "" ? errorMessage : "OTLP span error"
7102
+ };
7103
+ }
7104
+ return {
7105
+ event,
7106
+ warnings,
7107
+ unsupportedFields,
7108
+ spanId,
7109
+ ...parentSpanId !== void 0 ? { parentSpanId } : {}
7110
+ };
7111
+ }
7112
+ function mapOtlpEventsToPersisted(document) {
7113
+ const mapped = document.spans.map((span) => mapOtlpSpan(span));
7114
+ const spanIdToEventId = new Map(
7115
+ mapped.map((span) => [span.spanId, span.event.eventId])
7116
+ );
7117
+ for (const span of mapped) {
7118
+ if (span.parentSpanId === void 0) continue;
7119
+ span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
7120
+ }
7121
+ return {
7122
+ events: mapped.map((span) => span.event),
7123
+ warnings: mapped.flatMap((span) => span.warnings),
7124
+ unsupportedFields: mapped.flatMap((span) => span.unsupportedFields)
7125
+ };
7126
+ }
7127
+ var otlpJsonReader = {
7128
+ format: OTLP_READER_FORMAT,
7129
+ name: "OTLP JSON",
7130
+ async detect(input) {
7131
+ const resolved = await resolveInput(input);
7132
+ if (!resolved) return void 0;
7133
+ let parsed;
7134
+ try {
7135
+ parsed = parseJsonDocument(resolved.content);
7136
+ } catch {
7137
+ return void 0;
7138
+ }
7139
+ const document = extractOtlpDocument(parsed);
7140
+ if (!document) return void 0;
7141
+ return {
7142
+ format: OTLP_READER_FORMAT,
7143
+ confidence: document.confidence,
7144
+ readerName: "OTLP JSON",
7145
+ description: document.description,
7146
+ warnings: attachSingleSourceFile(document.warnings, resolved)
7147
+ };
7148
+ },
7149
+ async read(input) {
7150
+ const resolved = await resolveInput(input);
7151
+ if (!resolved) {
7152
+ throw new TraceReadError(
7153
+ "unsupported_format",
7154
+ "OTLP JSON reader requires file, string, or buffer input."
7155
+ );
7156
+ }
7157
+ let parsed;
7158
+ try {
7159
+ parsed = parseJsonDocument(resolved.content);
7160
+ } catch {
7161
+ throw new TraceReadError("unsupported_format", "OTLP JSON input is not valid JSON.", [
7162
+ {
7163
+ code: "otlp_invalid_json",
7164
+ message: "OTLP JSON reader could not parse the input as JSON.",
7165
+ severity: "error"
7166
+ }
7167
+ ]);
7168
+ }
7169
+ const document = extractOtlpDocument(parsed);
7170
+ if (!document || document.spans.length === 0) {
7171
+ throw new TraceReadError(
7172
+ "unsupported_format",
7173
+ "No valid OTLP spans found.",
7174
+ attachSingleSourceFile(
7175
+ document?.warnings ?? [
7176
+ {
7177
+ code: "otlp_no_valid_spans",
7178
+ message: "OTLP JSON input did not contain valid spans.",
7179
+ severity: "error"
7180
+ }
7181
+ ],
7182
+ resolved
7183
+ )
7184
+ );
7185
+ }
7186
+ const mapped = mapOtlpEventsToPersisted(document);
7187
+ const warnings = attachSingleSourceFile(
7188
+ [...document.warnings, ...mapped.warnings],
7189
+ resolved
7190
+ );
7191
+ const unsupportedFields = [
7192
+ ...document.unsupportedFields,
7193
+ ...mapped.unsupportedFields
7194
+ ].sort((a, b) => a.localeCompare(b));
7195
+ return {
7196
+ format: OTLP_READER_FORMAT,
7197
+ events: mapped.events,
7198
+ runs: persistedInspectEventsToRunTrees(mapped.events, { skipInvalid: true }),
7199
+ warnings,
7200
+ unsupportedFields,
7201
+ sourceFiles: resolved.sourceFiles
7202
+ };
7203
+ }
7204
+ };
7205
+ var agentInspectJsonlReader = {
7206
+ format: "agent-inspect-jsonl",
7207
+ name: "AgentInspect JSONL",
7208
+ async detect(input) {
7209
+ const resolved = await resolveInput(input);
7210
+ if (!resolved) return void 0;
7211
+ const detected = detectJsonlFormat(resolved.content);
7212
+ if (detected.validRows === 0 || detected.format === "empty") {
7213
+ return void 0;
7214
+ }
7215
+ return {
7216
+ format: "agent-inspect-jsonl",
7217
+ confidence: 0.95,
7218
+ readerName: "AgentInspect JSONL",
7219
+ description: agentInspectFormatLabel(detected.format),
7220
+ warnings: attachSingleSourceFile(detected.warnings, resolved)
7221
+ };
7222
+ },
7223
+ async read(input) {
7224
+ const resolved = await resolveInput(input);
7225
+ if (!resolved) {
7226
+ throw new Error("AgentInspect JSONL reader requires file, directory, string, or buffer input.");
7227
+ }
7228
+ const parsed = parseTraceJsonl(resolved.content, { warnings: false });
7229
+ if (parsed.sourceEventCount === 0) {
7230
+ throw new Error("No valid AgentInspect JSONL events found.");
7231
+ }
7232
+ const events = persistedEventsForParsedTrace(parsed);
7233
+ return {
7234
+ format: agentInspectFormatLabel(parsed.format),
7235
+ events,
7236
+ runs: persistedInspectEventsToRunTrees(events, { skipInvalid: true }),
7237
+ warnings: parsed.format === "mixed" ? attachSingleSourceFile(
7238
+ [
7239
+ {
7240
+ code: "mixed_agent_inspect_jsonl",
7241
+ message: "Trace input mixes schemaVersion 0.1 and 0.2 rows; events were normalized for reading.",
7242
+ severity: "warning"
7243
+ }
7244
+ ],
7245
+ resolved
7246
+ ) : [],
7247
+ unsupportedFields: [],
7248
+ sourceFiles: resolved.sourceFiles
7249
+ };
7250
+ }
7251
+ };
7252
+ var DEFAULT_TRACE_READERS = [
7253
+ agentInspectJsonlReader,
7254
+ openInferenceJsonReader,
7255
+ otlpJsonReader
7256
+ ];
7257
+ async function detectTraceFormat(input, options = {}) {
7258
+ const readers = options.readers ?? DEFAULT_TRACE_READERS;
7259
+ if (options.format !== void 0) {
7260
+ const reader = findReaderByFormat(options.format, readers);
7261
+ if (!reader) {
7262
+ return {
7263
+ status: "unsupported",
7264
+ candidates: [],
7265
+ warnings: [
7266
+ {
7267
+ code: "unsupported_format",
7268
+ message: `No trace reader is registered for format "${options.format}".`,
7269
+ severity: "error"
7270
+ }
7271
+ ]
7272
+ };
7273
+ }
7274
+ return {
7275
+ status: "detected",
7276
+ format: reader.format,
7277
+ candidates: [
7278
+ {
7279
+ format: reader.format,
7280
+ confidence: 1,
7281
+ readerName: reader.name,
7282
+ description: "Explicit format override"
7283
+ }
7284
+ ],
7285
+ warnings: []
7286
+ };
7287
+ }
7288
+ const candidates = [];
7289
+ const warnings = [];
7290
+ for (const reader of readers) {
7291
+ try {
7292
+ const candidate = await reader.detect(input);
7293
+ if (candidate !== void 0) {
7294
+ candidates.push(normalizeCandidate(reader, candidate));
7295
+ }
7296
+ } catch (error) {
7297
+ if (error instanceof TraceReadError) {
7298
+ warnings.push(...error.warnings);
7299
+ continue;
7300
+ }
7301
+ warnings.push({
7302
+ code: "reader_detect_failed",
7303
+ message: error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed during detection.`,
7304
+ severity: "warning"
7305
+ });
7306
+ }
7307
+ }
7308
+ const sorted = sortCandidates(
7309
+ candidates.filter((candidate) => candidate.confidence >= MIN_DETECTION_CONFIDENCE)
7310
+ );
7311
+ const candidateWarnings = collectWarnings(sorted);
7312
+ const lowConfidenceWarnings = candidates.length > sorted.length ? [
7313
+ {
7314
+ code: "low_confidence_candidates",
7315
+ message: `Ignored ${candidates.length - sorted.length} low-confidence format candidate(s).`,
7316
+ severity: "info"
7317
+ }
7318
+ ] : [];
7319
+ const allWarnings = dedupeWarnings([
7320
+ ...warnings,
7321
+ ...candidateWarnings,
7322
+ ...lowConfidenceWarnings
7323
+ ]);
7324
+ if (sorted.length === 0) {
7325
+ return {
7326
+ status: "unsupported",
7327
+ candidates: [],
7328
+ warnings: allWarnings
7329
+ };
7330
+ }
7331
+ const [best, second] = sorted;
7332
+ if (second !== void 0 && best.confidence - second.confidence <= AMBIGUOUS_CONFIDENCE_DELTA) {
7333
+ return {
7334
+ status: "ambiguous",
7335
+ candidates: sorted,
7336
+ warnings: [
7337
+ ...allWarnings,
7338
+ {
7339
+ code: "ambiguous_format_candidates",
7340
+ message: `Top trace format candidates are within ${AMBIGUOUS_CONFIDENCE_DELTA} confidence.`,
7341
+ severity: "warning"
7342
+ }
7343
+ ]
7344
+ };
7345
+ }
7346
+ return {
7347
+ status: "detected",
7348
+ format: best.format,
7349
+ candidates: sorted,
7350
+ warnings: allWarnings
7351
+ };
7352
+ }
7353
+ async function readTrace(input, options = {}) {
7354
+ const readers = options.readers ?? DEFAULT_TRACE_READERS;
7355
+ const detection = await detectTraceFormat(input, options);
7356
+ if (detection.status === "unsupported" || detection.format === void 0) {
7357
+ throw new TraceReadError(
7358
+ "unsupported_format",
7359
+ "No trace reader could detect the input format.",
7360
+ detection.warnings
7361
+ );
7362
+ }
7363
+ if (detection.status === "ambiguous") {
7364
+ throw new TraceReadError(
7365
+ "ambiguous_format",
7366
+ "Multiple trace readers matched the input with equal confidence.",
7367
+ detection.warnings
7368
+ );
7369
+ }
7370
+ const reader = findReaderByFormat(detection.format, readers);
7371
+ if (!reader) {
7372
+ throw new TraceReadError(
7373
+ "unsupported_format",
7374
+ `No trace reader is registered for format "${detection.format}".`,
7375
+ detection.warnings
7376
+ );
7377
+ }
7378
+ try {
7379
+ const result = await reader.read(input, { format: detection.format });
7380
+ return {
7381
+ ...result,
7382
+ format: result.format || detection.format,
7383
+ warnings: [...detection.warnings, ...result.warnings]
7384
+ };
7385
+ } catch (error) {
7386
+ if (error instanceof TraceReadError) {
7387
+ throw new TraceReadError(
7388
+ error.code,
7389
+ error.message,
7390
+ dedupeWarnings([...detection.warnings, ...error.warnings])
7391
+ );
7392
+ }
7393
+ throw new TraceReadError(
7394
+ "reader_failed",
7395
+ error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed.`,
7396
+ detection.warnings
7397
+ );
7398
+ }
7399
+ }
7400
+ function openTrace(input, options = {}) {
7401
+ return readTrace(input, options);
7402
+ }
7403
+
7404
+ // packages/core/src/diff/comparable.ts
7405
+ function extractOutputPreview(meta) {
7406
+ if (meta === void 0) return void 0;
7407
+ if ("outputPreview" in meta) return meta.outputPreview;
7408
+ if ("resultPreview" in meta) return meta.resultPreview;
7409
+ return void 0;
7410
+ }
7411
+ function mapStepStatus2(s) {
7412
+ if (s === void 0) return "running";
7413
+ return s;
7414
+ }
7415
+ function manualTraceEventsToComparableRun(events) {
7416
+ const started = events.find((e) => e.event === "run_started");
7417
+ if (!started || started.event !== "run_started") {
7418
+ throw new Error("Invalid trace: missing run_started");
7419
+ }
7420
+ const rs = started;
7421
+ const runId = rs.runId;
7422
+ const completedAll = events.filter((e) => e.event === "run_completed");
7423
+ const lastCompleted = completedAll[completedAll.length - 1];
7424
+ let runStatus;
7425
+ if (lastCompleted === void 0) runStatus = "running";
7426
+ else runStatus = lastCompleted.status;
7427
+ const durationMs2 = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
7428
+ const steps = /* @__PURE__ */ new Map();
7429
+ let order = 0;
7430
+ for (const e of events) {
7431
+ if (e.event !== "step_started") continue;
7432
+ const s = e;
7433
+ const meta = s.metadata ? { ...s.metadata } : void 0;
7434
+ steps.set(s.stepId, {
7435
+ id: s.stepId,
7436
+ parentId: s.parentId,
7437
+ name: s.name,
7438
+ type: s.type,
7439
+ order: order++,
7440
+ timestamp: s.timestamp,
7441
+ metadata: meta
7442
+ });
7443
+ }
7444
+ for (const e of events) {
7445
+ if (e.event !== "step_completed") continue;
7446
+ const acc = steps.get(e.stepId);
7447
+ if (!acc) continue;
7448
+ acc.status = e.status;
7449
+ acc.durationMs = e.durationMs;
7450
+ if (e.error?.message) acc.errorMsg = e.error.message;
7451
+ const extra = e;
7452
+ if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
7453
+ acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
7454
+ }
7455
+ }
7456
+ const nodes = /* @__PURE__ */ new Map();
7457
+ for (const acc of steps.values()) {
7458
+ let meta = acc.metadata ? { ...acc.metadata } : void 0;
7459
+ if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
7460
+ meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
4728
7461
  }
4729
7462
  const outputPreview = extractOutputPreview(meta);
4730
7463
  const sc = {
@@ -4762,7 +7495,7 @@ function manualTraceEventsToComparableRun(events) {
4762
7495
  runId,
4763
7496
  name: rs.name,
4764
7497
  status: runStatus,
4765
- durationMs,
7498
+ durationMs: durationMs2,
4766
7499
  steps: roots
4767
7500
  };
4768
7501
  }
@@ -4807,13 +7540,13 @@ function pairSteps(left, right) {
4807
7540
  return pairs;
4808
7541
  }
4809
7542
  function compareLeafSteps(L, R, segments, opts, out) {
4810
- const path5 = buildPath(segments);
7543
+ const path7 = buildPath(segments);
4811
7544
  if (L.name !== R.name) {
4812
7545
  out.push({
4813
7546
  kind: "structure",
4814
7547
  severity: "warning",
4815
7548
  message: "Step name differs",
4816
- path: path5,
7549
+ path: path7,
4817
7550
  left: L.name,
4818
7551
  right: R.name
4819
7552
  });
@@ -4823,7 +7556,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
4823
7556
  kind: "step-type",
4824
7557
  severity: "warning",
4825
7558
  message: "Step type differs",
4826
- path: path5,
7559
+ path: path7,
4827
7560
  left: L.type,
4828
7561
  right: R.type
4829
7562
  });
@@ -4833,7 +7566,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
4833
7566
  kind: "step-status",
4834
7567
  severity: "warning",
4835
7568
  message: "Step status differs",
4836
- path: path5,
7569
+ path: path7,
4837
7570
  left: L.status,
4838
7571
  right: R.status
4839
7572
  });
@@ -4845,7 +7578,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
4845
7578
  kind: "error",
4846
7579
  severity: "error",
4847
7580
  message: "Step error message differs",
4848
- path: path5,
7581
+ path: path7,
4849
7582
  left: le || void 0,
4850
7583
  right: re || void 0
4851
7584
  });
@@ -4863,7 +7596,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
4863
7596
  kind: "duration",
4864
7597
  severity: "info",
4865
7598
  message: "Step duration differs",
4866
- path: path5,
7599
+ path: path7,
4867
7600
  left: ld,
4868
7601
  right: rd
4869
7602
  });
@@ -4876,7 +7609,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
4876
7609
  kind: "metadata",
4877
7610
  severity: "info",
4878
7611
  message: "Step metadata differs",
4879
- path: path5,
7612
+ path: path7,
4880
7613
  left: L.metadata,
4881
7614
  right: R.metadata
4882
7615
  });
@@ -4888,7 +7621,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
4888
7621
  kind: "output",
4889
7622
  severity: "info",
4890
7623
  message: "Output preview differs",
4891
- path: path5,
7624
+ path: path7,
4892
7625
  left: L.outputPreview,
4893
7626
  right: R.outputPreview
4894
7627
  });
@@ -5538,11 +8271,11 @@ createChalk({ level: stderrColor ? stderrColor.level : 0 });
5538
8271
  var source_default = chalk;
5539
8272
 
5540
8273
  // packages/core/src/diff/renderer.ts
5541
- function formatPath(path5) {
5542
- if (path5 === void 0 || path5.path.length === 0) {
8274
+ function formatPath(path7) {
8275
+ if (path7 === void 0 || path7.path.length === 0) {
5543
8276
  return "(run)";
5544
8277
  }
5545
- return path5.path.map((s) => s.name).join(" > ");
8278
+ return path7.path.map((s) => s.name).join(" > ");
5546
8279
  }
5547
8280
  function formatValue(v, verbose) {
5548
8281
  if (v === void 0) return "(undefined)";
@@ -5657,15 +8390,15 @@ function getStatusIcon(status) {
5657
8390
  if (status === "error") return source_default.red("\u2716");
5658
8391
  return source_default.yellow("\u23F3");
5659
8392
  }
5660
- function renderStepLine(name, durationMs, status, depth) {
8393
+ function renderStepLine(name, durationMs2, status, depth) {
5661
8394
  try {
5662
8395
  const nm = formatTerminalName(name);
5663
8396
  const ind = getIndent(depth ?? 0);
5664
- if (status === "running" && durationMs === void 0) {
8397
+ if (status === "running" && durationMs2 === void 0) {
5665
8398
  return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
5666
8399
  }
5667
- const hasDur = durationMs !== void 0 && Number.isFinite(durationMs);
5668
- const dur = hasDur ? formatDuration2(durationMs) : void 0;
8400
+ const hasDur = durationMs2 !== void 0 && Number.isFinite(durationMs2);
8401
+ const dur = hasDur ? formatDuration2(durationMs2) : void 0;
5669
8402
  if (status === "running") {
5670
8403
  return dur !== void 0 ? `${ind}${source_default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${source_default.yellow("\u23F3")} ${nm}`;
5671
8404
  }
@@ -5689,9 +8422,9 @@ function renderErrorLine(error, depth) {
5689
8422
  return "";
5690
8423
  }
5691
8424
  }
5692
- function renderRunSummary(durationMs, status, traceFilePath) {
8425
+ function renderRunSummary(durationMs2, status, traceFilePath) {
5693
8426
  try {
5694
- const dur = Number.isFinite(durationMs) ? formatDuration2(durationMs) : formatDuration2(0);
8427
+ const dur = Number.isFinite(durationMs2) ? formatDuration2(durationMs2) : formatDuration2(0);
5695
8428
  const head = status === "error" ? `Failed in ${dur}` : `Completed in ${dur}`;
5696
8429
  const lines = [head];
5697
8430
  if (traceFilePath !== void 0 && traceFilePath.trim() !== "") {
@@ -5718,10 +8451,10 @@ function printStepStart(name, depth = 0) {
5718
8451
  } catch {
5719
8452
  }
5720
8453
  }
5721
- function printStepComplete(name, durationMs, status, depth = 0) {
8454
+ function printStepComplete(name, durationMs2, status, depth = 0) {
5722
8455
  if (isSilentContext()) return;
5723
8456
  try {
5724
- safePrint(renderStepLine(name, durationMs, status, depth));
8457
+ safePrint(renderStepLine(name, durationMs2, status, depth));
5725
8458
  } catch {
5726
8459
  }
5727
8460
  }
@@ -5732,10 +8465,10 @@ function printError(error, depth = 0) {
5732
8465
  } catch {
5733
8466
  }
5734
8467
  }
5735
- function printRunComplete(_name, _runId, durationMs, status, traceFilePath) {
8468
+ function printRunComplete(_name, _runId, durationMs2, status, traceFilePath) {
5736
8469
  if (isSilentContext()) return;
5737
8470
  try {
5738
- const lines = renderRunSummary(durationMs, status, traceFilePath);
8471
+ const lines = renderRunSummary(durationMs2, status, traceFilePath);
5739
8472
  for (let i = 0; i < lines.length; i++) {
5740
8473
  const line = lines[i];
5741
8474
  if (i === 0) {
@@ -5818,7 +8551,7 @@ async function inspectRun(name, fn, options) {
5818
8551
  result = await Promise.resolve(fn());
5819
8552
  } catch (userError) {
5820
8553
  const endTime2 = Date.now();
5821
- const durationMs2 = endTime2 - startTime;
8554
+ const durationMs3 = endTime2 - startTime;
5822
8555
  const formatted = formatError(userError);
5823
8556
  const printPath2 = traceFilePath ?? getTraceFilePath(runId, traceDir);
5824
8557
  await safeInstrumentation("writeTraceEvent(run_completed error)", async () => {
@@ -5829,7 +8562,7 @@ async function inspectRun(name, fn, options) {
5829
8562
  runId,
5830
8563
  status: "error",
5831
8564
  endTime: endTime2,
5832
- durationMs: durationMs2,
8565
+ durationMs: durationMs3,
5833
8566
  error: formatted
5834
8567
  };
5835
8568
  await writeTraceEvent(
@@ -5838,12 +8571,12 @@ async function inspectRun(name, fn, options) {
5838
8571
  );
5839
8572
  });
5840
8573
  await safeInstrumentation("printRunComplete(error)", () => {
5841
- printRunComplete(runName, runId, durationMs2, "error", printPath2);
8574
+ printRunComplete(runName, runId, durationMs3, "error", printPath2);
5842
8575
  });
5843
8576
  throw userError;
5844
8577
  }
5845
8578
  const endTime = Date.now();
5846
- const durationMs = endTime - startTime;
8579
+ const durationMs2 = endTime - startTime;
5847
8580
  const printPath = traceFilePath ?? getTraceFilePath(runId, traceDir);
5848
8581
  await safeInstrumentation("writeTraceEvent(run_completed success)", async () => {
5849
8582
  const completed = {
@@ -5853,7 +8586,7 @@ async function inspectRun(name, fn, options) {
5853
8586
  runId,
5854
8587
  status: "success",
5855
8588
  endTime,
5856
- durationMs
8589
+ durationMs: durationMs2
5857
8590
  };
5858
8591
  await writeTraceEvent(
5859
8592
  prepareTraceEventForDisk(completed, traceSafety),
@@ -5861,7 +8594,7 @@ async function inspectRun(name, fn, options) {
5861
8594
  );
5862
8595
  });
5863
8596
  await safeInstrumentation("printRunComplete(success)", () => {
5864
- printRunComplete(runName, runId, durationMs, "success", printPath);
8597
+ printRunComplete(runName, runId, durationMs2, "success", printPath);
5865
8598
  });
5866
8599
  return result;
5867
8600
  }, traceSafety);
@@ -5943,7 +8676,7 @@ async function stepImpl(name, fn, options) {
5943
8676
  });
5944
8677
  } catch (userError) {
5945
8678
  const endTime2 = Date.now();
5946
- const durationMs2 = endTime2 - startTime;
8679
+ const durationMs3 = endTime2 - startTime;
5947
8680
  const formatted = formatError(userError);
5948
8681
  await safeInstrumentation2("writeTraceEvent(step_completed error)", async () => {
5949
8682
  const completed = {
@@ -5954,14 +8687,14 @@ async function stepImpl(name, fn, options) {
5954
8687
  stepId,
5955
8688
  status: "error",
5956
8689
  endTime: endTime2,
5957
- durationMs: durationMs2,
8690
+ durationMs: durationMs3,
5958
8691
  error: formatted
5959
8692
  };
5960
8693
  const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
5961
8694
  await writeTraceEvent(safe, context.traceDir);
5962
8695
  });
5963
8696
  await safeInstrumentation2("printStepComplete(error)", () => {
5964
- printStepComplete(stepName, durationMs2, "error", renderDepth);
8697
+ printStepComplete(stepName, durationMs3, "error", renderDepth);
5965
8698
  });
5966
8699
  await safeInstrumentation2("printError", () => {
5967
8700
  printError(formatted, renderDepth);
@@ -5972,7 +8705,7 @@ async function stepImpl(name, fn, options) {
5972
8705
  throw userError;
5973
8706
  }
5974
8707
  const endTime = Date.now();
5975
- const durationMs = endTime - startTime;
8708
+ const durationMs2 = endTime - startTime;
5976
8709
  await safeInstrumentation2("writeTraceEvent(step_completed success)", async () => {
5977
8710
  const completed = {
5978
8711
  schemaVersion: "0.1",
@@ -5982,13 +8715,13 @@ async function stepImpl(name, fn, options) {
5982
8715
  stepId,
5983
8716
  status: "success",
5984
8717
  endTime,
5985
- durationMs
8718
+ durationMs: durationMs2
5986
8719
  };
5987
8720
  const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
5988
8721
  await writeTraceEvent(safe, context.traceDir);
5989
8722
  });
5990
8723
  await safeInstrumentation2("printStepComplete(success)", () => {
5991
- printStepComplete(stepName, durationMs, "success", renderDepth);
8724
+ printStepComplete(stepName, durationMs2, "success", renderDepth);
5992
8725
  });
5993
8726
  return result;
5994
8727
  }
@@ -6463,6 +9196,7 @@ exports.DEFAULT_MAX_METADATA_VALUE_LENGTH = DEFAULT_MAX_METADATA_VALUE_LENGTH;
6463
9196
  exports.DEFAULT_MAX_PREVIEW_LENGTH = DEFAULT_MAX_PREVIEW_LENGTH;
6464
9197
  exports.DEFAULT_REDACT_KEYS = DEFAULT_REDACT_KEYS;
6465
9198
  exports.DEFAULT_TRACE_DIR_NAME = DEFAULT_TRACE_DIR_NAME;
9199
+ exports.DEFAULT_TRACE_READERS = DEFAULT_TRACE_READERS;
6466
9200
  exports.EXPORT_PAYLOAD_VERSION = EXPORT_PAYLOAD_VERSION;
6467
9201
  exports.EventNormalizer = EventNormalizer;
6468
9202
  exports.FALLBACK_TRACE_DIR = FALLBACK_TRACE_DIR;
@@ -6476,15 +9210,22 @@ exports.RUNS_DIR_NAME = RUNS_DIR_NAME;
6476
9210
  exports.Redactor = Redactor;
6477
9211
  exports.TERMINAL_INDENT = TERMINAL_INDENT;
6478
9212
  exports.TraceDirectory = TraceDirectory;
9213
+ exports.TraceReadError = TraceReadError;
6479
9214
  exports.TreeBuilder = TreeBuilder;
9215
+ exports.agentInspectJsonlReader = agentInspectJsonlReader;
9216
+ exports.bufferedFileWriter = bufferedFileWriter;
6480
9217
  exports.buildRunReport = buildRunReport;
6481
9218
  exports.buildRunSummary = buildRunSummary;
6482
9219
  exports.buildRunTimeline = buildRunTimeline;
6483
9220
  exports.buildRunWhatSummary = buildRunWhatSummary;
6484
9221
  exports.buildTraceStats = buildTraceStats;
6485
9222
  exports.compactAttributes = compactAttributes4;
9223
+ exports.compositeWriter = compositeWriter;
9224
+ exports.createInspector = createInspector;
9225
+ exports.createInspectorRuntime = createInspectorRuntime;
6486
9226
  exports.createRunId = createRunId;
6487
9227
  exports.createStepId = createStepId;
9228
+ exports.detectTraceFormat = detectTraceFormat;
6488
9229
  exports.diffRuns = diffRuns;
6489
9230
  exports.diffTraceEvents = diffTraceEvents;
6490
9231
  exports.ensureTraceDir = ensureTraceDir;
@@ -6496,6 +9237,7 @@ exports.exportOpenInference = exportOpenInference;
6496
9237
  exports.exportOtlpJson = exportOtlpJson;
6497
9238
  exports.exportRunTree = exportRunTree;
6498
9239
  exports.extractMetadata = extractMetadata;
9240
+ exports.fileWriter = fileWriter;
6499
9241
  exports.filterTraces = filterTraces;
6500
9242
  exports.flattenTree = flattenTree;
6501
9243
  exports.formatDuration = formatDuration2;
@@ -6534,9 +9276,12 @@ exports.manualTraceEventsToComparableRun = manualTraceEventsToComparableRun;
6534
9276
  exports.manualTraceEventsToRunTree = manualTraceEventsToRunTree;
6535
9277
  exports.matchMapping = matchMapping;
6536
9278
  exports.maybeInspectRun = maybeInspectRun;
9279
+ exports.memoryWriter = memoryWriter;
6537
9280
  exports.mergeExportDefaults = mergeExportDefaults;
6538
9281
  exports.mergeLogIngestConfig = mergeLogIngestConfig;
9282
+ exports.nullWriter = nullWriter;
6539
9283
  exports.observe = observe;
9284
+ exports.openTrace = openTrace;
6540
9285
  exports.parseDuration = parseDuration;
6541
9286
  exports.parseDurationFilter = parseDurationFilter;
6542
9287
  exports.parseLogLine = parseLogLine;
@@ -6555,6 +9300,7 @@ exports.printRunComplete = printRunComplete;
6555
9300
  exports.printRunStart = printRunStart;
6556
9301
  exports.printStepComplete = printStepComplete;
6557
9302
  exports.printStepStart = printStepStart;
9303
+ exports.readTrace = readTrace;
6558
9304
  exports.readTraceEvents = readTraceEvents;
6559
9305
  exports.readTraceFile = readTraceFile;
6560
9306
  exports.redactRunTreeForExport = redactRunTreeForExport;