agent-inspect 6.18.0 → 6.19.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 (32) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/docs/API.md +2 -1
  4. package/package.json +1 -1
  5. package/packages/cli/dist/{chunk-S4TLTLXN.mjs → chunk-R7Y5SGH5.mjs} +348 -27
  6. package/packages/cli/dist/chunk-R7Y5SGH5.mjs.map +1 -0
  7. package/packages/cli/dist/index.cjs +375 -46
  8. package/packages/cli/dist/index.cjs.map +1 -1
  9. package/packages/cli/dist/index.mjs +6 -5
  10. package/packages/cli/dist/index.mjs.map +1 -1
  11. package/packages/cli/dist/{src-R6V5EZZH.mjs → src-T4EZERCX.mjs} +3 -3
  12. package/packages/cli/dist/{src-R6V5EZZH.mjs.map → src-T4EZERCX.mjs.map} +1 -1
  13. package/packages/core/dist/advanced.cjs.map +1 -1
  14. package/packages/core/dist/advanced.d.cts +13 -2
  15. package/packages/core/dist/advanced.d.ts +13 -2
  16. package/packages/core/dist/advanced.mjs +1 -1
  17. package/packages/core/dist/advanced.mjs.map +1 -1
  18. package/packages/core/dist/checks.cjs +334 -5
  19. package/packages/core/dist/checks.cjs.map +1 -1
  20. package/packages/core/dist/checks.d.cts +81 -4
  21. package/packages/core/dist/checks.d.ts +81 -4
  22. package/packages/core/dist/checks.mjs +1 -1
  23. package/packages/core/dist/{chunk-LQC7IED3.mjs → chunk-NABMW5DX.mjs} +336 -8
  24. package/packages/core/dist/chunk-NABMW5DX.mjs.map +1 -0
  25. package/packages/core/dist/{index-B9ZGvUVL.d.ts → index-AMAGuO_i.d.ts} +1 -1
  26. package/packages/core/dist/{index-DWu54Y28.d.cts → index-DCR816Yt.d.cts} +2 -2
  27. package/packages/core/dist/{index-DlwbVqEs.d.ts → index-DKwuGSe-.d.ts} +2 -2
  28. package/packages/core/dist/{index-B259NKkH.d.cts → index-vqr-g6ev.d.cts} +1 -1
  29. package/packages/core/dist/readers.d.cts +1 -1
  30. package/packages/core/dist/readers.d.ts +1 -1
  31. package/packages/cli/dist/chunk-S4TLTLXN.mjs.map +0 -1
  32. package/packages/core/dist/chunk-LQC7IED3.mjs.map +0 -1
@@ -488,6 +488,325 @@ function pickString(record, keys) {
488
488
  return void 0;
489
489
  }
490
490
 
