agent-inspect 2.2.0 → 2.4.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 (43) hide show
  1. package/CHANGELOG.md +31 -4
  2. package/README.md +47 -4
  3. package/docs/ADAPTER-CONFORMANCE.md +25 -5
  4. package/docs/ADAPTERS.md +102 -11
  5. package/docs/CLI.md +54 -1
  6. package/docs/SCHEMA.md +1 -0
  7. package/package.json +2 -2
  8. package/packages/cli/dist/index.cjs +757 -14
  9. package/packages/cli/dist/index.cjs.map +1 -1
  10. package/packages/cli/dist/index.mjs +757 -14
  11. package/packages/cli/dist/index.mjs.map +1 -1
  12. package/packages/core/dist/advanced.cjs +581 -3
  13. package/packages/core/dist/advanced.cjs.map +1 -1
  14. package/packages/core/dist/advanced.d.cts +172 -8
  15. package/packages/core/dist/advanced.d.ts +172 -8
  16. package/packages/core/dist/advanced.mjs +572 -4
  17. package/packages/core/dist/advanced.mjs.map +1 -1
  18. package/packages/core/dist/checks.d.cts +2 -2
  19. package/packages/core/dist/checks.d.ts +2 -2
  20. package/packages/core/dist/{context-yv2VSDQF.d.ts → context-BDZmi53V.d.ts} +3 -3
  21. package/packages/core/dist/{context-CSKnzpXR.d.cts → context-DjY-jvQk.d.cts} +3 -3
  22. package/packages/core/dist/diff.d.cts +3 -3
  23. package/packages/core/dist/diff.d.ts +3 -3
  24. package/packages/core/dist/exporters.d.cts +3 -3
  25. package/packages/core/dist/exporters.d.ts +3 -3
  26. package/packages/core/dist/index.d.cts +6 -6
  27. package/packages/core/dist/index.d.ts +6 -6
  28. package/packages/core/dist/{inspect-event-CevRYp58.d.cts → inspect-event-CYAV7Hxm.d.cts} +1 -1
  29. package/packages/core/dist/{inspect-event-CevRYp58.d.ts → inspect-event-CYAV7Hxm.d.ts} +1 -1
  30. package/packages/core/dist/{log-config-8aE5Kxtr.d.cts → log-config-BNQ9UTmP.d.cts} +1 -1
  31. package/packages/core/dist/{log-config-DVimQJho.d.ts → log-config-D3Yp1SZN.d.ts} +1 -1
  32. package/packages/core/dist/logs.d.cts +3 -3
  33. package/packages/core/dist/logs.d.ts +3 -3
  34. package/packages/core/dist/{persisted-inspect-event-D-WpXeZX.d.ts → persisted-inspect-event-BLvb0jSX.d.ts} +1 -1
  35. package/packages/core/dist/{persisted-inspect-event-DHcHPUKv.d.cts → persisted-inspect-event-D5SjBz9b.d.cts} +1 -1
  36. package/packages/core/dist/persisted.d.cts +5 -5
  37. package/packages/core/dist/persisted.d.ts +5 -5
  38. package/packages/core/dist/readers.d.cts +2 -2
  39. package/packages/core/dist/readers.d.ts +2 -2
  40. package/packages/core/dist/{types-DgMN3qow.d.cts → types-C-llnPH0.d.cts} +1 -1
  41. package/packages/core/dist/{types-D-Y1kOU-.d.ts → types-CQun9LW6.d.ts} +1 -1
  42. package/packages/core/dist/writers.d.cts +2 -2
  43. package/packages/core/dist/writers.d.ts +2 -2
@@ -432,10 +432,12 @@ async function searchTraces(metas, options) {
432
432
  durationFilter = parseDurationFilter(options.duration);
433
433
  }
434
434
  const limit = options.limit ?? 50;
435
+ const sessionId = options.session?.trim();
435
436
  const hasContentFilter = Boolean(
436
437
  options.status || stepTypeFilter || nameQuery || toolQuery || durationFilter
437
438
  );
438
439
  const results = [];
