agent-inspect 1.8.0 → 2.0.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 (100) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +146 -23
  3. package/docs/ADAPTER-CONFORMANCE.md +1 -1
  4. package/docs/ADAPTERS.md +41 -6
  5. package/docs/API.md +123 -36
  6. package/docs/CLI.md +75 -11
  7. package/docs/EXPORTS.md +1 -1
  8. package/docs/GETTING-STARTED.md +72 -16
  9. package/docs/KNOWN-ISSUES.md +8 -3
  10. package/docs/LIMITATIONS.md +6 -6
  11. package/docs/LOG-TO-TREE-QUICKSTART.md +1 -2
  12. package/docs/MIGRATION.md +67 -0
  13. package/docs/SCHEMA.md +29 -12
  14. package/package.json +2 -2
  15. package/packages/cli/dist/index.cjs +7604 -7660
  16. package/packages/cli/dist/index.cjs.map +1 -1
  17. package/packages/cli/dist/index.mjs +7604 -7660
  18. package/packages/cli/dist/index.mjs.map +1 -1
  19. package/packages/core/dist/advanced.cjs +2047 -26
  20. package/packages/core/dist/advanced.cjs.map +1 -1
  21. package/packages/core/dist/advanced.d.cts +346 -196
  22. package/packages/core/dist/advanced.d.ts +346 -196
  23. package/packages/core/dist/advanced.mjs +628 -5
  24. package/packages/core/dist/advanced.mjs.map +1 -1
  25. package/packages/core/dist/checks.d.cts +1 -1
  26. package/packages/core/dist/checks.d.ts +1 -1
  27. package/packages/core/dist/chunk-2ZXEMWGK.mjs +549 -0
  28. package/packages/core/dist/chunk-2ZXEMWGK.mjs.map +1 -0
  29. package/packages/core/dist/{chunk-57S5D6HR.mjs → chunk-4JVGFNQH.mjs} +50 -6
  30. package/packages/core/dist/chunk-4JVGFNQH.mjs.map +1 -0
  31. package/packages/core/dist/{chunk-6QSLZCBJ.mjs → chunk-A4V2H3YU.mjs} +329 -163
  32. package/packages/core/dist/chunk-A4V2H3YU.mjs.map +1 -0
  33. package/packages/core/dist/{chunk-74XZ6N7Q.mjs → chunk-IZBJAZGF.mjs} +12 -4
  34. package/packages/core/dist/chunk-IZBJAZGF.mjs.map +1 -0
  35. package/packages/core/dist/{chunk-VTIB5MDK.mjs → chunk-NQZPZ2FN.mjs} +15 -10
  36. package/packages/core/dist/chunk-NQZPZ2FN.mjs.map +1 -0
  37. package/packages/core/dist/{chunk-TZISEVLQ.mjs → chunk-XUNJMAPD.mjs} +3 -3
  38. package/packages/core/dist/{chunk-TZISEVLQ.mjs.map → chunk-XUNJMAPD.mjs.map} +1 -1
  39. package/packages/core/dist/context-CSKnzpXR.d.cts +177 -0
  40. package/packages/core/dist/context-yv2VSDQF.d.ts +177 -0
  41. package/packages/core/dist/diff.d.cts +2 -2
  42. package/packages/core/dist/diff.d.ts +2 -2
  43. package/packages/core/dist/diff.mjs +473 -3
  44. package/packages/core/dist/diff.mjs.map +1 -1
  45. package/packages/core/dist/exporters.cjs +691 -0
  46. package/packages/core/dist/exporters.cjs.map +1 -1
  47. package/packages/core/dist/exporters.d.cts +24 -3
  48. package/packages/core/dist/exporters.d.ts +24 -3
  49. package/packages/core/dist/exporters.mjs +1113 -3
  50. package/packages/core/dist/exporters.mjs.map +1 -1
  51. package/packages/core/dist/index.cjs +1385 -8022
  52. package/packages/core/dist/index.cjs.map +1 -1
  53. package/packages/core/dist/index.d.cts +8 -313
  54. package/packages/core/dist/index.d.ts +8 -313
  55. package/packages/core/dist/index.mjs +18 -1331
  56. package/packages/core/dist/index.mjs.map +1 -1
  57. package/packages/core/dist/{log-config-DanPV3P9.d.cts → log-config-8aE5Kxtr.d.cts} +1 -1
  58. package/packages/core/dist/{log-config-BPHS4Sds.d.ts → log-config-DVimQJho.d.ts} +1 -1
  59. package/packages/core/dist/logs.d.cts +2 -2
  60. package/packages/core/dist/logs.d.ts +2 -2
  61. package/packages/core/dist/logs.mjs +785 -2
  62. package/packages/core/dist/logs.mjs.map +1 -1
  63. package/packages/core/dist/{persisted-inspect-event-Cw7TeYGr.d.ts → persisted-inspect-event-D-WpXeZX.d.ts} +14 -5
  64. package/packages/core/dist/{persisted-inspect-event-DHPfzUd8.d.cts → persisted-inspect-event-DHcHPUKv.d.cts} +14 -5
  65. package/packages/core/dist/persisted.cjs +11 -1
  66. package/packages/core/dist/persisted.cjs.map +1 -1
  67. package/packages/core/dist/persisted.d.cts +4 -4
  68. package/packages/core/dist/persisted.d.ts +4 -4
  69. package/packages/core/dist/persisted.mjs +150 -3
  70. package/packages/core/dist/persisted.mjs.map +1 -1
  71. package/packages/core/dist/readers.cjs +27 -10
  72. package/packages/core/dist/readers.cjs.map +1 -1
  73. package/packages/core/dist/readers.d.cts +1 -1
  74. package/packages/core/dist/readers.d.ts +1 -1
  75. package/packages/core/dist/readers.mjs +1580 -4
  76. package/packages/core/dist/readers.mjs.map +1 -1
  77. package/packages/core/dist/{types-Ap9uMdx_.d.ts → types-D-Y1kOU-.d.ts} +2 -2
  78. package/packages/core/dist/{types-B2-BU5CS.d.cts → types-DgMN3qow.d.cts} +2 -2
  79. package/packages/core/dist/writers.cjs +49 -3
  80. package/packages/core/dist/writers.cjs.map +1 -1
  81. package/packages/core/dist/writers.d.cts +1 -1
  82. package/packages/core/dist/writers.d.ts +1 -1
  83. package/packages/core/dist/writers.mjs +341 -4
  84. package/packages/core/dist/writers.mjs.map +1 -1
  85. package/packages/core/dist/chunk-57S5D6HR.mjs.map +0 -1
  86. package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +0 -1
  87. package/packages/core/dist/chunk-6SZPTECC.mjs +0 -342
  88. package/packages/core/dist/chunk-6SZPTECC.mjs.map +0 -1
  89. package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +0 -1
  90. package/packages/core/dist/chunk-HR7G62IE.mjs +0 -785
  91. package/packages/core/dist/chunk-HR7G62IE.mjs.map +0 -1
  92. package/packages/core/dist/chunk-TFLPUZ56.mjs +0 -1571
  93. package/packages/core/dist/chunk-TFLPUZ56.mjs.map +0 -1
  94. package/packages/core/dist/chunk-U2BGPESY.mjs +0 -150
  95. package/packages/core/dist/chunk-U2BGPESY.mjs.map +0 -1
  96. package/packages/core/dist/chunk-VTIB5MDK.mjs.map +0 -1
  97. package/packages/core/dist/chunk-Y56BPA3B.mjs +0 -990
  98. package/packages/core/dist/chunk-Y56BPA3B.mjs.map +0 -1
  99. package/packages/core/dist/chunk-YWAOOXLR.mjs +0 -475
  100. package/packages/core/dist/chunk-YWAOOXLR.mjs.map +0 -1
@@ -7,6 +7,8 @@ var path = require('path');
7
7
  var os = require('os');
8
8
  var process2 = require('process');
9
9
  var tty = require('tty');
10
+ var fs = require('fs');
11
+ var readline = require('readline');
10
12
 
11
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
14
 
@@ -43,6 +45,25 @@ function extractCorrelationMetadata(record) {
43
45
  }
44
46
  return found ? out : void 0;
45
47
  }
