agent-inspect 6.31.7 → 6.31.9

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 (51) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/packages/cli/dist/{chunk-QV73NM25.mjs → chunk-SWUZRRDT.mjs} +158 -21
  5. package/packages/cli/dist/chunk-SWUZRRDT.mjs.map +1 -0
  6. package/packages/cli/dist/index.cjs +312 -52
  7. package/packages/cli/dist/index.cjs.map +1 -1
  8. package/packages/cli/dist/index.mjs +156 -36
  9. package/packages/cli/dist/index.mjs.map +1 -1
  10. package/packages/cli/dist/{src-KFOBXFPN.mjs → src-XFIPYODW.mjs} +3 -3
  11. package/packages/cli/dist/{src-KFOBXFPN.mjs.map → src-XFIPYODW.mjs.map} +1 -1
  12. package/packages/core/dist/advanced.cjs +200 -24
  13. package/packages/core/dist/advanced.cjs.map +1 -1
  14. package/packages/core/dist/advanced.d.cts +1 -1
  15. package/packages/core/dist/advanced.d.ts +1 -1
  16. package/packages/core/dist/advanced.mjs +89 -15
  17. package/packages/core/dist/advanced.mjs.map +1 -1
  18. package/packages/core/dist/checks.mjs +2 -2
  19. package/packages/core/dist/{chunk-LXYPM2ZO.mjs → chunk-2CCRUI42.mjs} +19 -318
  20. package/packages/core/dist/chunk-2CCRUI42.mjs.map +1 -0
  21. package/packages/core/dist/{chunk-QLYUWKK7.mjs → chunk-2IRRUNIN.mjs} +11 -5
  22. package/packages/core/dist/chunk-2IRRUNIN.mjs.map +1 -0
  23. package/packages/core/dist/{chunk-VQUB3WRI.mjs → chunk-3SPBELJB.mjs} +14 -3
  24. package/packages/core/dist/chunk-3SPBELJB.mjs.map +1 -0
  25. package/packages/core/dist/{chunk-3RV3JILQ.mjs → chunk-IJJSPJXV.mjs} +20 -12
  26. package/packages/core/dist/chunk-IJJSPJXV.mjs.map +1 -0
  27. package/packages/core/dist/chunk-L5WLVBW4.mjs +355 -0
  28. package/packages/core/dist/chunk-L5WLVBW4.mjs.map +1 -0
  29. package/packages/core/dist/exporters.cjs +110 -18
  30. package/packages/core/dist/exporters.cjs.map +1 -1
  31. package/packages/core/dist/exporters.mjs +110 -18
  32. package/packages/core/dist/exporters.mjs.map +1 -1
  33. package/packages/core/dist/index.cjs +12 -1
  34. package/packages/core/dist/index.cjs.map +1 -1
  35. package/packages/core/dist/index.mjs +2 -2
  36. package/packages/core/dist/persisted.cjs +344 -9
  37. package/packages/core/dist/persisted.cjs.map +1 -1
  38. package/packages/core/dist/persisted.d.cts +8 -1
  39. package/packages/core/dist/persisted.d.ts +8 -1
  40. package/packages/core/dist/persisted.mjs +3 -2
  41. package/packages/core/dist/persisted.mjs.map +1 -1
  42. package/packages/core/dist/readers.cjs +377 -87
  43. package/packages/core/dist/readers.cjs.map +1 -1
  44. package/packages/core/dist/readers.mjs +3 -3
  45. package/packages/cli/dist/chunk-QV73NM25.mjs.map +0 -1
  46. package/packages/core/dist/chunk-3RV3JILQ.mjs.map +0 -1
  47. package/packages/core/dist/chunk-FWK3Q3OJ.mjs +0 -56
  48. package/packages/core/dist/chunk-FWK3Q3OJ.mjs.map +0 -1
  49. package/packages/core/dist/chunk-LXYPM2ZO.mjs.map +0 -1
  50. package/packages/core/dist/chunk-QLYUWKK7.mjs.map +0 -1
  51. package/packages/core/dist/chunk-VQUB3WRI.mjs.map +0 -1