440
+ const sessionLabel = sessionId && sessionId !== "" ? sessionId : void 0;
439
441
  if (!hasContentFilter) {
440
442
  for (const m of filtered) {
441
443
  results.push({
@@ -444,9 +446,10 @@ async function searchTraces(metas, options) {
444
446
  runStatus: m.status,
445
447
  timestamp: m.startedAt,
446
448
  durationMs: m.durationMs,
447
- matchReason: "trace in directory",
448
- matchedFields: ["run"],
449
- filePath: m.filePath
449
+ matchReason: sessionLabel ? `trace in session ${sessionLabel}` : "trace in directory",
450
+ matchedFields: sessionLabel ? ["run", "session"] : ["run"],
451
+ filePath: m.filePath,
452
+ ...sessionLabel ? { sessionId: sessionLabel } : {}
450
453
  });
451
454
  }
452
455
  return results.slice(0, limit);
@@ -585,6 +588,571 @@ async function loadTraceMetadataList(_traceDir, fileNames, getPath) {
585
588
  }
586
589
  return metas;
587
590
  }
591
+
592
+ // packages/core/src/sessions/metadata.ts
593
+ function isNonEmptyString(value) {
594
+ return typeof value === "string" && value.trim() !== "";
595
+ }
596
+ function finitePositiveInt(value) {
597
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 1) {
598
+ return void 0;
599
+ }
600
+ return Math.trunc(value);
601
+ }
602
+ function extractSessionWorkflowMetadata(record) {
603
+ if (!record) return void 0;
604
+ const out = {};
605
+ let found = false;
606
+ const assignString = (key, value) => {
607
+ if (isNonEmptyString(value)) {
608
+ out[key] = value.trim();
609
+ found = true;
610
+ }
611
+ };
612
+ assignString("sessionId", record.sessionId);
613
+ assignString("conversationId", record.conversationId);
614
+ assignString("groupId", record.groupId);
615
+ assignString("parentGroupId", record.parentGroupId);
616
+ assignString("retryOf", record.retryOf);
617
+ assignString("retryReason", record.retryReason);
618
+ assignString("handoffFrom", record.handoffFrom);
619
+ assignString("handoffTo", record.handoffTo);
620
+ assignString("subAgentId", record.subAgentId);
621
+ assignString("subAgentName", record.subAgentName);
622
+ assignString("jobId", record.jobId);
623
+ assignString("queueName", record.queueName);
624
+ assignString("workflowName", record.workflowName);
625
+ assignString("workflowStep", record.workflowStep);
626
+ assignString("toolCallId", record.toolCallId);
627
+ assignString("mcpToolCallId", record.mcpToolCallId);
628
+ assignString("linkedStepId", record.linkedStepId);
629
+ assignString("correlationId", record.correlationId);
630
+ assignString("requestId", record.requestId);
631
+ assignString("decisionId", record.decisionId);
632
+ const attempt = finitePositiveInt(record.attempt);
633
+ if (attempt !== void 0) {
634
+ out.attempt = attempt;
635
+ found = true;
636
+ }
637
+ return found ? out : void 0;
638
+ }
639
+ function sessionKeyForRun(meta, options) {
640
+ if (meta?.sessionId) return meta.sessionId;
641
+ if (options?.correlateByGroupId && meta?.groupId) {
642
+ return `group:${meta.groupId}`;
643
+ }
644
+ return void 0;
645
+ }
646
+
647
+ // packages/core/src/sessions/types.ts
648
+ var SESSION_WORKFLOW_KEYS = [
649
+ "sessionId",
650
+ "conversationId",
651
+ "groupId",
652
+ "parentGroupId",
653
+ "attempt",
654
+ "retryOf",
655
+ "retryReason",
656
+ "handoffFrom",
657
+ "handoffTo",
658
+ "subAgentId",
659
+ "subAgentName",
660
+ "jobId",
661
+ "queueName",
662
+ "workflowName",
663
+ "workflowStep",
664
+ "toolCallId",
665
+ "mcpToolCallId",
666
+ "linkedStepId",
667
+ "correlationId",
668
+ "requestId",
669
+ "decisionId"
670
+ ];
671
+
672
+ // packages/core/src/sessions/load.ts
673
+ async function enrichSessionRunRecord(meta) {
674
+ let metadata;
675
+ try {
676
+ const events = await readTraceEventsFromFile(meta.filePath);
677
+ for (const event of events) {
678
+ if (event.event !== "run_started") continue;
679
+ if (event.metadata && typeof event.metadata === "object") {
680
+ metadata = event.metadata;
681
+ }
682
+ break;
683
+ }
684
+ } catch {
685
+ }
686
+ return {
687
+ runId: meta.runId,
688
+ name: meta.name,
689
+ status: meta.status,
690
+ startedAt: meta.startedAt,
691
+ endedAt: meta.endedAt,
692
+ durationMs: meta.durationMs,
693
+ filePath: meta.filePath,
694
+ metadata
695
+ };
696
+ }
697
+ async function loadSessionRunRecords(metas) {
698
+ const out = [];
699
+ for (const meta of metas) {
700
+ out.push(await enrichSessionRunRecord(meta));
701
+ }
702
+ return out;
703
+ }
704
+
705
+ // packages/core/src/sessions/scope.ts
706
+ function metaToSessionRunRecord(meta) {
707
+ return {
708
+ runId: meta.runId,
709
+ name: meta.name,
710
+ status: meta.status,
711
+ startedAt: meta.startedAt,
712
+ endedAt: meta.endedAt,
713
+ durationMs: meta.durationMs,
714
+ filePath: meta.filePath,
715
+ metadata: void 0
716
+ };
717
+ }
718
+ function filterMetasBySessionScope(metas, records, options) {
719
+ const sessionId = options.sessionId?.trim();
720
+ const groupId = options.groupId?.trim();
721
+ const warnings = [];
722
+ if (sessionId) {
723
+ const index = buildSessionIndex(records, {
724
+ correlateByGroupId: options.correlateByGroupId === true
725
+ });
726
+ warnings.push(...index.warnings);
727
+ const session = index.sessions.find((item) => item.sessionId === sessionId);
728
+ if (!session) {
729
+ return {
730
+ metas: [],
731
+ scopeLabel: sessionId,
732
+ scopeKind: "session",
733
+ runIds: [],
734
+ warnings,
735
+ notFound: true
736
+ };
737
+ }
738
+ const runIdSet = new Set(session.runIds);
739
+ const filtered = metas.filter((meta) => runIdSet.has(meta.runId));
740
+ return {
741
+ metas: filtered,
742
+ scopeLabel: sessionId,
743
+ scopeKind: "session",
744
+ runIds: session.runIds,
745
+ warnings,
746
+ notFound: false
747
+ };
748
+ }
749
+ if (groupId) {
750
+ const runIds = records.filter((run) => extractSessionWorkflowMetadata(run.metadata)?.groupId === groupId).map((run) => run.runId).sort();
751
+ if (runIds.length === 0) {
752
+ return {
753
+ metas: [],
754
+ scopeLabel: groupId,
755
+ scopeKind: "group",
756
+ runIds: [],
757
+ warnings,
758
+ notFound: true
759
+ };
760
+ }
761
+ const runIdSet = new Set(runIds);
762
+ return {
763
+ metas: metas.filter((meta) => runIdSet.has(meta.runId)),
764
+ scopeLabel: groupId,
765
+ scopeKind: "group",
766
+ runIds,
767
+ warnings,
768
+ notFound: false
769
+ };
770
+ }
771
+ return {
772
+ metas: [...metas],
773
+ scopeLabel: "",
774
+ scopeKind: "session",
775
+ runIds: [],
776
+ warnings,
777
+ notFound: false
778
+ };
779
+ }
780
+ function traceMetasToSessionRunRecords(metas) {
781
+ return metas.map(metaToSessionRunRecord);
782
+ }
783
+
784
+ // packages/core/src/sessions/cohort.ts
785
+ function groupSessionCohorts(runs, options = {}) {
786
+ const groupBy = options.groupBy ?? "session";
787
+ const cohorts = [];
788
+ if (groupBy === "session") {
789
+ const index = buildSessionIndex(runs, options);
790
+ for (const session of index.sessions) {
791
+ cohorts.push({
792
+ key: session.sessionId,
793
+ kind: "session",
794
+ runIds: [...session.runIds]
795
+ });
796
+ }
797
+ if (index.unscopedRunIds.length > 0) {
798
+ cohorts.push({
799
+ key: "__unscoped__",
800
+ kind: "session",
801
+ runIds: [...index.unscopedRunIds]
802
+ });
803
+ }
804
+ return cohorts.sort((a, b) => a.key.localeCompare(b.key));
805
+ }
806
+ const byGroup = /* @__PURE__ */ new Map();
807
+ const unscoped = [];
808
+ for (const run of runs) {
809
+ const groupId = extractSessionWorkflowMetadata(run.metadata)?.groupId;
810
+ if (!groupId) {
811
+ unscoped.push(run.runId);
812
+ continue;
813
+ }
814
+ const bucket = byGroup.get(groupId) ?? [];
815
+ bucket.push(run.runId);
816
+ byGroup.set(groupId, bucket);
817
+ }
818
+ for (const [key, runIds] of [...byGroup.entries()].sort(
819
+ ([a], [b]) => a.localeCompare(b)
820
+ )) {
821
+ cohorts.push({
822
+ key,
823
+ kind: "group",
824
+ runIds: runIds.sort()
825
+ });
826
+ }
827
+ if (unscoped.length > 0) {
828
+ cohorts.push({
829
+ key: "__unscoped__",
830
+ kind: "group",
831
+ runIds: unscoped.sort()
832
+ });
833
+ }
834
+ return cohorts;
835
+ }
836
+
837
+ // packages/core/src/sessions/checks.ts
838
+ function emptySummary() {
839
+ return { passed: 0, failed: 0, warnings: 0, errors: 0 };
840
+ }
841
+ function mergeSummary(target, source) {
842
+ return {
843
+ passed: target.passed + source.passed,
844
+ failed: target.failed + source.failed,
845
+ warnings: target.warnings + source.warnings,
846
+ errors: target.errors + source.errors
847
+ };
848
+ }
849
+ function sessionDiagnostic(code, message) {
850
+ return { code, message, severity: "error" };
851
+ }
852
+ function aggregateSessionCheckResults(perRun, scope) {
853
+ if (scope.notFound) {
854
+ return {
855
+ ok: false,
856
+ status: "error",
857
+ format: perRun[0]?.format ?? "agent-inspect-jsonl",
858
+ scopeKind: scope.scopeKind,
859
+ scopeLabel: scope.scopeLabel,
860
+ runIds: [],
861
+ runResults: [],
862
+ summary: { ...emptySummary(), errors: 1 },
863
+ findings: [],
864
+ diagnostics: [
865
+ sessionDiagnostic(
866
+ "AI_CHECK_INVALID_ARGUMENTS",
867
+ `${scope.scopeKind} not found: ${scope.scopeLabel}`
868
+ )
869
+ ],
870
+ ...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
871
+ };
872
+ }
873
+ if (scope.empty || perRun.length === 0) {
874
+ return {
875
+ ok: false,
876
+ status: "error",
877
+ format: perRun[0]?.format ?? "agent-inspect-jsonl",
878
+ scopeKind: scope.scopeKind,
879
+ scopeLabel: scope.scopeLabel,
880
+ runIds: scope.runIds,
881
+ runResults: [],
882
+ summary: { ...emptySummary(), errors: 1 },
883
+ findings: [],
884
+ diagnostics: [
885
+ sessionDiagnostic(
886
+ "AI_CHECK_TRACE_UNREADABLE",
887
+ `No readable traces in ${scope.scopeKind}: ${scope.scopeLabel}`
888
+ )
889
+ ],
890
+ ...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
891
+ };
892
+ }
893
+ let summary = emptySummary();
894
+ const findings = [];
895
+ const diagnostics = [];
896
+ const runResults = [];
897
+ for (const result of perRun) {
898
+ summary = mergeSummary(summary, result.summary);
899
+ findings.push(...result.findings);
900
+ diagnostics.push(...result.diagnostics);
901
+ if (result.runId) {
902
+ runResults.push({ runId: result.runId, status: result.status });
903
+ }
904
+ }
905
+ runResults.sort((a, b) => a.runId.localeCompare(b.runId));
906
+ findings.sort((a, b) => {
907
+ const runCmp = (a.evidence[0]?.runId ?? "").localeCompare(
908
+ b.evidence[0]?.runId ?? ""
909
+ );
910
+ if (runCmp !== 0) return runCmp;
911
+ return a.ruleId.localeCompare(b.ruleId);
912
+ });
913
+ const hasErrors = diagnostics.some((item) => item.severity === "error");
914
+ const status = hasErrors ? "error" : summary.failed > 0 ? "fail" : "pass";
915
+ return {
916
+ ok: status === "pass",
917
+ status,
918
+ format: perRun[0]?.format ?? "agent-inspect-jsonl",
919
+ scopeKind: scope.scopeKind,
920
+ scopeLabel: scope.scopeLabel,
921
+ runIds: scope.runIds,
922
+ runResults,
923
+ summary,
924
+ findings,
925
+ diagnostics,
926
+ ...scope.sessionWarnings?.length ? { sessionWarnings: [...scope.sessionWarnings] } : {}
927
+ };
928
+ }
929
+
930
+ // packages/core/src/sessions/index.ts
931
+ function compareRuns(a, b) {
932
+ const aStart = a.startedAt ?? 0;
933
+ const bStart = b.startedAt ?? 0;
934
+ if (aStart !== bStart) return aStart - bStart;
935
+ return a.runId.localeCompare(b.runId);
936
+ }
937
+ function buildGroups(runIds, metaByRunId) {
938
+ const byGroup = /* @__PURE__ */ new Map();
939
+ for (const runId of runIds) {
940
+ const groupId = metaByRunId.get(runId)?.groupId;
941
+ if (!groupId) continue;
942
+ const existing = byGroup.get(groupId);
943
+ if (existing) {
944
+ existing.runIds.push(runId);
945
+ } else {
946
+ byGroup.set(groupId, {
947
+ groupId,
948
+ parentGroupId: metaByRunId.get(runId)?.parentGroupId,
949
+ runIds: [runId]
950
+ });
951
+ }
952
+ }
953
+ return [...byGroup.values()].map((group) => ({
954
+ ...group,
955
+ runIds: [...group.runIds].sort((a, b) => a.localeCompare(b))
956
+ }));
957
+ }
958
+ function buildHandoffs(runIds, metaByRunId, warnings, sessionId) {
959
+ const edges = [];
960
+ const seen = /* @__PURE__ */ new Set();
961
+ const pushEdge = (edge) => {
962
+ const key = `${edge.from}->${edge.to}:${edge.confidence}`;
963
+ if (seen.has(key)) return;
964
+ seen.add(key);
965
+ edges.push(edge);
966
+ };
967
+ for (const runId of runIds) {
968
+ const meta = metaByRunId.get(runId);
969
+ if (!meta) continue;
970
+ if (meta.handoffFrom && meta.handoffTo) {
971
+ pushEdge({
972
+ from: meta.handoffFrom,
973
+ to: meta.handoffTo,
974
+ source: "manual",
975
+ confidence: "explicit"
976
+ });
977
+ continue;
978
+ }
979
+ if (meta.handoffFrom) {
980
+ pushEdge({
981
+ from: meta.handoffFrom,
982
+ to: runId,
983
+ source: "manual",
984
+ confidence: "explicit"
985
+ });
986
+ }
987
+ if (meta.handoffTo) {
988
+ pushEdge({
989
+ from: runId,
990
+ to: meta.handoffTo,
991
+ source: "manual",
992
+ confidence: "explicit"
993
+ });
994
+ }
995
+ if (meta.subAgentId && meta.parentGroupId && !meta.handoffFrom && !meta.handoffTo) {
996
+ pushEdge({
997
+ from: meta.parentGroupId,
998
+ to: meta.subAgentId,
999
+ source: "inferred",
1000
+ confidence: "correlated"
1001
+ });
1002
+ warnings.push({
1003
+ code: "ambiguous-handoff-endpoints",
1004
+ message: "Handoff inferred from parentGroupId and subAgentId without explicit handoffFrom/handoffTo.",
1005
+ runId,
1006
+ sessionId
1007
+ });
1008
+ }
1009
+ }
1010
+ return edges.sort((a, b) => {
1011
+ const from = a.from.localeCompare(b.from);
1012
+ if (from !== 0) return from;
1013
+ return a.to.localeCompare(b.to);
1014
+ });
1015
+ }
1016
+ function buildRetries(runIds, metaByRunId, warnings, sessionId) {
1017
+ const retries = [];
1018
+ for (const runId of runIds) {
1019
+ const meta = metaByRunId.get(runId);
1020
+ if (!meta) continue;
1021
+ if (meta.retryOf) {
1022
+ retries.push({
1023
+ runId,
1024
+ retryOf: meta.retryOf,
1025
+ attempt: meta.attempt,
1026
+ source: "manual",
1027
+ confidence: "explicit"
1028
+ });
1029
+ continue;
1030
+ }
1031
+ if (meta.attempt !== void 0 && meta.attempt > 1) {
1032
+ retries.push({
1033
+ runId,
1034
+ attempt: meta.attempt,
1035
+ source: "inferred",
1036
+ confidence: "correlated"
1037
+ });
1038
+ warnings.push({
1039
+ code: "ambiguous-retry-link",
1040
+ message: "attempt > 1 without retryOf; retry link is correlated only.",
1041
+ runId,
1042
+ sessionId
1043
+ });
1044
+ }
1045
+ }
1046
+ return retries.sort((a, b) => a.runId.localeCompare(b.runId));
1047
+ }
1048
+ function buildCriticalPath(runs, handoffs) {
1049
+ const runById = new Map(runs.map((run) => [run.runId, run]));
1050
+ const explicitTargets = new Set(
1051
+ handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.to)
1052
+ );
1053
+ const explicitSources = new Set(
1054
+ handoffs.filter((edge) => edge.confidence === "explicit").map((edge) => edge.from)
1055
+ );
1056
+ const ordered = [...runs].sort(compareRuns);
1057
+ const path = [];
1058
+ const visited = /* @__PURE__ */ new Set();
1059
+ const pushRun = (run, confidence, source) => {
1060
+ if (visited.has(run.runId)) return;
1061
+ visited.add(run.runId);
1062
+ path.push({
1063
+ runId: run.runId,
1064
+ name: run.name,
1065
+ startedAt: run.startedAt,
1066
+ durationMs: run.durationMs,
1067
+ confidence,
1068
+ source
1069
+ });
1070
+ };
1071
+ for (const edge of handoffs) {
1072
+ if (edge.confidence !== "explicit") continue;
1073
+ const fromRun = [...runById.values()].find(
1074
+ (run) => run.runId === edge.from || metaRunIdMatches(run, edge.from, runById)
1075
+ );
1076
+ const toRun = [...runById.values()].find(
1077
+ (run) => run.runId === edge.to || metaRunIdMatches(run, edge.to, runById)
1078
+ );
1079
+ if (fromRun) pushRun(fromRun, "explicit", "manual");
1080
+ if (toRun) pushRun(toRun, "explicit", "manual");
1081
+ }
1082
+ for (const run of ordered) {
1083
+ if (visited.has(run.runId)) continue;
1084
+ const confidence = explicitTargets.has(run.runId) || explicitSources.has(run.runId) ? "explicit" : "correlated";
1085
+ pushRun(run, confidence, confidence === "explicit" ? "manual" : "inferred");
1086
+ }
1087
+ return path;
1088
+ }
1089
+ function metaRunIdMatches(run, token, runById) {
1090
+ const meta = extractSessionWorkflowMetadata(run.metadata);
1091
+ return meta?.subAgentId === token || meta?.groupId === token || runById.has(token);
1092
+ }
1093
+ function buildSessionIndex(inputRuns, options = {}) {
1094
+ const warnings = [];
1095
+ const runs = [...inputRuns].sort(compareRuns);
1096
+ const metaByRunId = /* @__PURE__ */ new Map();
1097
+ for (const run of runs) {
1098
+ metaByRunId.set(run.runId, extractSessionWorkflowMetadata(run.metadata));
1099
+ }
1100
+ const sessionsByKey = /* @__PURE__ */ new Map();
1101
+ const unscopedRunIds = [];
1102
+ for (const run of runs) {
1103
+ const meta = metaByRunId.get(run.runId);
1104
+ const key = sessionKeyForRun(meta, {
1105
+ correlateByGroupId: options.correlateByGroupId === true
1106
+ });
1107
+ if (!key) {
1108
+ unscopedRunIds.push(run.runId);
1109
+ continue;
1110
+ }
1111
+ const bucket = sessionsByKey.get(key) ?? [];
1112
+ bucket.push(run);
1113
+ sessionsByKey.set(key, bucket);
1114
+ }
1115
+ const sessions = [...sessionsByKey.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([sessionId, sessionRuns]) => {
1116
+ const runIds = sessionRuns.map((run) => run.runId).sort();
1117
+ const handoffs = buildHandoffs(runIds, metaByRunId, warnings, sessionId);
1118
+ const retries = buildRetries(runIds, metaByRunId, warnings, sessionId);
1119
+ const groups = buildGroups(runIds, metaByRunId);
1120
+ const criticalPath = buildCriticalPath(sessionRuns, handoffs);
1121
+ const confidences = new Set(handoffs.map((edge) => edge.confidence));
1122
+ if (confidences.has("explicit") && confidences.has("correlated")) {
1123
+ warnings.push({
1124
+ code: "mixed-confidence-group",
1125
+ message: "Session aggregates explicit and correlated handoff edges.",
1126
+ sessionId
1127
+ });
1128
+ }
1129
+ return {
1130
+ sessionId,
1131
+ runIds,
1132
+ groups,
1133
+ handoffs,
1134
+ retries,
1135
+ criticalPath
1136
+ };
1137
+ });
1138
+ if (sessions.length === 0 && runs.length > 0) {
1139
+ warnings.push({
1140
+ code: "missing-session-id",
1141
+ message: "No sessionId (or correlated groupId) found on input runs."
1142
+ });
1143
+ }
1144
+ warnings.sort((a, b) => {
1145
+ const code = a.code.localeCompare(b.code);
1146
+ if (code !== 0) return code;
1147
+ return (a.runId ?? "").localeCompare(b.runId ?? "");
1148
+ });
1149
+ return {
1150
+ runs,
1151
+ sessions,
1152
+ unscopedRunIds: unscopedRunIds.sort(),
1153
+ warnings
1154
+ };
1155
+ }
588
1156
  var KNOWN_EVENTS = /* @__PURE__ */ new Set([
589
1157
  "run_started",
590
1158
  "run_completed",
@@ -629,6 +1197,6 @@ async function isAgentInspectTrace(filePath) {
629
1197
  }
630
1198
  }
631
1199
 
632
- export { buildLocalExplanation, buildTraceStats, filterTraces, isAgentInspectTrace, loadTraceMetadataList, parseDurationFilter, renderTraceStats, searchTraces };
1200
+ export { SESSION_WORKFLOW_KEYS, aggregateSessionCheckResults, buildLocalExplanation, buildSessionIndex, buildTraceStats, enrichSessionRunRecord, extractSessionWorkflowMetadata, filterMetasBySessionScope, filterTraces, groupSessionCohorts, isAgentInspectTrace, loadSessionRunRecords, loadTraceMetadataList, parseDurationFilter, renderTraceStats, searchTraces, sessionKeyForRun, traceMetasToSessionRunRecords };
633
1201
  //# sourceMappingURL=advanced.mjs.map
634
1202
  //# sourceMappingURL=advanced.mjs.map