48
+ function buildRunStartedMetadata(options) {
49
+ if (!options) {
50
+ return void 0;
51
+ }
52
+ const merged = options.metadata !== void 0 ? { ...options.metadata } : {};
53
+ if (isNonEmptyString(options.correlationId)) {
54
+ merged.correlationId = options.correlationId;
55
+ }
56
+ if (isNonEmptyString(options.requestId)) {
57
+ merged.requestId = options.requestId;
58
+ }
59
+ if (isNonEmptyString(options.decisionId)) {
60
+ merged.decisionId = options.decisionId;
61
+ }
62
+ if (isNonEmptyString(options.groupId)) {
63
+ merged.groupId = options.groupId;
64
+ }
65
+ return Object.keys(merged).length > 0 ? merged : void 0;
66
+ }
46
67
  var DEFAULT_REDACT_KEYS = [
47
68
  "authorization",
48
69
  "cookie",
@@ -212,6 +233,53 @@ function applyProfileMetadataCaps(maxMetadataValueLength, maxPreviewLength, reso
212
233
  return { maxMetadataValueLength: meta, maxPreviewLength: preview };
213
234
  }
214
235
 
236
+ // packages/core/src/types.ts
237
+ var STEP_TYPES = [
238
+ "run",
239
+ "llm",
240
+ "tool",
241
+ "decision",
242
+ "logic",
243
+ "state",
244
+ "custom"
245
+ ];
246
+ var STEP_STATUSES = [
247
+ "running",
248
+ "success",
249
+ "error"
250
+ ];
251
+ function isRecord2(value) {
252
+ return typeof value === "object" && value !== null && !Array.isArray(value);
253
+ }
254
+ function isStepType(value) {
255
+ return typeof value === "string" && STEP_TYPES.includes(value);
256
+ }
257
+ function isStepStatus(value) {
258
+ return typeof value === "string" && STEP_STATUSES.includes(value);
259
+ }
260
+ function isTraceEvent(value) {
261
+ if (!isRecord2(value)) return false;
262
+ if (value.schemaVersion !== "0.1") return false;
263
+ if (typeof value.timestamp !== "number") return false;
264
+ if (typeof value.event !== "string") return false;
265
+ switch (value.event) {
266
+ case "run_started": {
267
+ return typeof value.runId === "string" && typeof value.name === "string" && typeof value.startTime === "number";
268
+ }
269
+ case "run_completed": {
270
+ return typeof value.runId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
271
+ }
272
+ case "step_started": {
273
+ return typeof value.runId === "string" && typeof value.stepId === "string" && typeof value.name === "string" && isStepType(value.type) && typeof value.startTime === "number";
274
+ }
275
+ case "step_completed": {
276
+ return typeof value.runId === "string" && typeof value.stepId === "string" && (value.status === "success" || value.status === "error") && typeof value.endTime === "number" && typeof value.durationMs === "number";
277
+ }
278
+ default:
279
+ return false;
280
+ }
281
+ }
282
+
215
283
  // packages/core/src/types/persisted-inspect-event.ts
216
284
  var INSPECT_KINDS = [
217
285
  "RUN",
@@ -246,7 +314,7 @@ var PERSISTED_EVENT_STATUSES = [
246
314
  "error",
247
315
  "unknown"
248
316
  ];
249
- function isRecord2(value) {
317
+ function isRecord3(value) {
250
318
  return typeof value === "object" && value !== null && !Array.isArray(value);
251
319
  }
252
320
  function isString(value) {
@@ -277,21 +345,21 @@ function isPersistedEventStatus(value) {
277
345
  return typeof value === "string" && PERSISTED_EVENT_STATUSES.includes(value);
278
346
  }
279
347
  function isPersistedEventSource(value) {
280
- if (!isRecord2(value)) return false;
348
+ if (!isRecord3(value)) return false;
281
349
  if (!isPersistedEventSourceType(value.type)) return false;
282
350
  if (!isOptionalString(value.name)) return false;
283
351
  if (!isOptionalString(value.version)) return false;
284
352
  return true;
285
353
  }
286
354
  function isPersistedInspectError(value) {
287
- if (!isRecord2(value)) return false;
355
+ if (!isRecord3(value)) return false;
288
356
  if (!isNonEmptyString2(value.message)) return false;
289
357
  if (!isOptionalString(value.name)) return false;
290
358
  if (!isOptionalString(value.code)) return false;
291
359
  return true;
292
360
  }
293
361
  function isPersistedTokenUsage(value) {
294
- if (!isRecord2(value)) return false;
362
+ if (!isRecord3(value)) return false;
295
363
  if (!isOptionalNonNegativeNumber(value.input)) return false;
296
364
  if (!isOptionalNonNegativeNumber(value.output)) return false;
297
365
  if (!isOptionalNonNegativeNumber(value.total)) return false;
@@ -299,15 +367,17 @@ function isPersistedTokenUsage(value) {
299
367
  return true;
300
368
  }
301
369
  function isPersistedTraceContext(value) {
302
- if (!isRecord2(value)) return false;
370
+ if (!isRecord3(value)) return false;
303
371
  if (!isOptionalString(value.traceId)) return false;
304
372
  if (!isOptionalString(value.spanId)) return false;
305
373
  if (!isOptionalString(value.parentSpanId)) return false;
306
374
  return true;
307
375
  }
308
376
  function isPersistedInspectEvent(value) {
309
- if (!isRecord2(value)) return false;
310
- if (value.schemaVersion !== "0.2") return false;
377
+ if (!isRecord3(value)) return false;
378
+ if (value.schemaVersion !== "0.2" && value.schemaVersion !== "1.0") {
379
+ return false;
380
+ }
311
381
  if (!isNonEmptyString2(value.eventId)) return false;
312
382
  if (!isNonEmptyString2(value.runId)) return false;
313
383
  if (!isInspectKind(value.kind)) return false;
@@ -326,7 +396,7 @@ function isPersistedInspectEvent(value) {
326
396
  if (value.durationMs !== void 0 && !isNonNegativeNumber(value.durationMs)) {
327
397
  return false;
328
398
  }
329
- if (value.attributes !== void 0 && !isRecord2(value.attributes)) {
399
+ if (value.attributes !== void 0 && !isRecord3(value.attributes)) {
330
400
  return false;
331
401
  }
332
402
  if (value.error !== void 0 && !isPersistedInspectError(value.error)) {
@@ -341,6 +411,272 @@ function isPersistedInspectEvent(value) {
341
411
  return true;
342
412
  }
343
413
 
414
+ // packages/core/src/persisted/to-trace-event.ts
415
+ function parseIsoToMs(iso) {
416
+ const parsed = Date.parse(iso);
417
+ return Number.isFinite(parsed) ? parsed : 0;
418
+ }
419
+ function mapInspectKindToStepType(kind) {
420
+ switch (kind) {
421
+ case "LLM":
422
+ return "llm";
423
+ case "TOOL":
424
+ return "tool";
425
+ case "DECISION":
426
+ return "decision";
427
+ case "RUN":
428
+ return "run";
429
+ default:
430
+ return "logic";
431
+ }
432
+ }
433
+ function mapPersistedStatusToStepStatus(status) {
434
+ switch (status) {
435
+ case "ok":
436
+ return "success";
437
+ case "error":
438
+ return "error";
439
+ case "running":
440
+ return "running";
441
+ default:
442
+ return void 0;
443
+ }
444
+ }
445
+ function mapPersistedStatusToRunStatus(status) {
446
+ switch (status) {
447
+ case "ok":
448
+ return "success";
449
+ case "error":
450
+ return "error";
451
+ case "running":
452
+ return "running";
453
+ default:
454
+ return void 0;
455
+ }
456
+ }
457
+ function mapPersistedError(error, attributes) {
458
+ if (!error?.message) return void 0;
459
+ const out = { message: error.message };
460
+ const stack = typeof attributes?.errorStack === "string" && attributes.errorStack.length > 0 ? attributes.errorStack : void 0;
461
+ if (stack) {
462
+ out.stack = stack;
463
+ }
464
+ return out;
465
+ }
466
+ function mapTokenUsageToMetadata(tokenUsage, attributes) {
467
+ const metadata = {};
468
+ if (attributes?.metadata && typeof attributes.metadata === "object") {
469
+ Object.assign(metadata, attributes.metadata);
470
+ }
471
+ if (tokenUsage) {
472
+ metadata.tokens = {
473
+ ...tokenUsage.input !== void 0 ? { input: tokenUsage.input } : {},
474
+ ...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {},
475
+ ...tokenUsage.total !== void 0 ? { total: tokenUsage.total } : {},
476
+ ...tokenUsage.cached !== void 0 ? { cached: tokenUsage.cached } : {}
477
+ };
478
+ }
479
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
480
+ }
481
+ function pickRunMetadata(attributes) {
482
+ if (!attributes) return void 0;
483
+ const metadata = attributes.metadata && typeof attributes.metadata === "object" ? { ...attributes.metadata } : {};
484
+ for (const key of [
485
+ "correlationId",
486
+ "requestId",
487
+ "decisionId",
488
+ "groupId"
489
+ ]) {
490
+ const value = attributes[key];
491
+ if (typeof value === "string" && value.trim() !== "") {
492
+ metadata[key] = value;
493
+ }
494
+ }
495
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
496
+ }
497
+ function resolveStepId(event) {
498
+ const attrs = event.attributes;
499
+ if (attrs && typeof attrs.stepId === "string" && attrs.stepId.trim() !== "") {
500
+ return attrs.stepId;
501
+ }
502
+ return event.eventId;
503
+ }
504
+ function resolveStepType(event) {
505
+ const attrs = event.attributes;
506
+ if (attrs && typeof attrs.stepType === "string") {
507
+ const t = attrs.stepType;
508
+ if (t === "run" || t === "llm" || t === "tool" || t === "decision" || t === "logic" || t === "state" || t === "custom") {
509
+ return t;
510
+ }
511
+ }
512
+ return mapInspectKindToStepType(event.kind);
513
+ }
514
+ function resolveTimes(event) {
515
+ const timestamp = parseIsoToMs(event.timestamp);
516
+ const startTime = event.startedAt !== void 0 ? parseIsoToMs(event.startedAt) : timestamp;
517
+ let endTime = event.endedAt !== void 0 ? parseIsoToMs(event.endedAt) : timestamp;
518
+ if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0 && event.endedAt === void 0) {
519
+ endTime = startTime + event.durationMs;
520
+ }
521
+ return { timestamp, startTime, endTime };
522
+ }
523
+ function fromLegacyRunStarted(event) {
524
+ const { timestamp, startTime } = resolveTimes(event);
525
+ const out = {
526
+ schemaVersion: "0.1",
527
+ event: "run_started",
528
+ timestamp,
529
+ runId: event.runId,
530
+ name: event.name,
531
+ startTime
532
+ };
533
+ const metadata = pickRunMetadata(event.attributes);
534
+ if (metadata) out.metadata = metadata;
535
+ return out;
536
+ }
537
+ function fromLegacyRunCompleted(event) {
538
+ const { timestamp, endTime } = resolveTimes(event);
539
+ const status = mapPersistedStatusToRunStatus(event.status) ?? "success";
540
+ const out = {
541
+ schemaVersion: "0.1",
542
+ event: "run_completed",
543
+ timestamp,
544
+ runId: event.runId,
545
+ status: status === "running" ? "success" : status,
546
+ endTime,
547
+ durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
548
+ };
549
+ const error = mapPersistedError(event.error, event.attributes);
550
+ if (error) out.error = error;
551
+ return out;
552
+ }
553
+ function fromLegacyStepStarted(event) {
554
+ const { timestamp, startTime } = resolveTimes(event);
555
+ const out = {
556
+ schemaVersion: "0.1",
557
+ event: "step_started",
558
+ timestamp,
559
+ runId: event.runId,
560
+ stepId: resolveStepId(event),
561
+ name: event.name,
562
+ type: resolveStepType(event),
563
+ startTime
564
+ };
565
+ if (event.parentId !== void 0) out.parentId = event.parentId;
566
+ const metadata = mapTokenUsageToMetadata(event.tokenUsage, event.attributes);
567
+ if (metadata) out.metadata = metadata;
568
+ return out;
569
+ }
570
+ function fromLegacyStepCompleted(event) {
571
+ const { timestamp, endTime } = resolveTimes(event);
572
+ const status = mapPersistedStatusToStepStatus(event.status) ?? "success";
573
+ const out = {
574
+ schemaVersion: "0.1",
575
+ event: "step_completed",
576
+ timestamp,
577
+ runId: event.runId,
578
+ stepId: resolveStepId(event),
579
+ status: status === "running" ? "success" : status,
580
+ endTime,
581
+ durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
582
+ };
583
+ const error = mapPersistedError(event.error, event.attributes);
584
+ if (error) out.error = error;
585
+ return out;
586
+ }
587
+ function fromNativeRun(event) {
588
+ const { timestamp, startTime, endTime } = resolveTimes(event);
589
+ const runStatus = mapPersistedStatusToRunStatus(event.status);
590
+ const out = [];
591
+ if (runStatus === "running" || event.startedAt !== void 0) {
592
+ const started = {
593
+ schemaVersion: "0.1",
594
+ event: "run_started",
595
+ timestamp,
596
+ runId: event.runId,
597
+ name: event.name,
598
+ startTime
599
+ };
600
+ const metadata = pickRunMetadata(event.attributes);
601
+ if (metadata) started.metadata = metadata;
602
+ out.push(started);
603
+ }
604
+ if (runStatus === "success" || runStatus === "error" || event.endedAt !== void 0) {
605
+ const completed = {
606
+ schemaVersion: "0.1",
607
+ event: "run_completed",
608
+ timestamp,
609
+ runId: event.runId,
610
+ status: runStatus === "error" ? "error" : "success",
611
+ endTime,
612
+ durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
613
+ };
614
+ const error = mapPersistedError(event.error, event.attributes);
615
+ if (error) completed.error = error;
616
+ out.push(completed);
617
+ }
618
+ if (out.length === 0) {
619
+ out.push(fromLegacyRunStarted(event));
620
+ }
621
+ return out;
622
+ }
623
+ function fromNativeStep(event) {
624
+ const { timestamp, startTime, endTime } = resolveTimes(event);
625
+ const stepStatus = mapPersistedStatusToStepStatus(event.status);
626
+ const stepId = resolveStepId(event);
627
+ const out = [];
628
+ const shouldEmitStarted = stepStatus === "running" || event.startedAt !== void 0 || stepStatus === "success" || stepStatus === "error";
629
+ if (shouldEmitStarted) {
630
+ const started = {
631
+ schemaVersion: "0.1",
632
+ event: "step_started",
633
+ timestamp,
634
+ runId: event.runId,
635
+ stepId,
636
+ name: event.name,
637
+ type: resolveStepType(event),
638
+ startTime
639
+ };
640
+ if (event.parentId !== void 0) started.parentId = event.parentId;
641
+ const metadata = mapTokenUsageToMetadata(event.tokenUsage, event.attributes);
642
+ if (metadata) started.metadata = metadata;
643
+ out.push(started);
644
+ }
645
+ if (stepStatus === "success" || stepStatus === "error" || event.endedAt !== void 0 || event.durationMs !== void 0) {
646
+ const completed = {
647
+ schemaVersion: "0.1",
648
+ event: "step_completed",
649
+ timestamp,
650
+ runId: event.runId,
651
+ stepId,
652
+ status: stepStatus === "error" ? "error" : "success",
653
+ endTime,
654
+ durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
655
+ };
656
+ const error = mapPersistedError(event.error, event.attributes);
657
+ if (error) completed.error = error;
658
+ out.push(completed);
659
+ }
660
+ if (out.length === 0) {
661
+ out.push(fromLegacyStepStarted(event));
662
+ }
663
+ return out;
664
+ }
665
+ function persistedInspectEventToTraceEvents(event) {
666
+ if (!isPersistedInspectEvent(event)) {
667
+ throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
668
+ }
669
+ const legacyEvent = event.attributes?.legacyEvent;
670
+ if (legacyEvent === "run_started") return [fromLegacyRunStarted(event)];
671
+ if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
672
+ if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
673
+ if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
674
+ if (event.kind === "RUN") {
675
+ return fromNativeRun(event);
676
+ }
677
+ return fromNativeStep(event);
678
+ }
679
+
344
680
  // node_modules/.pnpm/nanoid@5.1.11/node_modules/nanoid/url-alphabet/index.js
345
681
  var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
346
682
 
@@ -370,6 +706,37 @@ function nanoid(size = 21) {
370
706
  }
371
707
 
372
708
  // packages/core/src/utils/duration.ts
709
+ function parseDuration(duration) {
710
+ const raw = typeof duration === "string" ? duration.trim() : "";
711
+ const match = raw.match(/^(\d+)(ms|[smhd])$/);
712
+ if (!match) {
713
+ throw new Error(
714
+ `Invalid duration format: ${duration}. Use a positive integer followed by ms, s, m, h, or d (e.g. 500ms, 30s, 5m, 2h, 7d).`
715
+ );
716
+ }
717
+ const amount = Number.parseInt(match[1], 10);
718
+ const unit = match[2];
719
+ if (!Number.isFinite(amount) || amount <= 0) {
720
+ throw new Error(
721
+ `Invalid duration amount: ${duration}. Amount must be a positive integer.`
722
+ );
723
+ }
724
+ switch (unit) {
725
+ case "ms":
726
+ return amount;
727
+ case "s":
728
+ return amount * 1e3;
729
+ case "m":
730
+ return amount * 60 * 1e3;
731
+ case "h":
732
+ return amount * 60 * 60 * 1e3;
733
+ case "d":
734
+ return amount * 24 * 60 * 60 * 1e3;
735
+ default: {
736
+ throw new Error(`Unknown duration unit: ${unit}`);
737
+ }
738
+ }
739
+ }
373
740
  function formatDuration(ms) {
374
741
  if (!Number.isFinite(ms)) {
375
742
  return "0ms";
@@ -514,7 +881,141 @@ function warn(message, error) {
514
881
  console.warn(`${base}: ${formatError(error).message}`);
515
882
  }
516
883
 
884
+ // packages/core/src/read-trace.ts
885
+ function isRecord4(value) {
886
+ return typeof value === "object" && value !== null && !Array.isArray(value);
887
+ }
888
+ function detectLineFormat(parsed) {
889
+ if (!isRecord4(parsed)) return "unknown";
890
+ if (parsed.schemaVersion === "0.1") return "0.1";
891
+ if (parsed.schemaVersion === "0.2") return "0.2";
892
+ if (parsed.schemaVersion === "1.0") return "1.0";
893
+ return "unknown";
894
+ }
895
+ function parseTraceJsonl(raw, options = {}) {
896
+ const validate = options.validate ?? isTraceEvent;
897
+ const emitWarning = (message) => {
898
+ if (options.warnings !== false) warn(message);
899
+ };
900
+ const persisted = [];
901
+ const traceEvents = [];
902
+ const rows = [];
903
+ let sourceEventCount = 0;
904
+ let saw01 = false;
905
+ let saw02 = false;
906
+ let saw10 = false;
907
+ let lineNumber = 0;
908
+ for (const line of raw.split(/\r?\n/)) {
909
+ lineNumber += 1;
910
+ const trimmed = line.trim();
911
+ if (trimmed === "") continue;
912
+ let parsed;
913
+ try {
914
+ parsed = JSON.parse(trimmed);
915
+ } catch {
916
+ emitWarning("Skipped invalid JSON line in trace file");
917
+ continue;
918
+ }
919
+ const format2 = detectLineFormat(parsed);
920
+ if (format2 === "0.1") {
921
+ saw01 = true;
922
+ if (validate(parsed)) {
923
+ sourceEventCount += 1;
924
+ traceEvents.push(parsed);
925
+ rows.push({ format: "0.1", event: parsed, sourceLine: lineNumber });
926
+ } else {
927
+ emitWarning("Skipped invalid trace event line in trace file");
928
+ }
929
+ continue;
930
+ }
931
+ if (format2 === "0.2" || format2 === "1.0") {
932
+ if (format2 === "0.2") saw02 = true;
933
+ else saw10 = true;
934
+ if (isPersistedInspectEvent(parsed)) {
935
+ sourceEventCount += 1;
936
+ persisted.push(parsed);
937
+ rows.push({ format: format2, event: parsed, sourceLine: lineNumber });
938
+ traceEvents.push(...persistedInspectEventToTraceEvents(parsed));
939
+ } else {
940
+ emitWarning("Skipped invalid persisted inspect event line in trace file");
941
+ }
942
+ continue;
943
+ }
944
+ emitWarning("Skipped trace line with unknown schemaVersion");
945
+ }
946
+ const seenFormats = [saw01, saw02, saw10].filter(Boolean).length;
947
+ if (seenFormats > 1) {
948
+ emitWarning(
949
+ "Trace file mixes AgentInspect schemaVersion rows; normalizing all rows"
950
+ );
951
+ }
952
+ let format = "empty";
953
+ if (seenFormats > 1) format = "mixed";
954
+ else if (saw01) format = "0.1";
955
+ else if (saw02) format = "0.2";
956
+ else if (saw10) format = "1.0";
957
+ return { format, sourceEventCount, events: traceEvents, persisted, rows };
958
+ }
959
+ function unknownTraceFormatMessage() {
960
+ return "Unsupported trace format. Expected schemaVersion 0.1 (TraceEvent), 0.2 (PersistedInspectEvent), or 1.0 (PersistedInspectEvent).";
961
+ }
962
+
517
963
  // packages/core/src/storage.ts
964
+ function isRecord5(value) {
965
+ return typeof value === "object" && value !== null && !Array.isArray(value);
966
+ }
967
+ function nonEmptyString(value) {
968
+ return typeof value === "string" && value.trim() !== "";
969
+ }
970
+ function finiteNumber(value) {
971
+ return typeof value === "number" && Number.isFinite(value);
972
+ }
973
+ function optionalErrorInfo(value) {
974
+ if (value === void 0) return true;
975
+ if (!isRecord5(value)) return false;
976
+ if (typeof value.message !== "string") return false;
977
+ if ("stack" in value && value.stack !== void 0) {
978
+ if (typeof value.stack !== "string") return false;
979
+ }
980
+ return true;
981
+ }
982
+ function validateEvent(event) {
983
+ if (!isRecord5(event)) return false;
984
+ if (event.schemaVersion !== "0.1") return false;
985
+ if (!finiteNumber(event.timestamp)) return false;
986
+ if (typeof event.event !== "string") return false;
987
+ switch (event.event) {
988
+ case "run_started": {
989
+ if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
990
+ return false;
991
+ }
992
+ if (event.metadata !== void 0 && !isRecord5(event.metadata)) {
993
+ return false;
994
+ }
995
+ return true;
996
+ }
997
+ case "run_completed": {
998
+ return nonEmptyString(event.runId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
999
+ }
1000
+ case "step_started": {
1001
+ if (!nonEmptyString(event.runId) || !nonEmptyString(event.stepId) || !nonEmptyString(event.name) || !isStepType(event.type) || !finiteNumber(event.startTime)) {
1002
+ return false;
1003
+ }
1004
+ if (event.parentId !== void 0 && typeof event.parentId !== "string") {
1005
+ return false;
1006
+ }
1007
+ if (event.metadata !== void 0 && !isRecord5(event.metadata)) {
1008
+ return false;
1009
+ }
1010
+ return true;
1011
+ }
1012
+ case "step_completed": {
1013
+ return nonEmptyString(event.runId) && nonEmptyString(event.stepId) && (event.status === "success" || event.status === "error") && finiteNumber(event.endTime) && finiteNumber(event.durationMs) && optionalErrorInfo(event.error);
1014
+ }
1015
+ default:
1016
+ return false;
1017
+ }
1018
+ }
518
1019
  function serializeEvent(event) {
519
1020
  try {
520
1021
  return JSON.stringify(event);
@@ -522,14 +1023,163 @@ function serializeEvent(event) {
522
1023
  return "";
523
1024
  }
524
1025
  }
1026
+ async function initializeTraceFile(runId, traceDir) {
1027
+ try {
1028
+ const usable = await ensureTraceDir(traceDir);
1029
+ const filePath = getTraceFilePath(runId, usable);
1030
+ await promises.writeFile(filePath, "", "utf-8");
1031
+ return filePath;
1032
+ } catch (e) {
1033
+ warn("Failed to initialize trace file", e);
1034
+ }
1035
+ try {
1036
+ const usable = await ensureTraceDir(FALLBACK_TRACE_DIR);
1037
+ const filePath = getTraceFilePath(runId, usable);
1038
+ await promises.writeFile(filePath, "", "utf-8");
1039
+ return filePath;
1040
+ } catch (e) {
1041
+ warn("Failed to initialize trace file on fallback directory", e);
1042
+ return void 0;
1043
+ }
1044
+ }
1045
+ function ensureEventWithinBounds(event) {
1046
+ const line = serializeEvent(event);
1047
+ if (line === "") return event;
1048
+ const bytes = Buffer.byteLength(line, "utf8");
1049
+ if (bytes <= DEFAULT_MAX_EVENT_BYTES) return event;
1050
+ return prepareTraceEventForDisk(event, resolveTraceSafetyOptions());
1051
+ }
1052
+ async function writeTraceEvent(event, traceDir) {
1053
+ const bounded = ensureEventWithinBounds(event);
1054
+ if (!validateEvent(bounded)) {
1055
+ warn("Skipped invalid trace event (validation failed)");
1056
+ return;
1057
+ }
1058
+ const line = serializeEvent(bounded);
1059
+ if (line === "") {
1060
+ warn("Skipped trace event (serialization failed)");
1061
+ return;
1062
+ }
1063
+ const payload = `${line}
1064
+ `;
1065
+ const tryAppend = async (dir) => {
1066
+ try {
1067
+ const usable = await ensureTraceDir(dir);
1068
+ const filePath = getTraceFilePath(event.runId, usable);
1069
+ await promises.appendFile(filePath, payload, "utf-8");
1070
+ return true;
1071
+ } catch {
1072
+ return false;
1073
+ }
1074
+ };
1075
+ if (await tryAppend(traceDir)) {
1076
+ return;
1077
+ }
1078
+ warn(`Failed to append trace event for run ${event.runId}`);
1079
+ if (await tryAppend(FALLBACK_TRACE_DIR)) {
1080
+ return;
1081
+ }
1082
+ warn("Failed to append trace event to fallback directory");
1083
+ }
1084
+ async function readTraceFile(runId, traceDir) {
1085
+ try {
1086
+ const filePath = getTraceFilePath(runId, traceDir);
1087
+ return await promises.readFile(filePath, "utf-8");
1088
+ } catch (e) {
1089
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
1090
+ return void 0;
1091
+ }
1092
+ warn("Unexpected error reading trace file", e);
1093
+ return void 0;
1094
+ }
1095
+ }
1096
+ async function readTraceEvents(runId, traceDir) {
1097
+ try {
1098
+ const filePath = getTraceFilePath(runId, traceDir);
1099
+ return await readTraceEventsFromFile(filePath);
1100
+ } catch (e) {
1101
+ warn("Failed to read trace events", e);
1102
+ return [];
1103
+ }
1104
+ }
1105
+ async function readTraceEventsFromFile(filePath) {
1106
+ try {
1107
+ const raw = await promises.readFile(filePath, "utf-8");
1108
+ return parseTraceJsonl(raw, { validate: validateEvent }).events;
1109
+ } catch (e) {
1110
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
1111
+ return [];
1112
+ }
1113
+ warn("Failed to read trace events from file", e);
1114
+ return [];
1115
+ }
1116
+ }
1117
+ async function listTraceFiles(traceDir) {
1118
+ try {
1119
+ const usable = path__default.default.resolve(traceDir);
1120
+ const names = await promises.readdir(usable);
1121
+ const jsonl = names.filter((n) => n.endsWith(".jsonl"));
1122
+ const withStat = await Promise.all(
1123
+ jsonl.map(async (name) => {
1124
+ try {
1125
+ const st = await promises.stat(path__default.default.join(usable, name));
1126
+ return { name, mtime: st.mtimeMs };
1127
+ } catch {
1128
+ return { name, mtime: 0 };
1129
+ }
1130
+ })
1131
+ );
1132
+ withStat.sort((a, b) => {
1133
+ if (b.mtime !== a.mtime) return b.mtime - a.mtime;
1134
+ return a.name.localeCompare(b.name);
1135
+ });
1136
+ return withStat.map((x) => x.name);
1137
+ } catch {
1138
+ return [];
1139
+ }
1140
+ }
1141
+ function getRunIdFromTraceFileName(fileName) {
1142
+ try {
1143
+ const base = path__default.default.basename(fileName);
1144
+ if (!base.endsWith(".jsonl")) return void 0;
1145
+ const id = base.slice(0, -".jsonl".length);
1146
+ return id === "" ? void 0 : id;
1147
+ } catch {
1148
+ return void 0;
1149
+ }
1150
+ }
525
1151
 
526
1152
  // packages/core/src/trace-event-safety.ts
527
1153
  var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
528
1154
  var DEFAULT_MAX_PREVIEW_LENGTH = 500;
529
1155
  var DEFAULT_MAX_EVENT_BYTES = 65536;
530
- function isRecord3(value) {
1156
+ function isRecord6(value) {
531
1157
  return typeof value === "object" && value !== null && !Array.isArray(value);
532
1158
  }
1159
+ var KNOWN_PERSISTED_EVENT_FIELDS = /* @__PURE__ */ new Set([
1160
+ "schemaVersion",
1161
+ "eventId",
1162
+ "runId",
1163
+ "kind",
1164
+ "name",
1165
+ "parentId",
1166
+ "status",
1167
+ "timestamp",
1168
+ "startedAt",
1169
+ "endedAt",
1170
+ "durationMs",
1171
+ "confidence",
1172
+ "source",
1173
+ "attributes",
1174
+ "inputSummary",
1175
+ "outputSummary",
1176
+ "error",
1177
+ "tokenUsage",
1178
+ "trace"
1179
+ ]);
1180
+ function isSafeExtensionFieldName(key) {
1181
+ return key !== "__proto__" && key !== "constructor" && key !== "prototype";
1182
+ }
533
1183
  function isPreviewKey(key) {
534
1184
  return key.toLowerCase().includes("preview");
535
1185
  }
@@ -549,7 +1199,7 @@ function resolveTraceSafetyOptions(options) {
549
1199
  redactEnabled = false;
550
1200
  } else if (redact === true || redact === void 0) {
551
1201
  redactEnabled = true;
552
- } else if (isRecord3(redact)) {
1202
+ } else if (isRecord6(redact)) {
553
1203
  redactEnabled = true;
554
1204
  redactionRules = redact.rules;
555
1205
  }
@@ -643,7 +1293,7 @@ function prepareMetadataForDisk(metadata, opts) {
643
1293
  0
644
1294
  );
645
1295
  const redacted = redactMetadata(
646
- isRecord3(preBounded) ? preBounded : {},
1296
+ isRecord6(preBounded) ? preBounded : {},
647
1297
  opts
648
1298
  );
649
1299
  const bounded = boundMetadataValue(
@@ -653,7 +1303,7 @@ function prepareMetadataForDisk(metadata, opts) {
653
1303
  /* @__PURE__ */ new WeakSet(),
654
1304
  0
655
1305
  );
656
- return isRecord3(bounded) ? bounded : {};
1306
+ return isRecord6(bounded) ? bounded : {};
657
1307
  } catch {
658
1308
  return { truncated: true, reason: "metadataPreparationFailed" };
659
1309
  }
@@ -802,7 +1452,7 @@ function preparePersistedSummaryForDisk(key, value, opts) {
802
1452
  }
803
1453
  }
804
1454
  function preparePersistedErrorForDisk(value, opts) {
805
- if (!isRecord3(value)) return void 0;
1455
+ if (!isRecord6(value)) return void 0;
806
1456
  try {
807
1457
  const redactor = new Redactor({
808
1458
  rules: opts.redactionRules,
@@ -829,7 +1479,7 @@ function preparePersistedErrorForDisk(value, opts) {
829
1479
  }
830
1480
  }
831
1481
  function prepareTokenUsage(value) {
832
- if (!isRecord3(value)) return void 0;
1482
+ if (!isRecord6(value)) return void 0;
833
1483
  const out = {};
834
1484
  for (const key of ["input", "output", "total", "cached"]) {
835
1485
  const item = safeGet(value, key);
@@ -840,7 +1490,7 @@ function prepareTokenUsage(value) {
840
1490
  return Object.keys(out).length > 0 ? out : void 0;
841
1491
  }
842
1492
  function prepareTraceContext(value, opts) {
843
- if (!isRecord3(value)) return void 0;
1493
+ if (!isRecord6(value)) return void 0;
844
1494
  const out = {};
845
1495
  const traceId = optionalBoundedString(safeGet(value, "traceId"), "traceId", opts);
846
1496
  const spanId = optionalBoundedString(safeGet(value, "spanId"), "spanId", opts);
@@ -854,6 +1504,25 @@ function prepareTraceContext(value, opts) {
854
1504
  if (parentSpanId !== void 0) out.parentSpanId = parentSpanId;
855
1505
  return Object.keys(out).length > 0 ? out : void 0;
856
1506
  }
1507
+ function preparePersistedExtensionFieldForDisk(key, value, opts) {
1508
+ if (isRecord6(value)) {
1509
+ return prepareMetadataForDisk(value, opts);
1510
+ }
1511
+ const prepared = prepareMetadataForDisk({ [key]: value }, opts);
1512
+ return Object.prototype.hasOwnProperty.call(prepared, key) ? prepared[key] : void 0;
1513
+ }
1514
+ function preserveV10ExtensionFields(source, candidate, opts) {
1515
+ if (candidate.schemaVersion !== "1.0") return;
1516
+ for (const [key, value] of Object.entries(source)) {
1517
+ if (KNOWN_PERSISTED_EVENT_FIELDS.has(key) || !isSafeExtensionFieldName(key)) {
1518
+ continue;
1519
+ }
1520
+ const prepared = preparePersistedExtensionFieldForDisk(key, value, opts);
1521
+ if (prepared !== void 0) {
1522
+ candidate[key] = prepared;
1523
+ }
1524
+ }
1525
+ }
857
1526
  function serializedPersistedEvent(event) {
858
1527
  try {
859
1528
  return JSON.stringify(event);
@@ -867,7 +1536,7 @@ function persistedEventByteLength(event) {
867
1536
  }
868
1537
  function minimalPersistedEvent(event, opts, originalApproxBytes) {
869
1538
  return {
870
- schemaVersion: "0.2",
1539
+ schemaVersion: event.schemaVersion,
871
1540
  eventId: truncateString(event.eventId, 128),
872
1541
  runId: truncateString(event.runId, 128),
873
1542
  kind: event.kind,
@@ -890,7 +1559,7 @@ function minimalPersistedEvent(event, opts, originalApproxBytes) {
890
1559
  }
891
1560
  function tinyPersistedEvent(event) {
892
1561
  return {
893
- schemaVersion: "0.2",
1562
+ schemaVersion: event.schemaVersion,
894
1563
  eventId: truncateString(event.eventId, 32),
895
1564
  runId: truncateString(event.runId, 32),
896
1565
  kind: event.kind,
@@ -915,9 +1584,9 @@ function enforcePersistedEventSize(event, opts) {
915
1584
  }
916
1585
  function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOptions()) {
917
1586
  try {
918
- if (!isRecord3(value)) return void 0;
1587
+ if (!isRecord6(value)) return void 0;
919
1588
  const source = safeGet(value, "source");
920
- if (!isRecord3(source)) return void 0;
1589
+ if (!isRecord6(source)) return void 0;
921
1590
  const candidate = {
922
1591
  schemaVersion: safeGet(value, "schemaVersion"),
923
1592
  eventId: requiredBoundedString(safeGet(value, "eventId"), "eventId", opts) ?? "",
@@ -949,7 +1618,7 @@ function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOp
949
1618
  if (sourceName !== void 0) candidate.source.name = sourceName;
950
1619
  if (sourceVersion !== void 0) candidate.source.version = sourceVersion;
951
1620
  const attributes = safeGet(value, "attributes");
952
- if (isRecord3(attributes)) {
1621
+ if (isRecord6(attributes)) {
953
1622
  candidate.attributes = prepareMetadataForDisk(attributes, opts);
954
1623
  }
955
1624
  if (safeGet(value, "inputSummary") !== void 0) {
@@ -972,6 +1641,7 @@ function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOp
972
1641
  if (tokenUsage !== void 0) candidate.tokenUsage = tokenUsage;
973
1642
  const trace = prepareTraceContext(safeGet(value, "trace"), opts);
974
1643
  if (trace !== void 0) candidate.trace = trace;
1644
+ preserveV10ExtensionFields(value, candidate, opts);
975
1645
  if (!isPersistedInspectEvent(candidate)) return void 0;
976
1646
  return enforcePersistedEventSize(candidate, opts);
977
1647
  } catch {
@@ -1287,6 +1957,7 @@ function createInspectorRuntime(options = {}) {
1287
1957
  }
1288
1958
 
1289
1959
  // packages/core/src/inspector.ts
1960
+ var INSPECTOR_PERSISTED_SCHEMA_VERSION = "1.0";
1290
1961
  function normalizeName(name, fallback) {
1291
1962
  if (typeof name !== "string" || name.trim() === "") return fallback;
1292
1963
  return truncateName(name.trim(), 100);
@@ -1403,7 +2074,7 @@ function createInspector(options = {}) {
1403
2074
  },
1404
2075
  async () => {
1405
2076
  await write({
1406
- schemaVersion: "0.2",
2077
+ schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
1407
2078
  eventId: `${runId}_started`,
1408
2079
  runId,
1409
2080
  kind: "RUN",
@@ -1422,7 +2093,7 @@ function createInspector(options = {}) {
1422
2093
  const result = await Promise.resolve(fn());
1423
2094
  const endedAt = nowIso();
1424
2095
  await write({
1425
- schemaVersion: "0.2",
2096
+ schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
1426
2097
  eventId: `${runId}_completed`,
1427
2098
  runId,
1428
2099
  kind: "RUN",
@@ -1440,7 +2111,7 @@ function createInspector(options = {}) {
1440
2111
  } catch (error) {
1441
2112
  const endedAt = nowIso();
1442
2113
  await write({
1443
- schemaVersion: "0.2",
2114
+ schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
1444
2115
  eventId: `${runId}_completed`,
1445
2116
  runId,
1446
2117
  kind: "RUN",
@@ -1480,7 +2151,7 @@ function createInspector(options = {}) {
1480
2151
  ...stepOptions.metadata !== void 0 ? { metadata: stepOptions.metadata } : {}
1481
2152
  };
1482
2153
  await write({
1483
- schemaVersion: "0.2",
2154
+ schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
1484
2155
  eventId: `${stepId}_started`,
1485
2156
  runId: context.runId,
1486
2157
  ...parentId !== void 0 ? { parentId } : {},
@@ -1498,7 +2169,7 @@ function createInspector(options = {}) {
1498
2169
  const result = await Promise.resolve(fn());
1499
2170
  const endedAt = nowIso();
1500
2171
  await write({
1501
- schemaVersion: "0.2",
2172
+ schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
1502
2173
  eventId: `${stepId}_completed`,
1503
2174
  runId: context.runId,
1504
2175
  kind: stepTypeToKind(stepType),
@@ -1520,7 +2191,7 @@ function createInspector(options = {}) {
1520
2191
  } catch (error) {
1521
2192
  const endedAt = nowIso();
1522
2193
  await write({
1523
- schemaVersion: "0.2",
2194
+ schemaVersion: INSPECTOR_PERSISTED_SCHEMA_VERSION,
1524
2195
  eventId: `${stepId}_completed`,
1525
2196
  runId: context.runId,
1526
2197
  kind: stepTypeToKind(stepType),
@@ -2203,6 +2874,1324 @@ function printFailedAt(stepName) {
2203
2874
  } catch {
2204
2875
  }
2205
2876
  }
2877
+ function resolveTraceDir(options = {}) {
2878
+ if (typeof options.dir === "string" && options.dir.trim() !== "") {
2879
+ return options.dir.trim();
2880
+ }
2881
+ const envDir = process.env.AGENT_INSPECT_TRACE_DIR;
2882
+ if (typeof envDir === "string" && envDir.trim() !== "") {
2883
+ return envDir.trim();
2884
+ }
2885
+ return getDefaultTraceDir();
2886
+ }
2887
+ var TraceDirectory = class {
2888
+ #dir;
2889
+ constructor(options = {}) {
2890
+ this.#dir = resolveTraceDir(options);
2891
+ }
2892
+ getPath(filename) {
2893
+ return filename ? path__default.default.join(this.#dir, filename) : this.#dir;
2894
+ }
2895
+ async list() {
2896
+ try {
2897
+ const files = await promises.readdir(this.#dir);
2898
+ return files.filter((f) => f.endsWith(".jsonl"));
2899
+ } catch (e) {
2900
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
2901
+ return [];
2902
+ }
2903
+ throw e;
2904
+ }
2905
+ }
2906
+ async getFileStats(filename) {
2907
+ return await promises.stat(this.getPath(filename));
2908
+ }
2909
+ };
2910
+ function isFiniteNumber(v) {
2911
+ return typeof v === "number" && Number.isFinite(v);
2912
+ }
2913
+ function parseIsoToMs2(value) {
2914
+ if (value === void 0) return void 0;
2915
+ const parsed = Date.parse(value);
2916
+ return Number.isFinite(parsed) ? parsed : void 0;
2917
+ }
2918
+ async function extractMetadata(filePath, _quickScan) {
2919
+ const stats = await promises.stat(filePath);
2920
+ let runIdFromFile = path__default.default.basename(filePath);
2921
+ if (runIdFromFile.endsWith(".jsonl")) {
2922
+ runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
2923
+ }
2924
+ const raw = await promises.readFile(filePath, "utf-8");
2925
+ const parsedTrace = parseTraceJsonl(raw, { warnings: false });
2926
+ let runId;
2927
+ let name;
2928
+ let startedAt;
2929
+ let endedAt;
2930
+ let explicitDurationMs;
2931
+ let hasRunStarted = false;
2932
+ let hasRunCompleted = false;
2933
+ let runCompletedStatus;
2934
+ let anyStepError = false;
2935
+ const anyKnownEvent = parsedTrace.sourceEventCount > 0;
2936
+ let persistedStatus;
2937
+ const persistedRun = parsedTrace.persisted.find(
2938
+ (event) => event.kind === "RUN"
2939
+ );
2940
+ if (persistedRun) {
2941
+ runId = persistedRun.runId;
2942
+ if (persistedRun.name.trim() !== "") {
2943
+ name = persistedRun.name;
2944
+ }
2945
+ startedAt = parseIsoToMs2(persistedRun.startedAt) ?? parseIsoToMs2(persistedRun.timestamp);
2946
+ endedAt = parseIsoToMs2(persistedRun.endedAt);
2947
+ if (isFiniteNumber(persistedRun.durationMs)) {
2948
+ explicitDurationMs = persistedRun.durationMs;
2949
+ if (endedAt === void 0 && startedAt !== void 0) {
2950
+ endedAt = startedAt + persistedRun.durationMs;
2951
+ }
2952
+ }
2953
+ if (persistedRun.status === "ok") persistedStatus = "success";
2954
+ else if (persistedRun.status === "error") persistedStatus = "error";
2955
+ else if (persistedRun.status === "running") persistedStatus = "running";
2956
+ else if (persistedRun.status === "unknown") persistedStatus = "unknown";
2957
+ } else {
2958
+ runId = parsedTrace.persisted[0]?.runId;
2959
+ }
2960
+ for (const e of parsedTrace.events) {
2961
+ if (runId === void 0 && typeof e.runId === "string") {
2962
+ runId = e.runId;
2963
+ }
2964
+ if (e.event === "run_started") {
2965
+ hasRunStarted = true;
2966
+ const rs = e;
2967
+ if (typeof rs.name === "string" && rs.name.trim() !== "") {
2968
+ name = rs.name;
2969
+ }
2970
+ if (isFiniteNumber(rs.startTime)) {
2971
+ startedAt = rs.startTime;
2972
+ } else if (isFiniteNumber(rs.timestamp)) {
2973
+ startedAt = rs.timestamp;
2974
+ }
2975
+ }
2976
+ if (e.event === "run_completed") {
2977
+ hasRunCompleted = true;
2978
+ const rc = e;
2979
+ runCompletedStatus = rc.status;
2980
+ if (isFiniteNumber(rc.endTime)) endedAt = rc.endTime;
2981
+ else if (isFiniteNumber(rc.timestamp)) endedAt = rc.timestamp;
2982
+ if (isFiniteNumber(rc.durationMs)) explicitDurationMs = rc.durationMs;
2983
+ }
2984
+ if (e.event === "step_completed") {
2985
+ const sc = e;
2986
+ if (sc.status === "error") {
2987
+ anyStepError = true;
2988
+ }
2989
+ }
2990
+ }
2991
+ const resolvedRunId = runId ?? runIdFromFile;
2992
+ let status = "unknown";
2993
+ if (hasRunCompleted && (runCompletedStatus === "success" || runCompletedStatus === "error")) {
2994
+ status = runCompletedStatus;
2995
+ } else if (anyStepError) {
2996
+ status = "error";
2997
+ } else if (persistedStatus !== void 0) {
2998
+ status = persistedStatus;
2999
+ } else if (hasRunStarted && !hasRunCompleted) {
3000
+ status = "running";
3001
+ } else if (anyKnownEvent) {
3002
+ status = "unknown";
3003
+ } else {
3004
+ status = "unknown";
3005
+ }
3006
+ const durationMs2 = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
3007
+ return {
3008
+ runId: resolvedRunId,
3009
+ name,
3010
+ status,
3011
+ startedAt,
3012
+ endedAt,
3013
+ durationMs: durationMs2,
3014
+ eventCount: parsedTrace.sourceEventCount,
3015
+ filePath,
3016
+ fileSize: stats.size,
3017
+ createdAt: stats.birthtime
3018
+ };
3019
+ }
3020
+ function isNonNegativeFiniteNumber(value) {
3021
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
3022
+ }
3023
+ function buildRunSummary(events) {
3024
+ const started = events.find(
3025
+ (e) => e.event === "run_started"
3026
+ );
3027
+ const completed = events.filter(
3028
+ (e) => e.event === "run_completed"
3029
+ );
3030
+ const lastCompleted = completed[completed.length - 1];
3031
+ const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
3032
+ const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
3033
+ const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
3034
+ const durationMs2 = lastCompleted && isFiniteNumber(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
3035
+ started && isFiniteNumber(started.startTime) ? started.startTime : void 0;
3036
+ const steps = /* @__PURE__ */ new Map();
3037
+ for (const e of events) {
3038
+ if (e.event === "step_started") {
3039
+ const s = e;
3040
+ steps.set(s.stepId, {
3041
+ type: s.type,
3042
+ name: s.name,
3043
+ status: "running",
3044
+ parentId: s.parentId,
3045
+ tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
3046
+ tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
3047
+ tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
3048
+ tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
3049
+ });
3050
+ }
3051
+ }
3052
+ for (const e of events) {
3053
+ if (e.event === "step_completed") {
3054
+ const c = e;
3055
+ const existing = steps.get(c.stepId);
3056
+ if (!existing) continue;
3057
+ existing.status = c.status;
3058
+ existing.durationMs = c.durationMs;
3059
+ }
3060
+ }
3061
+ let totalSteps = 0;
3062
+ let llmSteps = 0;
3063
+ let toolSteps = 0;
3064
+ let logicSteps = 0;
3065
+ let errorSteps = 0;
3066
+ let maxDepth = 0;
3067
+ let longestStep;
3068
+ let totalTokensInput = 0;
3069
+ let totalTokensOutput = 0;
3070
+ let totalTokensTotal = 0;
3071
+ let totalTokensCached = 0;
3072
+ let tokenBearingSteps = 0;
3073
+ let stepsWithKnownTotal = 0;
3074
+ let hasCachedTokens = false;
3075
+ const depthCache = /* @__PURE__ */ new Map();
3076
+ const computeDepth = (stepId) => {
3077
+ const cached = depthCache.get(stepId);
3078
+ if (cached !== void 0) return cached;
3079
+ const node = steps.get(stepId);
3080
+ if (!node) return 0;
3081
+ const parent = node.parentId;
3082
+ if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
3083
+ depthCache.set(stepId, 0);
3084
+ return 0;
3085
+ }
3086
+ const d = Math.min(1e3, computeDepth(parent) + 1);
3087
+ depthCache.set(stepId, d);
3088
+ return d;
3089
+ };
3090
+ for (const [id, s] of steps.entries()) {
3091
+ totalSteps += 1;
3092
+ if (s.type === "llm") llmSteps += 1;
3093
+ else if (s.type === "tool") toolSteps += 1;
3094
+ else logicSteps += 1;
3095
+ if (s.status === "error") errorSteps += 1;
3096
+ const depth = computeDepth(id);
3097
+ if (depth > maxDepth) maxDepth = depth;
3098
+ if (typeof s.durationMs === "number" && Number.isFinite(s.durationMs)) {
3099
+ if (!longestStep || s.durationMs > longestStep.durationMs) {
3100
+ longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
3101
+ }
3102
+ }
3103
+ if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
3104
+ tokenBearingSteps += 1;
3105
+ if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
3106
+ if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
3107
+ if (s.tokensTotal !== void 0) {
3108
+ totalTokensTotal += s.tokensTotal;
3109
+ stepsWithKnownTotal += 1;
3110
+ } else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
3111
+ totalTokensTotal += s.tokensInput + s.tokensOutput;
3112
+ stepsWithKnownTotal += 1;
3113
+ }
3114
+ if (s.tokensCached !== void 0) {
3115
+ totalTokensCached += s.tokensCached;
3116
+ hasCachedTokens = true;
3117
+ }
3118
+ }
3119
+ }
3120
+ const summary = {
3121
+ runId,
3122
+ name,
3123
+ status,
3124
+ durationMs: durationMs2,
3125
+ totalSteps,
3126
+ llmSteps,
3127
+ toolSteps,
3128
+ logicSteps,
3129
+ errorSteps,
3130
+ maxDepth,
3131
+ ...longestStep ? { longestStep } : {},
3132
+ ...tokenBearingSteps > 0 ? {
3133
+ totalTokens: {
3134
+ input: totalTokensInput,
3135
+ output: totalTokensOutput,
3136
+ ...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
3137
+ ...hasCachedTokens ? { cached: totalTokensCached } : {}
3138
+ }
3139
+ } : {}
3140
+ };
3141
+ return summary;
3142
+ }
3143
+
3144
+ // packages/core/src/trace-filter.ts
3145
+ function toLower(s) {
3146
+ return typeof s === "string" ? s.toLowerCase() : "";
3147
+ }
3148
+ function filterTraces(traces, options) {
3149
+ const input = [...traces];
3150
+ let out = input.filter((t) => {
3151
+ if (options.status && t.status !== options.status) return false;
3152
+ if (options.name) {
3153
+ const q = options.name.toLowerCase();
3154
+ const hay = `${toLower(t.name)} ${toLower(t.runId)}`;
3155
+ if (!hay.includes(q)) return false;
3156
+ }
3157
+ if (options.since) {
3158
+ const windowMs = parseDuration(options.since);
3159
+ const cutoff = Date.now() - windowMs;
3160
+ const started = typeof t.startedAt === "number" ? t.startedAt : void 0;
3161
+ const basis = started ?? t.createdAt.getTime();
3162
+ if (!Number.isFinite(basis) || basis < cutoff) return false;
3163
+ }
3164
+ return true;
3165
+ });
3166
+ out.sort((a, b) => {
3167
+ const aTime = (typeof a.startedAt === "number" ? a.startedAt : void 0) ?? a.createdAt.getTime();
3168
+ const bTime = (typeof b.startedAt === "number" ? b.startedAt : void 0) ?? b.createdAt.getTime();
3169
+ return bTime - aTime;
3170
+ });
3171
+ if (typeof options.limit === "number" && Number.isFinite(options.limit)) {
3172
+ const n = Math.max(0, Math.floor(options.limit));
3173
+ out = out.slice(0, n);
3174
+ }
3175
+ return out;
3176
+ }
3177
+
3178
+ // packages/core/src/timeline.ts
3179
+ function finite(n) {
3180
+ return typeof n === "number" && Number.isFinite(n);
3181
+ }
3182
+ function pickStreamingMeta(metadata) {
3183
+ if (!metadata || typeof metadata !== "object") return void 0;
3184
+ const chunkCount = metadata.chunkCount;
3185
+ const streamDurationMs = metadata.streamDurationMs;
3186
+ const streamedCharCount = metadata.streamedCharCount;
3187
+ if (!finite(chunkCount) && !finite(streamDurationMs) && !finite(streamedCharCount)) {
3188
+ return void 0;
3189
+ }
3190
+ return {
3191
+ ...finite(chunkCount) ? { chunkCount } : {},
3192
+ ...finite(streamDurationMs) ? { streamDurationMs } : {},
3193
+ ...finite(streamedCharCount) ? { streamedCharCount } : {}
3194
+ };
3195
+ }
3196
+ function pickCorrelation(metadata) {
3197
+ if (!metadata || typeof metadata !== "object") return void 0;
3198
+ const out = {};
3199
+ for (const key of [
3200
+ "correlationId",
3201
+ "requestId",
3202
+ "decisionId",
3203
+ "groupId"
3204
+ ]) {
3205
+ const v = metadata[key];
3206
+ if (typeof v === "string" && v.trim() !== "") {
3207
+ out[key] = v;
3208
+ }
3209
+ }
3210
+ return Object.keys(out).length > 0 ? out : void 0;
3211
+ }
3212
+ function buildRunTimeline(events, options = {}) {
3213
+ const started = events.find(
3214
+ (e) => e.event === "run_started"
3215
+ );
3216
+ const completed = events.filter(
3217
+ (e) => e.event === "run_completed"
3218
+ );
3219
+ const lastCompleted = completed[completed.length - 1];
3220
+ const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
3221
+ const runStart = started && finite(started.startTime) ? started.startTime : started && finite(started.timestamp) ? started.timestamp : void 0;
3222
+ const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
3223
+ const steps = /* @__PURE__ */ new Map();
3224
+ for (const e of events) {
3225
+ if (e.event === "step_started") {
3226
+ const s = e;
3227
+ steps.set(s.stepId, {
3228
+ name: s.name,
3229
+ type: s.type,
3230
+ parentId: s.parentId,
3231
+ startedAt: finite(s.startTime) ? s.startTime : s.timestamp,
3232
+ status: "running",
3233
+ metadata: s.metadata
3234
+ });
3235
+ }
3236
+ }
3237
+ for (const e of events) {
3238
+ if (e.event !== "step_completed") continue;
3239
+ const c = e;
3240
+ const node = steps.get(c.stepId);
3241
+ if (!node) continue;
3242
+ node.status = c.status;
3243
+ if (finite(c.durationMs)) node.durationMs = c.durationMs;
3244
+ }
3245
+ const depthCache = /* @__PURE__ */ new Map();
3246
+ const computeDepth = (stepId) => {
3247
+ const cached = depthCache.get(stepId);
3248
+ if (cached !== void 0) return cached;
3249
+ const node = steps.get(stepId);
3250
+ if (!node) return 0;
3251
+ const parent = node.parentId;
3252
+ if (typeof parent !== "string" || parent.trim() === "" || !steps.has(parent)) {
3253
+ depthCache.set(stepId, 0);
3254
+ return 0;
3255
+ }
3256
+ const d = Math.min(1e3, computeDepth(parent) + 1);
3257
+ depthCache.set(stepId, d);
3258
+ return d;
3259
+ };
3260
+ const entries = [];
3261
+ for (const [stepId, s] of steps.entries()) {
3262
+ const offsetMs = runStart !== void 0 && finite(s.startedAt) ? Math.max(0, s.startedAt - runStart) : 0;
3263
+ entries.push({
3264
+ stepId,
3265
+ name: s.name,
3266
+ type: s.type,
3267
+ status: s.status,
3268
+ depth: computeDepth(stepId),
3269
+ startedAt: s.startedAt,
3270
+ offsetMs,
3271
+ durationMs: s.durationMs,
3272
+ isError: s.status === "error",
3273
+ streaming: pickStreamingMeta(s.metadata)
3274
+ });
3275
+ }
3276
+ entries.sort((a, b) => a.startedAt - b.startedAt);
3277
+ const slowTopN = options.slowTopN ?? 3;
3278
+ if (options.focus === "slow" && entries.length > 0) {
3279
+ const ranked = [...entries].filter((e) => finite(e.durationMs)).sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
3280
+ const slowIds = new Set(
3281
+ ranked.slice(0, slowTopN).map((e) => e.stepId)
3282
+ );
3283
+ for (const e of entries) {
3284
+ if (slowIds.has(e.stepId)) e.slow = true;
3285
+ }
3286
+ }
3287
+ return {
3288
+ runId,
3289
+ name: typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0,
3290
+ status,
3291
+ startedAt: runStart,
3292
+ endedAt: lastCompleted && finite(lastCompleted.endTime) ? lastCompleted.endTime : void 0,
3293
+ durationMs: lastCompleted && finite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0,
3294
+ correlation: pickCorrelation(
3295
+ started?.metadata
3296
+ ),
3297
+ entries
3298
+ };
3299
+ }
3300
+ function renderTimeline(timeline, options = {}) {
3301
+ const lines = [];
3302
+ lines.push(`Timeline: ${timeline.name ?? timeline.runId}`);
3303
+ lines.push(`Run ID: ${timeline.runId}`);
3304
+ lines.push(`Status: ${timeline.status}`);
3305
+ if (timeline.startedAt !== void 0) {
3306
+ lines.push(`Started: ${formatTimestamp(timeline.startedAt)}`);
3307
+ }
3308
+ if (timeline.durationMs !== void 0) {
3309
+ lines.push(`Duration: ${formatDuration2(timeline.durationMs)}`);
3310
+ }
3311
+ if (timeline.correlation) {
3312
+ const parts = Object.entries(timeline.correlation).filter(([, v]) => typeof v === "string").map(([k, v]) => `${k}=${v}`);
3313
+ if (parts.length > 0) {
3314
+ lines.push(`Correlation: ${parts.join(", ")}`);
3315
+ }
3316
+ }
3317
+ lines.push("");
3318
+ lines.push("Steps (chronological):");
3319
+ const show = timeline.entries.filter((e) => {
3320
+ if (options.focus === "slow") return e.slow === true;
3321
+ return true;
3322
+ });
3323
+ if (show.length === 0) {
3324
+ lines.push(
3325
+ options.focus === "slow" ? "(no steps with duration for slow focus)" : "(no steps)"
3326
+ );
3327
+ return lines.join("\n");
3328
+ }
3329
+ for (const e of show) {
3330
+ const prefix = e.slow ? "[slow] " : "";
3331
+ const typeTag = e.type === "llm" ? "llm" : e.type === "tool" ? "tool" : e.type;
3332
+ const dur = e.durationMs !== void 0 ? formatDuration2(e.durationMs) : "-";
3333
+ const err = e.isError ? " error" : "";
3334
+ const off = formatDuration2(e.offsetMs);
3335
+ let line = `${prefix}+${off} ${typeTag}:${e.name} (${dur})${err}`;
3336
+ if (e.streaming?.chunkCount !== void 0) {
3337
+ line += ` chunks=${e.streaming.chunkCount}`;
3338
+ }
3339
+ if (e.streaming?.streamDurationMs !== void 0) {
3340
+ line += ` stream=${formatDuration2(e.streaming.streamDurationMs)}`;
3341
+ }
3342
+ lines.push(line);
3343
+ }
3344
+ return lines.join("\n");
3345
+ }
3346
+
3347
+ // packages/core/src/what.ts
3348
+ function pickCorrelation2(metadata) {
3349
+ if (!metadata) return void 0;
3350
+ const out = {};
3351
+ for (const key of [
3352
+ "correlationId",
3353
+ "requestId",
3354
+ "decisionId",
3355
+ "groupId"
3356
+ ]) {
3357
+ const value = metadata[key];
3358
+ if (typeof value === "string" && value.trim() !== "") {
3359
+ out[key] = value;
3360
+ }
3361
+ }
3362
+ return Object.keys(out).length > 0 ? out : void 0;
3363
+ }
3364
+ function stepMixLine(summary) {
3365
+ const parts = [];
3366
+ if (summary.llmSteps > 0) parts.push(`${summary.llmSteps} LLM`);
3367
+ if (summary.toolSteps > 0) parts.push(`${summary.toolSteps} tool`);
3368
+ if (summary.logicSteps > 0) parts.push(`${summary.logicSteps} logic`);
3369
+ return parts.length > 0 ? parts.join(", ") : "none";
3370
+ }
3371
+ function outcomeLine(summary) {
3372
+ if (summary.status === "success") {
3373
+ return summary.errorSteps > 0 ? "Completed with step errors recorded." : "Completed successfully.";
3374
+ }
3375
+ if (summary.status === "error") {
3376
+ if (summary.failedStepNames.length > 0) {
3377
+ const names = summary.failedStepNames.slice(0, 3).join(", ");
3378
+ const suffix = summary.failedStepNames.length > 3 ? ` (+${summary.failedStepNames.length - 3} more)` : "";
3379
+ return `Failed at step(s): ${names}${suffix}.`;
3380
+ }
3381
+ if (summary.runErrorMessage) {
3382
+ return `Run failed: ${summary.runErrorMessage}`;
3383
+ }
3384
+ return "Run failed.";
3385
+ }
3386
+ if (summary.status === "running") {
3387
+ return "Run is still in progress (no run_completed).";
3388
+ }
3389
+ return "Outcome unknown \u2014 inspect events may be incomplete.";
3390
+ }
3391
+ function buildRunWhatSummary(events) {
3392
+ const base = buildRunSummary(events);
3393
+ const started = events.find(
3394
+ (e) => e.event === "run_started"
3395
+ );
3396
+ const completed = events.filter(
3397
+ (e) => e.event === "run_completed"
3398
+ );
3399
+ const lastCompleted = completed[completed.length - 1];
3400
+ const failedStepNames = [];
3401
+ const stepNames = /* @__PURE__ */ new Map();
3402
+ for (const e of events) {
3403
+ if (e.event === "step_started") {
3404
+ const s = e;
3405
+ stepNames.set(s.stepId, s.name);
3406
+ }
3407
+ }
3408
+ for (const e of events) {
3409
+ if (e.event === "step_completed") {
3410
+ const sc = e;
3411
+ if (sc.status === "error") {
3412
+ failedStepNames.push(stepNames.get(sc.stepId) ?? sc.stepId);
3413
+ }
3414
+ }
3415
+ }
3416
+ return {
3417
+ runId: base.runId,
3418
+ name: base.name,
3419
+ status: base.status,
3420
+ durationMs: base.durationMs,
3421
+ totalSteps: base.totalSteps,
3422
+ llmSteps: base.llmSteps,
3423
+ toolSteps: base.toolSteps,
3424
+ logicSteps: base.logicSteps,
3425
+ errorSteps: base.errorSteps,
3426
+ maxDepth: base.maxDepth,
3427
+ longestStep: base.longestStep,
3428
+ totalTokens: base.totalTokens,
3429
+ correlation: pickCorrelation2(started?.metadata),
3430
+ failedStepNames,
3431
+ runErrorMessage: lastCompleted?.error?.message
3432
+ };
3433
+ }
3434
+ function renderRunWhat(summary, options = {}) {
3435
+ const showCorrelation = options.correlation !== false;
3436
+ const lines = [];
3437
+ const label = summary.name ?? summary.runId;
3438
+ lines.push(`What: ${label}`);
3439
+ const duration = summary.durationMs !== void 0 ? formatDuration2(summary.durationMs) : "\u2014";
3440
+ lines.push(
3441
+ `Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
3442
+ );
3443
+ if (summary.totalTokens) {
3444
+ const tokenParts = [
3445
+ `${summary.totalTokens.input} in`,
3446
+ `${summary.totalTokens.output} out`
3447
+ ];
3448
+ if (summary.totalTokens.total !== void 0) {
3449
+ tokenParts.push(`${summary.totalTokens.total} total`);
3450
+ }
3451
+ if (summary.totalTokens.cached !== void 0) {
3452
+ tokenParts.push(`${summary.totalTokens.cached} cached`);
3453
+ }
3454
+ lines.push(`Tokens: ${tokenParts.join(" / ")}`);
3455
+ }
3456
+ if (showCorrelation && summary.correlation) {
3457
+ const parts = [];
3458
+ if (summary.correlation.correlationId) {
3459
+ parts.push(`correlationId=${summary.correlation.correlationId}`);
3460
+ }
3461
+ if (summary.correlation.requestId) {
3462
+ parts.push(`requestId=${summary.correlation.requestId}`);
3463
+ }
3464
+ if (summary.correlation.decisionId) {
3465
+ parts.push(`decisionId=${summary.correlation.decisionId}`);
3466
+ }
3467
+ if (summary.correlation.groupId) {
3468
+ parts.push(`groupId=${summary.correlation.groupId}`);
3469
+ }
3470
+ if (parts.length > 0) {
3471
+ lines.push(`Correlation: ${parts.join(", ")}`);
3472
+ }
3473
+ }
3474
+ lines.push(`Outcome: ${outcomeLine(summary)}`);
3475
+ if (summary.longestStep && summary.totalSteps > 0) {
3476
+ lines.push(
3477
+ `Slowest: ${summary.longestStep.name} (${formatDuration2(summary.longestStep.durationMs)}, ${summary.longestStep.type})`
3478
+ );
3479
+ }
3480
+ if (summary.maxDepth > 0) {
3481
+ lines.push(`Max depth: ${summary.maxDepth}`);
3482
+ }
3483
+ return lines.join("\n");
3484
+ }
3485
+
3486
+ // packages/core/src/explain.ts
3487
+ function flatten(nodes, out = []) {
3488
+ for (const node of nodes) {
3489
+ out.push({ node, index: out.length + 1 });
3490
+ flatten(node.children, out);
3491
+ }
3492
+ return out;
3493
+ }
3494
+ function redactValue(redactor, key, value) {
3495
+ return redactor.redactValue(key, value);
3496
+ }
3497
+ function fact(id, label, value, redactor) {
3498
+ return {
3499
+ id,
3500
+ label,
3501
+ value: redactValue(redactor, id.split(".").at(-1) ?? id, value),
3502
+ source: "trace",
3503
+ confidence: "observed"
3504
+ };
3505
+ }
3506
+ function topKinds(run) {
3507
+ return Object.entries(run.metadata.kinds).filter(([, count]) => count > 0).sort((a, b) => {
3508
+ if (b[1] !== a[1]) return b[1] - a[1];
3509
+ return a[0].localeCompare(b[0]);
3510
+ }).slice(0, 5).map(([kind, count]) => `${kind}:${count}`);
3511
+ }
3512
+ function countErrorNodes(nodes) {
3513
+ return nodes.filter((entry) => entry.node.event.status === "error").length;
3514
+ }
3515
+ function slowestNode(nodes) {
3516
+ return nodes.filter((entry) => entry.node.event.durationMs !== void 0).sort((a, b) => {
3517
+ const delta = (b.node.event.durationMs ?? 0) - (a.node.event.durationMs ?? 0);
3518
+ return delta !== 0 ? delta : a.index - b.index;
3519
+ })[0];
3520
+ }
3521
+ function attributeFacts(nodes, redactor) {
3522
+ const facts = [];
3523
+ for (const entry of nodes) {
3524
+ const attrs = entry.node.event.attributes;
3525
+ if (attrs === void 0) continue;
3526
+ for (const key of Object.keys(attrs).sort()) {
3527
+ facts.push({
3528
+ id: `node.${entry.index}.attributes.${key}`,
3529
+ label: `${entry.node.event.name} attribute ${key}`,
3530
+ value: redactValue(redactor, key, attrs[key]),
3531
+ source: "trace",
3532
+ confidence: "observed"
3533
+ });
3534
+ if (facts.length >= 8) return facts;
3535
+ }
3536
+ }
3537
+ return facts;
3538
+ }
3539
+ function buildFacts(run, redactor) {
3540
+ const nodes = flatten(run.children);
3541
+ const facts = [
3542
+ fact("run.id", "Run id", run.runId, redactor),
3543
+ fact("run.name", "Run name", run.name ?? run.runId, redactor),
3544
+ fact("run.status", "Run status", run.status ?? "unknown", redactor),
3545
+ fact("run.totalEvents", "Total events", run.metadata.totalEvents, redactor),
3546
+ fact("run.stepCount", "Top-level step count", run.children.length, redactor),
3547
+ fact("run.nodeCount", "Total node count", nodes.length, redactor),
3548
+ fact("run.errorNodeCount", "Error node count", countErrorNodes(nodes), redactor),
3549
+ fact("run.kinds", "Observed kind mix", topKinds(run), redactor)
3550
+ ];
3551
+ if (run.durationMs !== void 0) {
3552
+ facts.push(fact("run.durationMs", "Run duration milliseconds", run.durationMs, redactor));
3553
+ }
3554
+ const slowest = slowestNode(nodes);
3555
+ if (slowest !== void 0) {
3556
+ facts.push(
3557
+ fact("run.slowestNode", "Slowest observed node", {
3558
+ name: slowest.node.event.name,
3559
+ kind: slowest.node.event.kind,
3560
+ durationMs: slowest.node.event.durationMs
3561
+ }, redactor)
3562
+ );
3563
+ }
3564
+ facts.push(...attributeFacts(nodes, redactor));
3565
+ return facts;
3566
+ }
3567
+ function buildInferences(run, facts) {
3568
+ const inferences = [];
3569
+ const errorFact = facts.find((item) => item.id === "run.errorNodeCount");
3570
+ const kindFact = facts.find((item) => item.id === "run.kinds");
3571
+ const durationFact = facts.find((item) => item.id === "run.durationMs");
3572
+ const errorNodeCount = typeof errorFact?.value === "number" ? errorFact.value : 0;
3573
+ if (run.status === "error" || errorNodeCount > 0) {
3574
+ inferences.push({
3575
+ id: "outcome.error",
3576
+ label: "Outcome",
3577
+ text: "The run recorded an error status or at least one error node.",
3578
+ evidence: ["run.status", "run.errorNodeCount"],
3579
+ confidence: "deterministic"
3580
+ });
3581
+ } else if (run.status === "ok") {
3582
+ inferences.push({
3583
+ id: "outcome.success",
3584
+ label: "Outcome",
3585
+ text: "The run completed without observed error nodes.",
3586
+ evidence: ["run.status", "run.errorNodeCount"],
3587
+ confidence: "deterministic"
3588
+ });
3589
+ }
3590
+ if (kindFact !== void 0) {
3591
+ inferences.push({
3592
+ id: "shape.kind-mix",
3593
+ label: "Trace shape",
3594
+ text: "The explanation is based on the observed event kind mix, not generated content.",
3595
+ evidence: [kindFact.id],
3596
+ confidence: "deterministic"
3597
+ });
3598
+ }
3599
+ if (durationFact !== void 0) {
3600
+ inferences.push({
3601
+ id: "timing.duration",
3602
+ label: "Timing",
3603
+ text: "Timing claims are limited to persisted duration fields in the trace.",
3604
+ evidence: [durationFact.id],
3605
+ confidence: "deterministic"
3606
+ });
3607
+ }
3608
+ return inferences;
3609
+ }
3610
+ function buildLocalExplanation(run, options = {}) {
3611
+ const redactionProfile = options.redactionProfile ?? "local";
3612
+ const resolved = resolveRedactionProfile(redactionProfile);
3613
+ const redactor = new Redactor({ extraKeys: resolved.extraKeys });
3614
+ const mode = options.mode ?? "local";
3615
+ const facts = buildFacts(run, redactor);
3616
+ return {
3617
+ mode,
3618
+ runId: String(redactValue(redactor, "runId", run.runId)),
3619
+ ...run.name !== void 0 ? { name: String(redactValue(redactor, "name", run.name)) } : {},
3620
+ ...run.status !== void 0 ? { status: run.status } : {},
3621
+ redactionProfile,
3622
+ facts,
3623
+ inferences: mode === "dry-run" ? [] : buildInferences(run, facts),
3624
+ notes: [
3625
+ "Generated locally without provider or network calls.",
3626
+ "Facts are observed from normalized trace data; inferences are deterministic labels."
3627
+ ]
3628
+ };
3629
+ }
3630
+
3631
+ // packages/core/src/stats.ts
3632
+ function percentile(sorted, p) {
3633
+ if (sorted.length === 0) return void 0;
3634
+ const idx = Math.min(
3635
+ sorted.length - 1,
3636
+ Math.max(0, Math.ceil(p / 100 * sorted.length) - 1)
3637
+ );
3638
+ return sorted[idx];
3639
+ }
3640
+ async function readRunStartedMetadata(filePath) {
3641
+ try {
3642
+ const events = await readTraceEventsFromFile(filePath);
3643
+ for (const event of events) {
3644
+ if (event.event !== "run_started") continue;
3645
+ const rs = event;
3646
+ if (rs.metadata && typeof rs.metadata === "object") {
3647
+ return rs.metadata;
3648
+ }
3649
+ return void 0;
3650
+ }
3651
+ } catch {
3652
+ }
3653
+ return void 0;
3654
+ }
3655
+ function metaMatchesCorrelation(metadata, correlationId, groupId) {
3656
+ if (correlationId) {
3657
+ const v = metadata?.correlationId;
3658
+ if (typeof v !== "string" || v !== correlationId) return false;
3659
+ }
3660
+ if (groupId) {
3661
+ const v = metadata?.groupId;
3662
+ if (typeof v !== "string" || v !== groupId) return false;
3663
+ }
3664
+ return true;
3665
+ }
3666
+ async function buildTraceStats(metas, options) {
3667
+ let filtered = filterTraces(metas, { since: options.since });
3668
+ if (options.correlationId || options.groupId) {
3669
+ const next = [];
3670
+ for (const m of filtered) {
3671
+ const md = await readRunStartedMetadata(m.filePath);
3672
+ if (metaMatchesCorrelation(md, options.correlationId, options.groupId)) {
3673
+ next.push(m);
3674
+ }
3675
+ }
3676
+ filtered = next;
3677
+ }
3678
+ let successCount = 0;
3679
+ let errorCount = 0;
3680
+ let runningCount = 0;
3681
+ let unknownCount = 0;
3682
+ const durations = [];
3683
+ let totalSteps = 0;
3684
+ let totalLlmSteps = 0;
3685
+ let totalToolSteps = 0;
3686
+ let totalErrorSteps = 0;
3687
+ const slowestRuns = [];
3688
+ const slowestSteps = [];
3689
+ for (const m of filtered) {
3690
+ if (m.status === "success") successCount += 1;
3691
+ else if (m.status === "error") errorCount += 1;
3692
+ else if (m.status === "running") runningCount += 1;
3693
+ else unknownCount += 1;
3694
+ if (typeof m.durationMs === "number" && Number.isFinite(m.durationMs) && m.durationMs >= 0) {
3695
+ durations.push(m.durationMs);
3696
+ slowestRuns.push({
3697
+ runId: m.runId,
3698
+ name: m.name,
3699
+ durationMs: m.durationMs,
3700
+ status: m.status
3701
+ });
3702
+ }
3703
+ try {
3704
+ const events = await readTraceEventsFromFile(m.filePath);
3705
+ if (events.length === 0) continue;
3706
+ const summary = buildRunSummary(events);
3707
+ totalSteps += summary.totalSteps;
3708
+ totalLlmSteps += summary.llmSteps;
3709
+ totalToolSteps += summary.toolSteps;
3710
+ totalErrorSteps += summary.errorSteps;
3711
+ const steps = collectCompletedSteps(events, m.runId);
3712
+ for (const s of steps) {
3713
+ slowestSteps.push(s);
3714
+ }
3715
+ } catch {
3716
+ }
3717
+ }
3718
+ slowestRuns.sort((a, b) => (b.durationMs ?? 0) - (a.durationMs ?? 0));
3719
+ slowestSteps.sort((a, b) => b.durationMs - a.durationMs);
3720
+ const runLimit = options.slowRunLimit ?? 5;
3721
+ const stepLimit = options.slowStepLimit ?? 5;
3722
+ const sortedDur = [...durations].sort((a, b) => a - b);
3723
+ const totalRuns = filtered.length;
3724
+ const errorRate = totalRuns > 0 ? errorCount / totalRuns : 0;
3725
+ const sumDur = durations.reduce((a, b) => a + b, 0);
3726
+ return {
3727
+ traceDir: options.traceDir,
3728
+ ...options.since ? { since: options.since } : {},
3729
+ ...options.correlationId ? { correlationId: options.correlationId } : {},
3730
+ ...options.groupId ? { groupId: options.groupId } : {},
3731
+ totalRuns,
3732
+ successCount,
3733
+ errorCount,
3734
+ runningCount,
3735
+ unknownCount,
3736
+ errorRate,
3737
+ duration: {
3738
+ ...sortedDur.length > 0 ? {
3739
+ minMs: sortedDur[0],
3740
+ maxMs: sortedDur[sortedDur.length - 1],
3741
+ avgMs: sumDur / sortedDur.length,
3742
+ p50Ms: percentile(sortedDur, 50),
3743
+ p95Ms: percentile(sortedDur, 95)
3744
+ } : {}
3745
+ },
3746
+ totalSteps,
3747
+ avgStepsPerRun: totalRuns > 0 ? totalSteps / totalRuns : 0,
3748
+ totalLlmSteps,
3749
+ totalToolSteps,
3750
+ totalErrorSteps,
3751
+ slowestRuns: slowestRuns.slice(0, runLimit),
3752
+ slowestSteps: slowestSteps.slice(0, stepLimit)
3753
+ };
3754
+ }
3755
+ function collectCompletedSteps(events, runId) {
3756
+ const started = /* @__PURE__ */ new Map();
3757
+ const out = [];
3758
+ for (const e of events) {
3759
+ if (e.event === "step_started") {
3760
+ const s = e;
3761
+ started.set(s.stepId, { name: s.name, type: s.type });
3762
+ }
3763
+ if (e.event === "step_completed") {
3764
+ const c = e;
3765
+ if (c.status !== "success" && c.status !== "error") continue;
3766
+ if (typeof c.durationMs !== "number" || !Number.isFinite(c.durationMs)) {
3767
+ continue;
3768
+ }
3769
+ const meta = started.get(c.stepId);
3770
+ out.push({
3771
+ runId,
3772
+ stepName: meta?.name ?? c.stepId,
3773
+ stepType: meta?.type ?? "logic",
3774
+ durationMs: c.durationMs
3775
+ });
3776
+ }
3777
+ }
3778
+ return out;
3779
+ }
3780
+ function renderTraceStats(stats) {
3781
+ const lines = [];
3782
+ lines.push("Trace stats (local)");
3783
+ lines.push(`Directory: ${stats.traceDir}`);
3784
+ if (stats.since) lines.push(`Since: ${stats.since}`);
3785
+ if (stats.correlationId) lines.push(`Correlation ID: ${stats.correlationId}`);
3786
+ if (stats.groupId) lines.push(`Group ID: ${stats.groupId}`);
3787
+ lines.push("");
3788
+ lines.push(`Runs: ${stats.totalRuns}`);
3789
+ lines.push(
3790
+ ` success: ${stats.successCount} error: ${stats.errorCount} running: ${stats.runningCount} unknown: ${stats.unknownCount}`
3791
+ );
3792
+ lines.push(`Error rate: ${(stats.errorRate * 100).toFixed(1)}%`);
3793
+ if (stats.duration.avgMs !== void 0) {
3794
+ lines.push(
3795
+ `Duration: min ${formatDuration2(stats.duration.minMs ?? 0)} | avg ${formatDuration2(stats.duration.avgMs)} | p50 ${formatDuration2(stats.duration.p50Ms ?? 0)} | p95 ${formatDuration2(stats.duration.p95Ms ?? 0)} | max ${formatDuration2(stats.duration.maxMs ?? 0)}`
3796
+ );
3797
+ }
3798
+ lines.push("");
3799
+ lines.push(`Steps: ${stats.totalSteps} (avg ${stats.avgStepsPerRun.toFixed(1)} per run)`);
3800
+ lines.push(
3801
+ ` LLM: ${stats.totalLlmSteps} tool: ${stats.totalToolSteps} errors: ${stats.totalErrorSteps}`
3802
+ );
3803
+ if (stats.slowestRuns.length > 0) {
3804
+ lines.push("");
3805
+ lines.push("Slowest runs:");
3806
+ for (const r of stats.slowestRuns) {
3807
+ lines.push(
3808
+ ` ${r.runId} | ${r.name ?? "-"} | ${formatDuration2(r.durationMs ?? 0)} | ${r.status}`
3809
+ );
3810
+ }
3811
+ }
3812
+ if (stats.slowestSteps.length > 0) {
3813
+ lines.push("");
3814
+ lines.push("Slowest steps:");
3815
+ for (const s of stats.slowestSteps) {
3816
+ lines.push(
3817
+ ` ${s.runId} | ${s.stepType}:${s.stepName} | ${formatDuration2(s.durationMs)}`
3818
+ );
3819
+ }
3820
+ }
3821
+ return lines.join("\n");
3822
+ }
3823
+
3824
+ // packages/core/src/search.ts
3825
+ function parseDurationFilter(expr) {
3826
+ const raw = expr.trim();
3827
+ const m = raw.match(/^(>=|<=|>|<)\s*(.+)$/);
3828
+ if (!m) {
3829
+ throw new Error(
3830
+ `Invalid --duration "${expr}". Use forms like >5s, >=500ms, <2m.`
3831
+ );
3832
+ }
3833
+ const op = m[1];
3834
+ const ms = parseDuration(m[2].trim());
3835
+ return { op, ms };
3836
+ }
3837
+ function durationMatches(valueMs, filter) {
3838
+ if (valueMs === void 0 || !Number.isFinite(valueMs)) return false;
3839
+ switch (filter.op) {
3840
+ case ">":
3841
+ return valueMs > filter.ms;
3842
+ case ">=":
3843
+ return valueMs >= filter.ms;
3844
+ case "<":
3845
+ return valueMs < filter.ms;
3846
+ case "<=":
3847
+ return valueMs <= filter.ms;
3848
+ default:
3849
+ return false;
3850
+ }
3851
+ }
3852
+ function normalizeStepTypeFilter(kind, type) {
3853
+ const v = (kind ?? type)?.trim().toLowerCase();
3854
+ return v && v !== "" ? v : void 0;
3855
+ }
3856
+ function nameMatches(hay, needle) {
3857
+ return hay.toLowerCase().includes(needle.toLowerCase());
3858
+ }
3859
+ async function searchTraces(metas, options) {
3860
+ let filtered = filterTraces(metas, { since: options.since });
3861
+ const stepTypeFilter = normalizeStepTypeFilter(options.kind, options.type);
3862
+ const nameQuery = options.name?.trim();
3863
+ const toolQuery = options.tool?.trim();
3864
+ let durationFilter;
3865
+ if (options.duration) {
3866
+ durationFilter = parseDurationFilter(options.duration);
3867
+ }
3868
+ const limit = options.limit ?? 50;
3869
+ const hasContentFilter = Boolean(
3870
+ options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
3871
+ );
3872
+ const results = [];
3873
+ if (!hasContentFilter) {
3874
+ for (const m of filtered) {
3875
+ results.push({
3876
+ runId: m.runId,
3877
+ runName: m.name,
3878
+ runStatus: m.status,
3879
+ timestamp: m.startedAt,
3880
+ durationMs: m.durationMs,
3881
+ matchReason: "trace in directory",
3882
+ matchedFields: ["run"],
3883
+ filePath: m.filePath
3884
+ });
3885
+ }
3886
+ return results.slice(0, limit);
3887
+ }
3888
+ for (const m of filtered) {
3889
+ if (options.status && m.status !== options.status) continue;
3890
+ let events = [];
3891
+ try {
3892
+ events = await readTraceEventsFromFile(m.filePath);
3893
+ } catch {
3894
+ continue;
3895
+ }
3896
+ if (events.length === 0) continue;
3897
+ const runMatches = matchRunLevel(m, {
3898
+ stepTypeFilter,
3899
+ nameQuery,
3900
+ toolQuery,
3901
+ durationFilter,
3902
+ statusFilter: options.status
3903
+ });
3904
+ results.push(...runMatches);
3905
+ const stepMatches = matchStepLevel(m, events, {
3906
+ stepTypeFilter,
3907
+ nameQuery,
3908
+ toolQuery,
3909
+ durationFilter,
3910
+ statusFilter: options.status
3911
+ });
3912
+ results.push(...stepMatches);
3913
+ }
3914
+ results.sort((a, b) => {
3915
+ const ta = a.timestamp ?? 0;
3916
+ const tb = b.timestamp ?? 0;
3917
+ if (ta !== tb) return ta - tb;
3918
+ const runCmp = a.runId.localeCompare(b.runId);
3919
+ if (runCmp !== 0) return runCmp;
3920
+ return (a.stepName ?? "").localeCompare(b.stepName ?? "");
3921
+ });
3922
+ return results.slice(0, limit);
3923
+ }
3924
+ function matchRunLevel(m, opts) {
3925
+ if (opts.stepTypeFilter || opts.toolQuery) return [];
3926
+ const out = [];
3927
+ const fields = [];
3928
+ if (opts.statusFilter && m.status === opts.statusFilter) {
3929
+ fields.push("run.status");
3930
+ }
3931
+ if (opts.nameQuery && nameMatches(m.name ?? m.runId, opts.nameQuery)) {
3932
+ fields.push("run.name");
3933
+ }
3934
+ if (opts.durationFilter && durationMatches(m.durationMs, opts.durationFilter)) {
3935
+ fields.push("run.durationMs");
3936
+ }
3937
+ if (fields.length === 0) return out;
3938
+ out.push({
3939
+ runId: m.runId,
3940
+ runName: m.name,
3941
+ runStatus: m.status,
3942
+ timestamp: m.startedAt,
3943
+ durationMs: m.durationMs,
3944
+ matchReason: `run match: ${fields.join(", ")}`,
3945
+ matchedFields: fields,
3946
+ filePath: m.filePath
3947
+ });
3948
+ return out;
3949
+ }
3950
+ function matchStepLevel(m, events, opts) {
3951
+ const out = [];
3952
+ const started = /* @__PURE__ */ new Map();
3953
+ for (const e of events) {
3954
+ if (e.event === "step_started") {
3955
+ started.set(e.stepId, e);
3956
+ }
3957
+ }
3958
+ for (const e of events) {
3959
+ if (e.event !== "step_completed") continue;
3960
+ const c = e;
3961
+ const s = started.get(c.stepId);
3962
+ if (!s) continue;
3963
+ const fields = [];
3964
+ const stepType = s.type;
3965
+ if (opts.stepTypeFilter && stepType !== opts.stepTypeFilter) {
3966
+ continue;
3967
+ }
3968
+ const hasStepFilters = opts.stepTypeFilter || opts.nameQuery || opts.toolQuery || opts.durationFilter || opts.statusFilter === "error" || opts.statusFilter === "success";
3969
+ if (!hasStepFilters) continue;
3970
+ if (opts.statusFilter === "error" && c.status === "error") {
3971
+ fields.push("step.status");
3972
+ } else if (opts.statusFilter === "success" && c.status === "success") {
3973
+ fields.push("step.status");
3974
+ } else if (opts.statusFilter === "error" || opts.statusFilter === "success") {
3975
+ continue;
3976
+ }
3977
+ if (opts.nameQuery) {
3978
+ if (!nameMatches(s.name, opts.nameQuery)) continue;
3979
+ fields.push("step.name");
3980
+ }
3981
+ if (opts.toolQuery) {
3982
+ const toolName = typeof s.metadata?.toolName === "string" ? s.metadata.toolName : s.name;
3983
+ if (!nameMatches(toolName, opts.toolQuery)) continue;
3984
+ fields.push("step.tool");
3985
+ }
3986
+ if (opts.durationFilter) {
3987
+ if (!durationMatches(c.durationMs, opts.durationFilter)) continue;
3988
+ fields.push("step.durationMs");
3989
+ }
3990
+ if (opts.stepTypeFilter) {
3991
+ fields.push("step.type");
3992
+ }
3993
+ if (fields.length === 0) continue;
3994
+ out.push({
3995
+ runId: m.runId,
3996
+ runName: m.name,
3997
+ runStatus: m.status,
3998
+ stepId: c.stepId,
3999
+ stepName: s.name,
4000
+ stepType,
4001
+ timestamp: s.startTime ?? s.timestamp,
4002
+ durationMs: c.durationMs,
4003
+ matchReason: `step match: ${fields.join(", ")}`,
4004
+ matchedFields: fields,
4005
+ filePath: m.filePath
4006
+ });
4007
+ }
4008
+ return out;
4009
+ }
4010
+ async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
4011
+ const metas = [];
4012
+ for (const fileName of fileNames) {
4013
+ try {
4014
+ const filePath = getPath(fileName);
4015
+ const meta = await extractMetadata(filePath);
4016
+ metas.push(meta);
4017
+ } catch {
4018
+ }
4019
+ }
4020
+ return metas;
4021
+ }
4022
+ var KNOWN_EVENTS = /* @__PURE__ */ new Set([
4023
+ "run_started",
4024
+ "run_completed",
4025
+ "step_started",
4026
+ "step_completed"
4027
+ ]);
4028
+ function isRecord7(value) {
4029
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4030
+ }
4031
+ function safeParse(line) {
4032
+ try {
4033
+ return JSON.parse(line);
4034
+ } catch {
4035
+ return void 0;
4036
+ }
4037
+ }
4038
+ async function isAgentInspectTrace(filePath) {
4039
+ try {
4040
+ const rl = readline.createInterface({
4041
+ input: fs.createReadStream(filePath, { encoding: "utf8" }),
4042
+ crlfDelay: Infinity
4043
+ });
4044
+ let checked = 0;
4045
+ for await (const line of rl) {
4046
+ const trimmed = line.trim();
4047
+ if (trimmed === "") continue;
4048
+ const parsed = safeParse(trimmed);
4049
+ if (!parsed) continue;
4050
+ if (!isRecord7(parsed)) continue;
4051
+ checked += 1;
4052
+ if (isTraceEvent(parsed)) return true;
4053
+ const ev = parsed.event;
4054
+ const runId = parsed.runId;
4055
+ if (typeof ev === "string" && KNOWN_EVENTS.has(ev) && typeof runId === "string") {
4056
+ return true;
4057
+ }
4058
+ if (checked >= 20) break;
4059
+ }
4060
+ return false;
4061
+ } catch {
4062
+ return false;
4063
+ }
4064
+ }
4065
+
4066
+ // packages/core/src/inspect-run.ts
4067
+ function normalizeRunName(name) {
4068
+ if (typeof name !== "string" || name.trim() === "") {
4069
+ return "unnamed-run";
4070
+ }
4071
+ return truncateName(name.trim(), 100);
4072
+ }
4073
+ async function safeInstrumentation(label, op) {
4074
+ try {
4075
+ await Promise.resolve(op());
4076
+ } catch (e) {
4077
+ warn(`inspectRun: ${label}`, e);
4078
+ }
4079
+ }
4080
+ async function inspectRun(name, fn, options) {
4081
+ if (typeof fn !== "function") {
4082
+ throw new TypeError("inspectRun requires `fn` to be a function");
4083
+ }
4084
+ if (options?.enabled === false) {
4085
+ return Promise.resolve(fn());
4086
+ }
4087
+ const runName = normalizeRunName(name);
4088
+ const runId = createRunId();
4089
+ const traceDir = resolveTraceDir({ dir: options?.traceDir });
4090
+ const traceSafety = resolveTraceSafetyOptions(options);
4091
+ const runMetadata = buildRunStartedMetadata(options);
4092
+ const context = {
4093
+ runId,
4094
+ runName,
4095
+ traceDir,
4096
+ silent: options?.silent ?? false,
4097
+ metadata: runMetadata
4098
+ };
4099
+ return runWithContext(context, async () => {
4100
+ const startTime = Date.now();
4101
+ let traceFilePath;
4102
+ await safeInstrumentation("initializeTraceFile", async () => {
4103
+ traceFilePath = await initializeTraceFile(runId, traceDir);
4104
+ });
4105
+ await safeInstrumentation("writeTraceEvent(run_started)", async () => {
4106
+ const started = {
4107
+ schemaVersion: "0.1",
4108
+ event: "run_started",
4109
+ timestamp: startTime,
4110
+ runId,
4111
+ name: runName,
4112
+ startTime,
4113
+ ...runMetadata !== void 0 ? { metadata: runMetadata } : {}
4114
+ };
4115
+ await writeTraceEvent(
4116
+ prepareTraceEventForDisk(started, traceSafety),
4117
+ traceDir
4118
+ );
4119
+ });
4120
+ await safeInstrumentation("printRunStart", () => {
4121
+ printRunStart(runId, runName);
4122
+ });
4123
+ let result;
4124
+ try {
4125
+ result = await Promise.resolve(fn());
4126
+ } catch (userError) {
4127
+ const endTime2 = Date.now();
4128
+ const durationMs3 = endTime2 - startTime;
4129
+ const formatted = formatError(userError);
4130
+ const printPath2 = traceFilePath ?? getTraceFilePath(runId, traceDir);
4131
+ await safeInstrumentation("writeTraceEvent(run_completed error)", async () => {
4132
+ const completed = {
4133
+ schemaVersion: "0.1",
4134
+ event: "run_completed",
4135
+ timestamp: endTime2,
4136
+ runId,
4137
+ status: "error",
4138
+ endTime: endTime2,
4139
+ durationMs: durationMs3,
4140
+ error: formatted
4141
+ };
4142
+ await writeTraceEvent(
4143
+ prepareTraceEventForDisk(completed, traceSafety),
4144
+ traceDir
4145
+ );
4146
+ });
4147
+ await safeInstrumentation("printRunComplete(error)", () => {
4148
+ printRunComplete(runName, runId, durationMs3, "error", printPath2);
4149
+ });
4150
+ throw userError;
4151
+ }
4152
+ const endTime = Date.now();
4153
+ const durationMs2 = endTime - startTime;
4154
+ const printPath = traceFilePath ?? getTraceFilePath(runId, traceDir);
4155
+ await safeInstrumentation("writeTraceEvent(run_completed success)", async () => {
4156
+ const completed = {
4157
+ schemaVersion: "0.1",
4158
+ event: "run_completed",
4159
+ timestamp: endTime,
4160
+ runId,
4161
+ status: "success",
4162
+ endTime,
4163
+ durationMs: durationMs2
4164
+ };
4165
+ await writeTraceEvent(
4166
+ prepareTraceEventForDisk(completed, traceSafety),
4167
+ traceDir
4168
+ );
4169
+ });
4170
+ await safeInstrumentation("printRunComplete(success)", () => {
4171
+ printRunComplete(runName, runId, durationMs2, "success", printPath);
4172
+ });
4173
+ return result;
4174
+ }, traceSafety);
4175
+ }
4176
+
4177
+ // packages/core/src/maybe-inspect-run.ts
4178
+ var ENABLED_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on", "enabled"]);
4179
+ function isAgentInspectEnabled(value) {
4180
+ if (value === void 0) return false;
4181
+ const normalized = value.trim().toLowerCase();
4182
+ if (normalized === "") return false;
4183
+ return ENABLED_ENV_VALUES.has(normalized);
4184
+ }
4185
+ async function maybeInspectRun(name, fn, options) {
4186
+ if (typeof fn !== "function") {
4187
+ throw new TypeError("maybeInspectRun requires `fn` to be a function");
4188
+ }
4189
+ const enabled = options?.enabled !== void 0 ? options.enabled : isAgentInspectEnabled(process.env.AGENT_INSPECT);
4190
+ if (!enabled) {
4191
+ return Promise.resolve(fn());
4192
+ }
4193
+ return inspectRun(name, fn, options);
4194
+ }
2206
4195
 
2207
4196
  exports.DEFAULT_MAX_EVENT_BYTES = DEFAULT_MAX_EVENT_BYTES;
2208
4197
  exports.DEFAULT_MAX_METADATA_VALUE_LENGTH = DEFAULT_MAX_METADATA_VALUE_LENGTH;
@@ -2214,11 +4203,19 @@ exports.MAX_TERMINAL_DEPTH = MAX_TERMINAL_DEPTH;
2214
4203
  exports.MAX_TERMINAL_NAME_LENGTH = MAX_TERMINAL_NAME_LENGTH;
2215
4204
  exports.RUNS_DIR_NAME = RUNS_DIR_NAME;
2216
4205
  exports.TERMINAL_INDENT = TERMINAL_INDENT;
4206
+ exports.TraceDirectory = TraceDirectory;
4207
+ exports.buildLocalExplanation = buildLocalExplanation;
4208
+ exports.buildRunSummary = buildRunSummary;
4209
+ exports.buildRunTimeline = buildRunTimeline;
4210
+ exports.buildRunWhatSummary = buildRunWhatSummary;
4211
+ exports.buildTraceStats = buildTraceStats;
2217
4212
  exports.createInspector = createInspector;
2218
4213
  exports.createInspectorRuntime = createInspectorRuntime;
2219
4214
  exports.createRunId = createRunId;
2220
4215
  exports.createStepId = createStepId;
2221
4216
  exports.ensureTraceDir = ensureTraceDir;
4217
+ exports.extractMetadata = extractMetadata;
4218
+ exports.filterTraces = filterTraces;
2222
4219
  exports.formatDuration = formatDuration2;
2223
4220
  exports.formatError = formatError;
2224
4221
  exports.formatTerminalName = formatTerminalName;
@@ -2232,11 +4229,24 @@ exports.getCurrentStepId = getCurrentStepId;
2232
4229
  exports.getDefaultTraceDir = getDefaultTraceDir;
2233
4230
  exports.getIndent = getIndent;
2234
4231
  exports.getParentStepId = getParentStepId;
4232
+ exports.getRunIdFromTraceFileName = getRunIdFromTraceFileName;
2235
4233
  exports.getTraceDirFromContext = getTraceDirFromContext;
2236
4234
  exports.getTraceFilePath = getTraceFilePath;
2237
4235
  exports.getTraceSafetyFromContext = getTraceSafetyFromContext;
2238
4236
  exports.hasActiveContext = hasActiveContext;
4237
+ exports.initializeTraceFile = initializeTraceFile;
4238
+ exports.isAgentInspectEnabled = isAgentInspectEnabled;
4239
+ exports.isAgentInspectTrace = isAgentInspectTrace;
2239
4240
  exports.isSilentContext = isSilentContext;
4241
+ exports.isStepStatus = isStepStatus;
4242
+ exports.isStepType = isStepType;
4243
+ exports.isTraceEvent = isTraceEvent;
4244
+ exports.listTraceFiles = listTraceFiles;
4245
+ exports.loadTraceMetadataList = loadTraceMetadataList;
4246
+ exports.maybeInspectRun = maybeInspectRun;
4247
+ exports.parseDuration = parseDuration;
4248
+ exports.parseDurationFilter = parseDurationFilter;
4249
+ exports.parseTraceJsonl = parseTraceJsonl;
2240
4250
  exports.prepareMetadataForDisk = prepareMetadataForDisk;
2241
4251
  exports.prepareTraceEventForDisk = prepareTraceEventForDisk;
2242
4252
  exports.printError = printError;
@@ -2245,14 +4255,25 @@ exports.printRunComplete = printRunComplete;
2245
4255
  exports.printRunStart = printRunStart;
2246
4256
  exports.printStepComplete = printStepComplete;
2247
4257
  exports.printStepStart = printStepStart;
4258
+ exports.readTraceEvents = readTraceEvents;
4259
+ exports.readTraceFile = readTraceFile;
2248
4260
  exports.renderErrorLine = renderErrorLine;
2249
4261
  exports.renderRunSummary = renderRunSummary;
4262
+ exports.renderRunWhat = renderRunWhat;
2250
4263
  exports.renderStepLine = renderStepLine;
4264
+ exports.renderTimeline = renderTimeline;
4265
+ exports.renderTraceStats = renderTraceStats;
2251
4266
  exports.resolveRedactionProfile = resolveRedactionProfile;
4267
+ exports.resolveTraceDir = resolveTraceDir;
2252
4268
  exports.resolveTraceSafetyOptions = resolveTraceSafetyOptions;
2253
4269
  exports.runWithContext = runWithContext;
2254
4270
  exports.runWithStepContext = runWithStepContext;
4271
+ exports.searchTraces = searchTraces;
4272
+ exports.serializeEvent = serializeEvent;
2255
4273
  exports.truncateName = truncateName;
4274
+ exports.unknownTraceFormatMessage = unknownTraceFormatMessage;
4275
+ exports.validateEvent = validateEvent;
2256
4276
  exports.warn = warn;
4277
+ exports.writeTraceEvent = writeTraceEvent;
2257
4278
  //# sourceMappingURL=advanced.cjs.map
2258
4279
  //# sourceMappingURL=advanced.cjs.map