491
+ // packages/core/src/checks/derived-failure.ts
492
+ function isRecord2(value) {
493
+ return typeof value === "object" && value !== null && !Array.isArray(value);
494
+ }
495
+ function pickString2(record, keys) {
496
+ if (!record) return void 0;
497
+ for (const key of keys) {
498
+ const value = record[key];
499
+ if (typeof value === "string" && value.trim() !== "") return value;
500
+ }
501
+ return void 0;
502
+ }
503
+ function pickNumber(record, keys) {
504
+ if (!record) return void 0;
505
+ for (const key of keys) {
506
+ const value = record[key];
507
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
508
+ return value;
509
+ }
510
+ }
511
+ return void 0;
512
+ }
513
+ function eventMetadata(event) {
514
+ const attrs = isRecord2(event.attributes) ? event.attributes : void 0;
515
+ const nested = attrs !== void 0 && isRecord2(attrs.metadata) ? attrs.metadata : void 0;
516
+ return {
517
+ ...attrs ?? {},
518
+ ...nested ?? {}
519
+ };
520
+ }
521
+ function canonicalName(event) {
522
+ if (event.kind === "TOOL") return resolveCanonicalToolName(event);
523
+ return event.name;
524
+ }
525
+ function linkKeys(event) {
526
+ const meta = eventMetadata(event);
527
+ const keys = [];
528
+ for (const key of ["linkedStepId", "toolCallId", "mcpToolCallId"]) {
529
+ const value = pickString2(meta, [key]);
530
+ if (value !== void 0) keys.push(`${key}:${value}`);
531
+ }
532
+ const stepId = pickString2(meta, ["stepId"]);
533
+ if (stepId !== void 0) keys.push(`stepId:${stepId}`);
534
+ return keys;
535
+ }
536
+ function buildRunContexts(logicalEvents) {
537
+ const byRun = /* @__PURE__ */ new Map();
538
+ for (const event of logicalEvents) {
539
+ const existing = byRun.get(event.runId) ?? {
540
+ runId: event.runId,
541
+ name: event.name
542
+ };
543
+ const meta = eventMetadata(event);
544
+ if (event.kind === "RUN" || existing.name === event.runId) {
545
+ existing.name = event.name || existing.name;
546
+ }
547
+ if (event.kind === "RUN" && event.status !== void 0 && event.status !== "running") {
548
+ existing.status = event.status;
549
+ }
550
+ existing.retryOf ??= pickString2(meta, ["retryOf"]);
551
+ existing.attempt ??= pickNumber(meta, ["attempt", "retryAttempt", "retryCount"]);
552
+ existing.sessionId ??= pickString2(meta, ["sessionId", "conversationId"]);
553
+ existing.groupId ??= pickString2(meta, ["groupId"]);
554
+ existing.parentGroupId ??= pickString2(meta, ["parentGroupId"]);
555
+ existing.fallbackOf ??= pickString2(meta, ["fallbackOf", "fallbackFrom"]);
556
+ byRun.set(event.runId, existing);
557
+ }
558
+ return byRun;
559
+ }
560
+ function sameCorrelationScope(a, b) {
561
+ if (a.sessionId && b.sessionId && a.sessionId === b.sessionId) return true;
562
+ if (a.groupId && b.groupId && a.groupId === b.groupId) return true;
563
+ if (a.parentGroupId && b.parentGroupId && a.parentGroupId === b.parentGroupId) {
564
+ return true;
565
+ }
566
+ return false;
567
+ }
568
+ function isSuccessful(event) {
569
+ return event.status === "ok";
570
+ }
571
+ function isFailure(event) {
572
+ return event.status === "error";
573
+ }
574
+ function compareEventOrder(a, b) {
575
+ const byTime = a.timestamp.localeCompare(b.timestamp);
576
+ if (byTime !== 0) return byTime;
577
+ return a.eventId.localeCompare(b.eventId);
578
+ }
579
+ function collectCandidates(failure, logicalEvents, runs) {
580
+ const failureRun = runs.get(failure.runId);
581
+ const failureLinks = new Set(linkKeys(failure));
582
+ const failureName = canonicalName(failure);
583
+ const failureAttempt = pickNumber(eventMetadata(failure), ["attempt", "retryAttempt", "retryCount"]) ?? failureRun?.attempt;
584
+ const candidates = [];
585
+ for (const event of logicalEvents) {
586
+ if (event.eventId === failure.eventId) continue;
587
+ if (event.status === "running") continue;
588
+ const eventRun = runs.get(event.runId);
589
+ const eventMeta = eventMetadata(event);
590
+ const sameRun = event.runId === failure.runId;
591
+ if (eventRun?.retryOf === failure.runId) {
592
+ candidates.push({
593
+ event,
594
+ basis: "retryOf",
595
+ confidence: "explicit",
596
+ viaRunId: event.runId
597
+ });
598
+ continue;
599
+ }
600
+ if (eventRun?.fallbackOf === failure.runId || pickString2(eventMeta, ["fallbackOf", "fallbackFrom"]) === failure.runId) {
601
+ candidates.push({
602
+ event,
603
+ basis: "fallbackOf",
604
+ confidence: "explicit",
605
+ viaRunId: event.runId
606
+ });
607
+ continue;
608
+ }
609
+ if (sameRun && compareEventOrder(failure, event) >= 0) continue;
610
+ const eventLinks = linkKeys(event);
611
+ const sharedLink = eventLinks.find((key) => failureLinks.has(key));
612
+ if (sharedLink !== void 0) {
613
+ candidates.push({
614
+ event,
615
+ basis: sharedLink.split(":")[0] ?? "linkedId",
616
+ confidence: "explicit"
617
+ });
618
+ continue;
619
+ }
620
+ const eventAttempt = pickNumber(eventMeta, ["attempt", "retryAttempt", "retryCount"]) ?? eventRun?.attempt;
621
+ const sameParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId === event.parentId;
622
+ const differentParent = failure.parentId !== void 0 && event.parentId !== void 0 && failure.parentId !== event.parentId;
623
+ const sessionScoped = failureRun !== void 0 && eventRun !== void 0 && sameCorrelationScope(failureRun, eventRun);
624
+ if (canonicalName(event) === failureName && failureAttempt !== void 0 && eventAttempt !== void 0 && eventAttempt > failureAttempt && !differentParent && (sameParent || sessionScoped || sameRun)) {
625
+ candidates.push({
626
+ event,
627
+ basis: "attempt-progression",
628
+ confidence: "correlated",
629
+ ...event.runId !== failure.runId ? { viaRunId: event.runId } : {}
630
+ });
631
+ }
632
+ }
633
+ const byId = /* @__PURE__ */ new Map();
634
+ for (const candidate of candidates) {
635
+ const prev = byId.get(candidate.event.eventId);
636
+ if (!prev || prev.confidence !== "explicit" && candidate.confidence === "explicit") {
637
+ byId.set(candidate.event.eventId, candidate);
638
+ }
639
+ }
640
+ return [...byId.values()].sort((a, b) => compareEventOrder(a.event, b.event));
641
+ }
642
+ function classifyFailure(failure, candidates, runs, logicalEvents) {
643
+ const successful = candidates.filter((c) => isSuccessful(c.event));
644
+ const unsuccessful = candidates.filter((c) => !isSuccessful(c.event));
645
+ const retryRunIds = Object.freeze(
646
+ [...new Set(candidates.map((c) => c.viaRunId).filter((id) => id !== void 0))].sort(
647
+ (a, b) => a.localeCompare(b)
648
+ )
649
+ );
650
+ if (successful.length > 1) {
651
+ const distinctRuns = new Set(successful.map((c) => c.event.runId));
652
+ const distinctParents = new Set(
653
+ successful.map((c) => c.event.parentId ?? "").filter((id) => id !== "")
654
+ );
655
+ if (distinctRuns.size > 1 || distinctParents.size > 1) {
656
+ return {
657
+ eventId: failure.eventId,
658
+ runId: failure.runId,
659
+ name: failure.name,
660
+ kind: failure.kind,
661
+ role: "unknown",
662
+ confidence: "unknown",
663
+ basis: Object.freeze(["ambiguous-recovery-candidates"]),
664
+ recoveryEventIds: Object.freeze(
665
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
666
+ ),
667
+ retryRunIds
668
+ };
669
+ }
670
+ }
671
+ if (successful.length >= 1) {
672
+ const best = successful[0];
673
+ return {
674
+ eventId: failure.eventId,
675
+ runId: failure.runId,
676
+ name: failure.name,
677
+ kind: failure.kind,
678
+ role: "recovered",
679
+ confidence: best.confidence,
680
+ basis: Object.freeze([best.basis]),
681
+ recoveryEventIds: Object.freeze(
682
+ successful.map((c) => c.event.eventId).sort((a, b) => a.localeCompare(b))
683
+ ),
684
+ retryRunIds
685
+ };
686
+ }
687
+ if (candidates.length > 0) {
688
+ const best = candidates[0];
689
+ return {
690
+ eventId: failure.eventId,
691
+ runId: failure.runId,
692
+ name: failure.name,
693
+ kind: failure.kind,
694
+ role: "transient",
695
+ confidence: best.confidence,
696
+ basis: Object.freeze([
697
+ best.basis,
698
+ unsuccessful.some((c) => c.event.status === void 0) ? "retry-incomplete" : "retry-without-success"
699
+ ]),
700
+ recoveryEventIds: Object.freeze([]),
701
+ retryRunIds
702
+ };
703
+ }
704
+ const failureMeta = eventMetadata(failure);
705
+ const declaredSuccessor = pickString2(failureMeta, [
706
+ "retriedBy",
707
+ "nextRetryRunId",
708
+ "retryRunId"
709
+ ]);
710
+ if (declaredSuccessor !== void 0 && !runs.has(declaredSuccessor)) {
711
+ return {
712
+ eventId: failure.eventId,
713
+ runId: failure.runId,
714
+ name: failure.name,
715
+ kind: failure.kind,
716
+ role: "transient",
717
+ confidence: "explicit",
718
+ basis: Object.freeze(["retry-declared", "retry-run-missing"]),
719
+ recoveryEventIds: Object.freeze([]),
720
+ retryRunIds: Object.freeze([declaredSuccessor])
721
+ };
722
+ }
723
+ for (const run of runs.values()) {
724
+ if (run.retryOf === failure.runId) {
725
+ return {
726
+ eventId: failure.eventId,
727
+ runId: failure.runId,
728
+ name: failure.name,
729
+ kind: failure.kind,
730
+ role: "transient",
731
+ confidence: "explicit",
732
+ basis: Object.freeze(["retryOf", "retry-run-missing-or-empty"]),
733
+ recoveryEventIds: Object.freeze([]),
734
+ retryRunIds: Object.freeze([run.runId])
735
+ };
736
+ }
737
+ }
738
+ const failureRun = runs.get(failure.runId);
739
+ const hasSuccessorDeclared = [...runs.values()].some((run) => run.retryOf === failure.runId);
740
+ const isFinalInChain = failureRun !== void 0 && !hasSuccessorDeclared && (failureRun.retryOf !== void 0 || failureRun.attempt !== void 0 && failureRun.attempt > 1 || pickNumber(eventMetadata(failure), ["attempt"]) !== void 0);
741
+ if (isFinalInChain && failureRun?.status === "error" && !logicalEvents.some(
742
+ (event) => event.runId === failure.runId && event.eventId !== failure.eventId && isSuccessful(event) && canonicalName(event) === canonicalName(failure)
743
+ )) {
744
+ return {
745
+ eventId: failure.eventId,
746
+ runId: failure.runId,
747
+ name: failure.name,
748
+ kind: failure.kind,
749
+ role: "terminal",
750
+ confidence: failureRun.retryOf !== void 0 ? "explicit" : "correlated",
751
+ basis: Object.freeze(["final-retry-chain-member", "enclosing-run-error"]),
752
+ recoveryEventIds: Object.freeze([]),
753
+ retryRunIds: Object.freeze(
754
+ failureRun.retryOf !== void 0 ? [failureRun.retryOf] : []
755
+ )
756
+ };
757
+ }
758
+ return {
759
+ eventId: failure.eventId,
760
+ runId: failure.runId,
761
+ name: failure.name,
762
+ kind: failure.kind,
763
+ role: "unknown",
764
+ confidence: "unknown",
765
+ basis: Object.freeze(["no-explicit-or-correlated-recovery"]),
766
+ recoveryEventIds: Object.freeze([]),
767
+ retryRunIds: Object.freeze([])
768
+ };
769
+ }
770
+ function deriveFailureFacts(logicalEvents) {
771
+ const runs = buildRunContexts(logicalEvents);
772
+ const failures = logicalEvents.filter((event) => isFailure(event)).sort(compareEventOrder);
773
+ const failureFacts = failures.map(
774
+ (failure) => classifyFailure(failure, collectCandidates(failure, logicalEvents, runs), runs, logicalEvents)
775
+ );
776
+ const byRole = /* @__PURE__ */ new Map([
777
+ ["transient", []],
778
+ ["recovered", []],
779
+ ["terminal", []],
780
+ ["unknown", []]
781
+ ]);
782
+ for (const fact of failureFacts) {
783
+ byRole.get(fact.role).push(fact);
784
+ }
785
+ for (const [role, list] of byRole) {
786
+ byRole.set(
787
+ role,
788
+ Object.freeze(
789
+ [...list].sort((a, b) => {
790
+ const byRun = a.runId.localeCompare(b.runId);
791
+ if (byRun !== 0) return byRun;
792
+ return a.eventId.localeCompare(b.eventId);
793
+ })
794
+ )
795
+ );
796
+ }
797
+ const failureRoleCounts = {
798
+ transient: byRole.get("transient").length,
799
+ recovered: byRole.get("recovered").length,
800
+ terminal: byRole.get("terminal").length,
801
+ unknown: byRole.get("unknown").length
802
+ };
803
+ return {
804
+ failureFacts: Object.freeze(failureFacts),
805
+ failuresByRole: byRole,
806
+ failureRoleCounts
807
+ };
808
+ }
809
+
491
810
  // packages/core/src/checks/trace-facts.ts