@@ -430,12 +430,12 @@ function persistedInspectEventToTraceEvents(event) {
430
430
  if (!isPersistedInspectEvent(event)) {
431
431
  throw new Error("Invalid PersistedInspectEvent: failed isPersistedInspectEvent");
432
432
  }
433
- const legacyEvent = event.attributes?.legacyEvent;
434
- if (legacyEvent === "run_started") return [fromLegacyRunStarted(event)];
435
- if (legacyEvent === "run_completed") return [fromLegacyRunCompleted(event)];
436
- if (legacyEvent === "step_started") return [fromLegacyStepStarted(event)];
437
- if (legacyEvent === "step_completed") return [fromLegacyStepCompleted(event)];
438
- if (legacyEvent === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
433
+ const legacyEvent2 = event.attributes?.legacyEvent;
434
+ if (legacyEvent2 === "run_started") return [fromLegacyRunStarted(event)];
435
+ if (legacyEvent2 === "run_completed") return [fromLegacyRunCompleted(event)];
436
+ if (legacyEvent2 === "step_started") return [fromLegacyStepStarted(event)];
437
+ if (legacyEvent2 === "step_completed") return [fromLegacyStepCompleted(event)];
438
+ if (legacyEvent2 === "outcome_observed") return [fromLegacyOutcomeObserved(event)];
439
439
  if (event.kind === "RUN") {
440
440
  return fromNativeRun(event);
441
441
  }
@@ -876,6 +876,336 @@ function traceEventsToPersistedInspectEvents(events, options) {
876
876
  );
877
877
  }
878
878
 
879
+ // packages/core/src/diagnostics/programmatic.ts
880
+ var PROGRAMMATIC_DIAGNOSTIC_SPECS = Object.freeze({
881
+ AI_TRACE_INPUT_INVALID: {
882
+ code: "AI_TRACE_INPUT_INVALID",
883
+ summary: 'Expected { type: "file", path }, { type: "directory", path }, { type: "string", content }, { type: "buffer", content }, or { type: "stdin" }.',
884
+ remediation: "For a file path, use openTraceFile(path).",
885
+ relatedCodes: ["invalid_input"]
886
+ },
887
+ AI_TRACE_FORMAT_UNSUPPORTED: {
888
+ code: "AI_TRACE_FORMAT_UNSUPPORTED",
889
+ summary: "No trace reader could detect the input format.",
890
+ remediation: "Pass an AgentInspect JSONL file via openTraceFile, or set options.format to a registered reader.",
891
+ relatedCodes: ["unsupported_format"]
892
+ },
893
+ AI_TRACE_FORMAT_AMBIGUOUS: {
894
+ code: "AI_TRACE_FORMAT_AMBIGUOUS",
895
+ summary: "Multiple trace readers matched the input with equal confidence.",
896
+ remediation: "Set options.format explicitly to disambiguate the reader.",
897
+ relatedCodes: ["ambiguous_format"]
898
+ },
899
+ AI_TRACE_FACTS_INPUT_NOT_NORMALIZED: {
900
+ code: "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED",
901
+ summary: "TraceFacts requires TraceReadResult or PersistedInspectEvent[].",
902
+ remediation: "Use openTraceFile() to normalize a JSONL trace first."
903
+ },
904
+ AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED: {
905
+ code: "AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED",
906
+ summary: "Multiple runs are available; select a run before executing checks.",
907
+ remediation: "Pass options.runId or TraceCheckInput.selectedRun.",
908
+ relatedCodes: ["AI_CHECK_RUN_SELECTION_REQUIRED"]
909
+ },
910
+ AI_TRACE_RELATIONSHIP_SELF_PARENT: {
911
+ code: "AI_TRACE_RELATIONSHIP_SELF_PARENT",
912
+ summary: "A parentId equals its own event/step id.",
913
+ remediation: "Reject at capture (AI_LANGGRAPH_SELF_PARENT_REJECTED) or drop via logical projection; do not invent replacement parents.",
914
+ relatedCodes: [
915
+ "AI_LANGGRAPH_SELF_PARENT_REJECTED",
916
+ "AI_LOGICAL_SELF_PARENT_REMOVED"
917
+ ]
918
+ },
919
+ AI_TRACE_RELATIONSHIP_CYCLE: {
920
+ code: "AI_TRACE_RELATIONSHIP_CYCLE",
921
+ summary: "Trace contains a parentId cycle.",
922
+ remediation: "Use visibility-first tree linking for legacy fixtures; prefer acyclic capture for new adapter output.",
923
+ relatedCodes: ["structure.cycle"]
924
+ }
925
+ });
926
+ function formatProgrammaticDiagnostic(code, detail) {
927
+ const spec = PROGRAMMATIC_DIAGNOSTIC_SPECS[code];
928
+ const summary = detail?.trim() ? detail.trim() : spec.summary;
929
+ return `${code}: ${summary} Remediation: ${spec.remediation}`;
930
+ }
931
+
932
+ // packages/core/src/checks/logical-events.ts
933
+ function isRecord5(value) {
934
+ return typeof value === "object" && value !== null && !Array.isArray(value);
935
+ }
936
+ function legacyEvent(event) {
937
+ const value = event.attributes?.legacyEvent;
938
+ return typeof value === "string" ? value : void 0;
939
+ }
940
+ function stepIdOf(event) {
941
+ const value = event.attributes?.stepId;
942
+ if (typeof value === "string" && value.trim() !== "") return value;
943
+ return void 0;
944
+ }
945
+ function cloneEvent(event) {
946
+ return {
947
+ ...event,
948
+ ...event.attributes !== void 0 ? { attributes: { ...event.attributes } } : {},
949
+ ...event.error !== void 0 ? { error: { ...event.error } } : {},
950
+ ...event.tokenUsage !== void 0 ? { tokenUsage: { ...event.tokenUsage } } : {},
951
+ ...event.source !== void 0 ? { source: { ...event.source } } : {}
952
+ };
953
+ }
954
+ function mergeAttributes(start, complete) {
955
+ const merged = {
956
+ ...isRecord5(complete.attributes) ? complete.attributes : {},
957
+ ...isRecord5(start.attributes) ? start.attributes : {}
958
+ };
959
+ merged.legacyEvent = start.attributes?.legacyEvent ?? complete.attributes?.legacyEvent;
960
+ merged.legacyCompleteEvent = complete.attributes?.legacyEvent;
961
+ if (complete.attributes?.errorStack !== void 0) {
962
+ merged.errorStack = complete.attributes.errorStack;
963
+ }
964
+ return Object.keys(merged).length > 0 ? merged : void 0;
965
+ }
966
+ function pairStartComplete(start, complete) {
967
+ const attributes = mergeAttributes(start, complete);
968
+ const paired = {
969
+ ...cloneEvent(start),
970
+ status: complete.status,
971
+ timestamp: complete.timestamp ?? start.timestamp,
972
+ ...complete.endedAt !== void 0 ? { endedAt: complete.endedAt } : {},
973
+ ...complete.durationMs !== void 0 ? { durationMs: complete.durationMs } : {},
974
+ ...complete.error !== void 0 ? { error: { ...complete.error } } : {},
975
+ ...complete.tokenUsage !== void 0 && start.tokenUsage === void 0 ? { tokenUsage: { ...complete.tokenUsage } } : {},
976
+ ...attributes !== void 0 ? { attributes } : {}
977
+ };
978
+ return {
979
+ ...paired,
980
+ sourceEventIds: Object.freeze([start.eventId, complete.eventId]),
981
+ projection: {
982
+ paired: true,
983
+ absorbedEventIds: Object.freeze([complete.eventId]),
984
+ parentNormalized: false,
985
+ ...start.parentId !== void 0 ? { originalParentId: start.parentId } : {}
986
+ }
987
+ };
988
+ }
989
+ function asLogical(event, extras) {
990
+ return {
991
+ ...cloneEvent(event),
992
+ sourceEventIds: Object.freeze([event.eventId]),
993
+ projection: {
994
+ paired: false,
995
+ absorbedEventIds: Object.freeze([]),
996
+ parentNormalized: extras?.parentNormalized === true,
997
+ ...{}
998
+ }
999
+ };
1000
+ }
1001
+ function projectLogicalEvents(events) {
1002
+ const diagnostics = [];
1003
+ const byRun = /* @__PURE__ */ new Map();
1004
+ for (const event of events) {
1005
+ const list = byRun.get(event.runId) ?? [];
1006
+ list.push(event);
1007
+ byRun.set(event.runId, list);
1008
+ }
1009
+ const absorbedIds = /* @__PURE__ */ new Set();
1010
+ const logicalByRawId = /* @__PURE__ */ new Map();
1011
+ const stepIdToLogicalId = /* @__PURE__ */ new Map();
1012
+ const logical = [];
1013
+ const orderedRuns = [...byRun.keys()].sort((a, b) => a.localeCompare(b));
1014
+ for (const runId of orderedRuns) {
1015
+ const runEvents = byRun.get(runId) ?? [];
1016
+ const starts = [];
1017
+ const completes = [];
1018
+ const others = [];
1019
+ for (const event of runEvents) {
1020
+ const legacy = legacyEvent(event);
1021
+ if (legacy === "step_started" || legacy === "run_started" && event.status === "running") {
1022
+ starts.push(event);
1023
+ } else if (legacy === "step_completed" || legacy === "run_completed") {
1024
+ completes.push(event);
1025
+ } else {
1026
+ others.push(event);
1027
+ }
1028
+ }
1029
+ const usedCompletes = /* @__PURE__ */ new Set();
1030
+ for (const start of starts) {
1031
+ const stepId = stepIdOf(start);
1032
+ let match;
1033
+ if (legacyEvent(start) === "run_started") {
1034
+ const candidates = completes.filter(
1035
+ (c) => !usedCompletes.has(c.eventId) && legacyEvent(c) === "run_completed"
1036
+ );
1037
+ if (candidates.length > 1) {
1038
+ diagnostics.push({
1039
+ code: "AI_LOGICAL_PAIR_AMBIGUOUS",
1040
+ message: `Multiple run_completed rows for run ${runId}; using first by eventId.`,
1041
+ eventIds: candidates.map((c) => c.eventId)
1042
+ });
1043
+ candidates.sort((a, b) => a.eventId.localeCompare(b.eventId));
1044
+ }
1045
+ match = candidates[0];
1046
+ } else if (stepId) {
1047
+ const candidates = completes.filter(
1048
+ (c) => !usedCompletes.has(c.eventId) && legacyEvent(c) === "step_completed" && stepIdOf(c) === stepId
1049
+ );
1050
+ if (candidates.length > 1) {
1051
+ diagnostics.push({
1052
+ code: "AI_LOGICAL_PAIR_AMBIGUOUS",
1053
+ message: `Multiple step_completed rows for stepId ${stepId}; using first by eventId.`,
1054
+ eventIds: candidates.map((c) => c.eventId)
1055
+ });
1056
+ candidates.sort((a, b) => a.eventId.localeCompare(b.eventId));
1057
+ }
1058
+ match = candidates[0];
1059
+ }
1060
+ if (match) {
1061
+ usedCompletes.add(match.eventId);
1062
+ absorbedIds.add(match.eventId);
1063
+ const paired = pairStartComplete(start, match);
1064
+ logical.push(paired);
1065
+ logicalByRawId.set(start.eventId, paired);
1066
+ logicalByRawId.set(match.eventId, paired);
1067
+ if (stepId) stepIdToLogicalId.set(`${runId}:${stepId}`, paired.eventId);
1068
+ } else {
1069
+ diagnostics.push({
1070
+ code: "AI_LOGICAL_PAIR_UNMATCHED_START",
1071
+ message: `No matching complete for start ${start.eventId}.`,
1072
+ eventIds: [start.eventId]
1073
+ });
1074
+ const alone = asLogical(start);
1075
+ logical.push(alone);
1076
+ logicalByRawId.set(start.eventId, alone);
1077
+ if (stepId) stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
1078
+ }
1079
+ }
1080
+ for (const complete of completes) {
1081
+ if (usedCompletes.has(complete.eventId)) continue;
1082
+ diagnostics.push({
1083
+ code: "AI_LOGICAL_PAIR_UNMATCHED_COMPLETE",
1084
+ message: `No matching start for complete ${complete.eventId}.`,
1085
+ eventIds: [complete.eventId]
1086
+ });
1087
+ const alone = asLogical(complete);
1088
+ logical.push(alone);
1089
+ logicalByRawId.set(complete.eventId, alone);
1090
+ const stepId = stepIdOf(complete);
1091
+ if (stepId && !stepIdToLogicalId.has(`${runId}:${stepId}`)) {
1092
+ stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
1093
+ }
1094
+ }
1095
+ for (const event of others) {
1096
+ const alone = asLogical(event);
1097
+ logical.push(alone);
1098
+ logicalByRawId.set(event.eventId, alone);
1099
+ const stepId = stepIdOf(event);
1100
+ if (stepId && !stepIdToLogicalId.has(`${runId}:${stepId}`)) {
1101
+ stepIdToLogicalId.set(`${runId}:${stepId}`, alone.eventId);
1102
+ }
1103
+ }
1104
+ }
1105
+ const logicalById = new Map(logical.map((e) => [e.eventId, e]));
1106
+ const normalized = [];
1107
+ for (const event of logical) {
1108
+ const originalParentId = event.parentId;
1109
+ if (!originalParentId) {
1110
+ normalized.push(event);
1111
+ continue;
1112
+ }
1113
+ let nextParent = originalParentId;
1114
+ let remapped = false;
1115
+ const viaAbsorbed = logicalByRawId.get(originalParentId);
1116
+ if (viaAbsorbed && viaAbsorbed.eventId !== originalParentId) {
1117
+ nextParent = viaAbsorbed.eventId;
1118
+ remapped = true;
1119
+ } else if (!logicalById.has(originalParentId)) {
1120
+ const viaStep = stepIdToLogicalId.get(`${event.runId}:${originalParentId}`);
1121
+ if (viaStep) {
1122
+ nextParent = viaStep;
1123
+ remapped = true;
1124
+ }
1125
+ }
1126
+ if (!remapped) {
1127
+ if (originalParentId === event.eventId) {
1128
+ diagnostics.push({
1129
+ code: "AI_LOGICAL_SELF_PARENT_REMOVED",
1130
+ message: formatProgrammaticDiagnostic(
1131
+ "AI_TRACE_RELATIONSHIP_SELF_PARENT",
1132
+ `Removed self-parent edge on ${event.eventId}.`
1133
+ ),
1134
+ eventIds: [event.eventId]
1135
+ });
1136
+ const { parentId: _drop, ...rest } = event;
1137
+ normalized.push({
1138
+ ...rest,
1139
+ projection: {
1140
+ ...event.projection,
1141
+ parentNormalized: true,
1142
+ originalParentId
1143
+ }
1144
+ });
1145
+ continue;
1146
+ }
1147
+ if (!logicalById.has(originalParentId) && !logicalByRawId.has(originalParentId)) {
1148
+ const mapping = event.attributes?.parentMapping;
1149
+ const unresolved = mapping === "unresolved" || event.attributes?.parentUnresolved === true || event.attributes?.unresolvedParent === true || // LangGraph/framework scaffolding sentinel labels are not event ids.
1150
+ /^LangGraph$/i.test(originalParentId) || originalParentId.startsWith("unresolved:");
1151
+ if (!unresolved) {
1152
+ diagnostics.push({
1153
+ code: "AI_LOGICAL_PARENT_UNRESOLVED",
1154
+ message: `Parent ${originalParentId} unresolved for ${event.eventId}.`,
1155
+ eventIds: [event.eventId]
1156
+ });
1157
+ }
1158
+ }
1159
+ normalized.push(event);
1160
+ continue;
1161
+ }
1162
+ if (nextParent === event.eventId) {
1163
+ diagnostics.push({
1164
+ code: "AI_LOGICAL_SELF_PARENT_REMOVED",
1165
+ message: formatProgrammaticDiagnostic(
1166
+ "AI_TRACE_RELATIONSHIP_SELF_PARENT",
1167
+ `Removed self-parent edge on ${event.eventId} (was ${originalParentId}).`
1168
+ ),
1169
+ eventIds: [event.eventId]
1170
+ });
1171
+ const { parentId: _drop, ...rest } = event;
1172
+ normalized.push({
1173
+ ...rest,
1174
+ projection: {
1175
+ ...event.projection,
1176
+ parentNormalized: true,
1177
+ originalParentId
1178
+ }
1179
+ });
1180
+ continue;
1181
+ }
1182
+ diagnostics.push({
1183
+ code: "AI_LOGICAL_PARENT_REMAPPED",
1184
+ message: `Remapped parent ${originalParentId} \u2192 ${nextParent} for ${event.eventId}.`,
1185
+ eventIds: [event.eventId]
1186
+ });
1187
+ normalized.push({
1188
+ ...event,
1189
+ parentId: nextParent,
1190
+ projection: {
1191
+ ...event.projection,
1192
+ parentNormalized: true,
1193
+ originalParentId
1194
+ }
1195
+ });
1196
+ }
1197
+ const rawIndex = new Map(events.map((e, i) => [e.eventId, i]));
1198
+ normalized.sort((a, b) => {
1199
+ const ai = rawIndex.get(a.sourceEventIds[0]) ?? 0;
1200
+ const bi = rawIndex.get(b.sourceEventIds[0]) ?? 0;
1201
+ return ai - bi || a.eventId.localeCompare(b.eventId);
1202
+ });
1203
+ return {
1204
+ logicalEvents: Object.freeze(normalized),
1205
+ diagnostics: Object.freeze(diagnostics)
1206
+ };
1207
+ }
1208
+
879
1209
  // packages/core/src/logs/tree-builder.ts
880
1210
  function inc(map, key) {
881
1211
  map[key] = (map[key] ?? 0) + 1;
@@ -1203,66 +1533,18 @@ function persistedInspectEventsToInspectEvents(events, options) {
1203
1533
  }
1204
1534
 
1205
1535
  // packages/core/src/persisted/tree-bridge.ts
1536
+ function logicalToPersisted(event) {
1537
+ const { sourceEventIds: _sourceEventIds, projection: _projection, ...rest } = event;
1538
+ return rest;
1539
+ }
1206
1540
  function persistedInspectEventsToRunTrees(events, options) {
1207
- const inspectEvents = persistedInspectEventsToInspectEvents(events, {
1541
+ const sourceEvents = options?.coalesceLifecycle === true ? projectLogicalEvents(events).logicalEvents.map(logicalToPersisted) : events;
1542
+ const inspectEvents = persistedInspectEventsToInspectEvents(sourceEvents, {
1208
1543
  skipInvalid: options?.skipInvalid
1209
1544
  });
1210
1545
  return new TreeBuilder().build(inspectEvents);
1211
1546
  }
1212
1547
 
1213
- // packages/core/src/diagnostics/programmatic.ts
1214
- var PROGRAMMATIC_DIAGNOSTIC_SPECS = Object.freeze({
1215
- AI_TRACE_INPUT_INVALID: {
1216
- code: "AI_TRACE_INPUT_INVALID",
1217
- summary: 'Expected { type: "file", path }, { type: "directory", path }, { type: "string", content }, { type: "buffer", content }, or { type: "stdin" }.',
1218
- remediation: "For a file path, use openTraceFile(path).",
1219
- relatedCodes: ["invalid_input"]
1220
- },
1221
- AI_TRACE_FORMAT_UNSUPPORTED: {
1222
- code: "AI_TRACE_FORMAT_UNSUPPORTED",
1223
- summary: "No trace reader could detect the input format.",
1224
- remediation: "Pass an AgentInspect JSONL file via openTraceFile, or set options.format to a registered reader.",
1225
- relatedCodes: ["unsupported_format"]
1226
- },
1227
- AI_TRACE_FORMAT_AMBIGUOUS: {
1228
- code: "AI_TRACE_FORMAT_AMBIGUOUS",
1229
- summary: "Multiple trace readers matched the input with equal confidence.",
1230
- remediation: "Set options.format explicitly to disambiguate the reader.",
1231
- relatedCodes: ["ambiguous_format"]
1232
- },
1233
- AI_TRACE_FACTS_INPUT_NOT_NORMALIZED: {
1234
- code: "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED",
1235
- summary: "TraceFacts requires TraceReadResult or PersistedInspectEvent[].",
1236
- remediation: "Use openTraceFile() to normalize a JSONL trace first."
1237
- },
1238
- AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED: {
1239
- code: "AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED",
1240
- summary: "Multiple runs are available; select a run before executing checks.",
1241
- remediation: "Pass options.runId or TraceCheckInput.selectedRun.",
1242
- relatedCodes: ["AI_CHECK_RUN_SELECTION_REQUIRED"]
1243
- },
1244
- AI_TRACE_RELATIONSHIP_SELF_PARENT: {
1245
- code: "AI_TRACE_RELATIONSHIP_SELF_PARENT",
1246
- summary: "A parentId equals its own event/step id.",
1247
- remediation: "Reject at capture (AI_LANGGRAPH_SELF_PARENT_REJECTED) or drop via logical projection; do not invent replacement parents.",
1248
- relatedCodes: [
1249
- "AI_LANGGRAPH_SELF_PARENT_REJECTED",
1250
- "AI_LOGICAL_SELF_PARENT_REMOVED"
1251
- ]
1252
- },
1253
- AI_TRACE_RELATIONSHIP_CYCLE: {
1254
- code: "AI_TRACE_RELATIONSHIP_CYCLE",
1255
- summary: "Trace contains a parentId cycle.",
1256
- remediation: "Use visibility-first tree linking for legacy fixtures; prefer acyclic capture for new adapter output.",
1257
- relatedCodes: ["structure.cycle"]
1258
- }
1259
- });
1260
- function formatProgrammaticDiagnostic(code, detail) {
1261
- const spec = PROGRAMMATIC_DIAGNOSTIC_SPECS[code];
1262
- const summary = detail?.trim() ? detail.trim() : spec.summary;
1263
- return `${code}: ${summary} Remediation: ${spec.remediation}`;
1264
- }
1265
-
1266
1548
  // packages/core/src/readers/mapping-ledger.ts
1267
1549
  var OPENINFERENCE_MAPPING_LEDGER = {
1268
1550
  id: "openinference-to-agent-inspect",
@@ -1668,7 +1950,7 @@ function persistedEventsForParsedTrace(parsed) {
1668
1950
  sourceName: "agent-inspect-jsonl-reader"
1669
1951
  });
1670
1952
  }
1671
- function isRecord5(value) {
1953
+ function isRecord6(value) {
1672
1954
  return typeof value === "object" && value !== null && !Array.isArray(value);
1673
1955
  }
1674
1956
  function isNonEmptyString3(value) {
@@ -1683,13 +1965,13 @@ function readStringField(record, keys) {
1683
1965
  }
1684
1966
  function readRecordField(record, key) {
1685
1967
  const value = record[key];
1686
- return isRecord5(value) ? value : void 0;
1968
+ return isRecord6(value) ? value : void 0;
1687
1969
  }
1688
1970
  function parseJsonDocument(content) {
1689
1971
  return JSON.parse(content);
1690
1972
  }
1691
1973
  function looksLikeOpenInferenceSpan(value) {
1692
- if (!isRecord5(value)) return false;
1974
+ if (!isRecord6(value)) return false;
1693
1975
  const attributes = readRecordField(value, "attributes");
1694
1976
  return readStringField(value, ["trace_id", "traceId"]) !== void 0 && readStringField(value, ["span_id", "spanId"]) !== void 0 && (readStringField(value, ["name"]) !== void 0 || attributes?.["openinference.span.kind"] !== void 0);
1695
1977
  }
@@ -1714,7 +1996,7 @@ function extractOpenInferenceDocument(root) {
1714
1996
  unsupportedFields
1715
1997
  };
1716
1998
  }
1717
- if (!isRecord5(root)) return void 0;
1999
+ if (!isRecord6(root)) return void 0;
1718
2000
  const rootFormat = root.format;
1719
2001
  const rootCompatibility = root.compatibility;
1720
2002
  const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -1854,7 +2136,7 @@ function summarizeAttributeValue(value) {
1854
2136
  if (Array.isArray(value)) {
1855
2137
  return { type: "array", length: value.length };
1856
2138
  }
1857
- if (isRecord5(value)) {
2139
+ if (isRecord6(value)) {
1858
2140
  return { type: "object", keyCount: Object.keys(value).length };
1859
2141
  }
1860
2142
  if (value === null) {
@@ -1941,7 +2223,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
1941
2223
  }
1942
2224
  }
1943
2225
  function mapOpenInferenceStatus(status) {
1944
- if (!isRecord5(status)) return void 0;
2226
+ if (!isRecord6(status)) return void 0;
1945
2227
  const rawCode = status.code;
1946
2228
  if (typeof rawCode !== "string") return void 0;
1947
2229
  switch (rawCode.toUpperCase()) {
@@ -2049,10 +2331,10 @@ function mapOpenInferenceSpan(span, index, version) {
2049
2331
  warnings.push(...kindWarnings);
2050
2332
  const status = mapOpenInferenceStatus(span.status);
2051
2333
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
2052
- const errorMessage = isRecord5(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
2334
+ const errorMessage = isRecord6(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
2053
2335
  const event = {
2054
2336
  schemaVersion: "0.2",
2055
- eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
2337
+ eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : `${traceId}:${spanId}`,
2056
2338
  runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
2057
2339
  kind,
2058
2340
  name,
@@ -2103,12 +2385,16 @@ function mapOpenInferenceEvents(document) {
2103
2385
  const mapped = document.spans.map(
2104
2386
  (span, index) => mapOpenInferenceSpan(span, index, document.version)
2105
2387
  );
2106
- const spanIdToEventId = new Map(
2107
- mapped.map((span) => [span.spanId, span.event.eventId])
2388
+ const spanKeyToEventId = new Map(
2389
+ mapped.map((span) => {
2390
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
2391
+ return [`${traceId}:${span.spanId}`, span.event.eventId];
2392
+ })
2108
2393
  );
2109
2394
  for (const span of mapped) {
2110
2395
  if (span.parentSpanId === void 0) continue;
2111
- span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
2396
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
2397
+ span.event.parentId = spanKeyToEventId.get(`${traceId}:${span.parentSpanId}`) ?? span.parentSpanId;
2112
2398
  }
2113
2399
  return {
2114
2400
  events: mapped.map((span) => span.event),
@@ -2195,7 +2481,7 @@ var openInferenceJsonReader = {
2195
2481
  }
2196
2482
  };
2197
2483
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
2198
- if (!isRecord5(value)) {
2484
+ if (!isRecord6(value)) {
2199
2485
  unsupportedFields.push(field);
2200
2486
  warnings.push({
2201
2487
  code: "otlp_attribute_value_invalid",
@@ -2217,15 +2503,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
2217
2503
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
2218
2504
  return value.doubleValue;
2219
2505
  }
2220
- if (isRecord5(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
2506
+ if (isRecord6(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
2221
2507
  return value.arrayValue.values.map(
2222
2508
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
2223
2509
  );
2224
2510
  }
2225
- if (isRecord5(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
2511
+ if (isRecord6(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
2226
2512
  const out = {};
2227
2513
  for (const [index, item] of value.kvlistValue.values.entries()) {
2228
- if (!isRecord5(item) || typeof item.key !== "string") {
2514
+ if (!isRecord6(item) || typeof item.key !== "string") {
2229
2515
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
2230
2516
  continue;
2231
2517
  }
@@ -2276,7 +2562,7 @@ function parseOtlpAttributes(value, pathPrefix) {
2276
2562
  }
2277
2563
  for (const [index, item] of value.entries()) {
2278
2564
  const field = `${pathPrefix}[${index}]`;
2279
- if (!isRecord5(item) || typeof item.key !== "string") {
2565
+ if (!isRecord6(item) || typeof item.key !== "string") {
2280
2566
  unsupportedFields.push(field);
2281
2567
  warnings.push({
2282
2568
  code: "otlp_attribute_invalid",
@@ -2299,16 +2585,16 @@ function parseOtlpAttributes(value, pathPrefix) {
2299
2585
  return { attributes, warnings, unsupportedFields };
2300
2586
  }
2301
2587
  function looksLikeOtlpSpan(value) {
2302
- return isRecord5(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
2588
+ return isRecord6(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
2303
2589
  }
2304
2590
  function extractOtlpDocument(root) {
2305
- if (!isRecord5(root) || !Array.isArray(root.resourceSpans)) return void 0;
2591
+ if (!isRecord6(root) || !Array.isArray(root.resourceSpans)) return void 0;
2306
2592
  const spans = [];
2307
2593
  const warnings = [];
2308
2594
  const unsupportedFields = [];
2309
2595
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
2310
2596
  const resourcePath = `resourceSpans[${resourceIndex}]`;
2311
- if (!isRecord5(resourceSpan)) {
2597
+ if (!isRecord6(resourceSpan)) {
2312
2598
  unsupportedFields.push(resourcePath);
2313
2599
  continue;
2314
2600
  }
@@ -2331,7 +2617,7 @@ function extractOtlpDocument(root) {
2331
2617
  }
2332
2618
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
2333
2619
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
2334
- if (!isRecord5(scopeSpan)) {
2620
+ if (!isRecord6(scopeSpan)) {
2335
2621
  unsupportedFields.push(scopePath);
2336
2622
  continue;
2337
2623
  }
@@ -2398,7 +2684,7 @@ function extractOtlpDocument(root) {
2398
2684
  };
2399
2685
  }
2400
2686
  function mapOtlpStatus(status) {
2401
- if (!isRecord5(status)) return void 0;
2687
+ if (!isRecord6(status)) return void 0;
2402
2688
  const rawCode = status.code;
2403
2689
  if (typeof rawCode === "number" && Number.isFinite(rawCode)) {
2404
2690
  switch (rawCode) {
@@ -2516,7 +2802,7 @@ function mapOtlpEvents(value, pathPrefix) {
2516
2802
  const events = [];
2517
2803
  for (const [index, event] of value.entries()) {
2518
2804
  const eventPath = `${pathPrefix}[${index}]`;
2519
- if (!isRecord5(event)) {
2805
+ if (!isRecord6(event)) {
2520
2806
  unsupportedFields.push(eventPath);
2521
2807
  continue;
2522
2808
  }
@@ -2654,10 +2940,10 @@ function mapOtlpSpan(context) {
2654
2940
  warnings.push(...kindWarnings);
2655
2941
  const status = mapOtlpStatus(span.status);
2656
2942
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
2657
- const errorMessage = isRecord5(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
2943
+ const errorMessage = isRecord6(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
2658
2944
  const event = {
2659
2945
  schemaVersion: "0.2",
2660
- eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
2946
+ eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : `${traceId}:${spanId}`,
2661
2947
  runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
2662
2948
  kind,
2663
2949
  name: readStringField(span, ["name"]) ?? spanId,
@@ -2706,12 +2992,16 @@ function mapOtlpSpan(context) {
2706
2992
  }
2707
2993
  function mapOtlpEventsToPersisted(document) {
2708
2994
  const mapped = document.spans.map((span) => mapOtlpSpan(span));
2709
- const spanIdToEventId = new Map(
2710
- mapped.map((span) => [span.spanId, span.event.eventId])
2995
+ const spanKeyToEventId = new Map(
2996
+ mapped.map((span) => {
2997
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
2998
+ return [`${traceId}:${span.spanId}`, span.event.eventId];
2999
+ })
2711
3000
  );
2712
3001
  for (const span of mapped) {
2713
3002
  if (span.parentSpanId === void 0) continue;
2714
- span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
3003
+ const traceId = typeof span.event.trace?.traceId === "string" ? span.event.trace.traceId : "";
3004
+ span.event.parentId = spanKeyToEventId.get(`${traceId}:${span.parentSpanId}`) ?? span.parentSpanId;
2715
3005
  }
2716
3006
  return {
2717
3007
  events: mapped.map((span) => span.event),