492
811
  function summarizeSemanticParity(events) {
493
812
  const projection = projectLogicalEvents(events);
@@ -498,6 +817,7 @@ function summarizeSemanticParity(events) {
498
817
  const finishedToolNames = Object.freeze(
499
818
  finishedTools.map((event) => resolveCanonicalToolName(event)).sort((a, b) => a.localeCompare(b))
500
819
  );
820
+ const derived = deriveFailureFacts(logical);
501
821
  return {
502
822
  rawEventCount: events.length,
503
823
  logicalEventCount: logical.length,
@@ -508,7 +828,8 @@ function summarizeSemanticParity(events) {
508
828
  parentRemapCount: projection.diagnostics.filter(
509
829
  (item) => item.code === "AI_LOGICAL_PARENT_REMAPPED"
510
830
  ).length,
511
- diagnostics: projection.diagnostics
831
+ diagnostics: projection.diagnostics,
832
+ failureRoleCounts: derived.failureRoleCounts
512
833
  };
513
834
  }
514
835
  var TRACE_FACTS_INPUT_NOT_NORMALIZED = formatProgrammaticDiagnostic(
@@ -571,6 +892,8 @@ function buildTraceFacts(input) {
571
892
  for (const [name, list] of [...toolsByName.entries()]) {
572
893
  toolsByName.set(name, Object.freeze([...list]));
573
894
  }
895
+ const derived = deriveFailureFacts(projection.logicalEvents);
896
+ const summary = summarizeSemanticParity(events);
574
897
  return {
575
898
  rawEvents: Object.freeze([...events]),
576
899
  logicalEvents: projection.logicalEvents,
@@ -578,7 +901,12 @@ function buildTraceFacts(input) {
578
901
  toolsByName,
579
902
  llmEvents: Object.freeze(llmEvents),
580
903
  outcomeEvents: Object.freeze(outcomeEvents),
581
- summary: summarizeSemanticParity(events)
904
+ summary: {
905
+ ...summary,
906
+ failureRoleCounts: derived.failureRoleCounts
907
+ },
908
+ failureFacts: derived.failureFacts,
909
+ failuresByRole: derived.failuresByRole
582
910
  };
583
911
  }
584
912
 
@@ -1168,7 +1496,7 @@ function firstIndexByName(events) {
1168
1496
  }
1169
1497
  return index;
1170
1498
  }
1171
- function isRecord2(value) {
1499
+ function isRecord3(value) {
1172
1500
  return typeof value === "object" && value !== null && !Array.isArray(value);
1173
1501
  }
1174
1502
  function eventMap(events) {
@@ -1222,7 +1550,7 @@ function pushValueEntries(entries, event, value, path3, key, depth = 0) {
1222
1550
  }
1223
1551
  return;
1224
1552
  }
1225
- if (!isRecord2(value)) return;
1553
+ if (!isRecord3(value)) return;
1226
1554
  for (const nestedKey of Object.keys(value).sort((a, b) => a.localeCompare(b))) {
1227
1555
  pushValueEntries(
1228
1556
  entries,
@@ -2317,7 +2645,7 @@ function createSafetyOversizedAttributeRule(options) {
2317
2645
  )
2318
2646
  );
2319
2647
  }
2320
- if (isRecord2(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
2648
+ if (isRecord3(entry.value) && options.maxObjectKeys !== void 0 && Object.keys(entry.value).length > options.maxObjectKeys) {
2321
2649
  findings.push(
2322
2650
  failFinding(
2323
2651
  "safety.oversizedAttribute",
@@ -2636,6 +2964,7 @@ exports.createToolFailureRule = createToolFailureRule;
2636
2964
  exports.createToolOrderingRule = createToolOrderingRule;
2637
2965
  exports.createToolUsageRule = createToolUsageRule;
2638
2966
  exports.defineTraceContract = defineTraceContract;
2967
+ exports.deriveFailureFacts = deriveFailureFacts;
2639
2968
  exports.evaluateTraceContract = evaluateTraceContract;
2640
2969
  exports.evaluateTraceContractRead = evaluateTraceContractRead;
2641
2970
  exports.formatProgrammaticDiagnostic = formatProgrammaticDiagnostic;