agent-inspect 6.31.6 → 6.31.8

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 (46) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/docs/AI-SDK-ADOPTION.md +62 -34
  4. package/package.json +1 -1
  5. package/packages/cli/dist/{chunk-YXDNWHNJ.mjs → chunk-6FE47XSF.mjs} +119 -34
  6. package/packages/cli/dist/chunk-6FE47XSF.mjs.map +1 -0
  7. package/packages/cli/dist/index.cjs +569 -102
  8. package/packages/cli/dist/index.cjs.map +1 -1
  9. package/packages/cli/dist/index.mjs +454 -74
  10. package/packages/cli/dist/index.mjs.map +1 -1
  11. package/packages/cli/dist/{src-H22KNWAZ.mjs → src-NXAYHG34.mjs} +3 -3
  12. package/packages/cli/dist/{src-H22KNWAZ.mjs.map → src-NXAYHG34.mjs.map} +1 -1
  13. package/packages/core/dist/advanced.cjs +116 -31
  14. package/packages/core/dist/advanced.cjs.map +1 -1
  15. package/packages/core/dist/advanced.mjs +7 -7
  16. package/packages/core/dist/checks.mjs +2 -2
  17. package/packages/core/dist/{chunk-LXYPM2ZO.mjs → chunk-2CCRUI42.mjs} +19 -318
  18. package/packages/core/dist/chunk-2CCRUI42.mjs.map +1 -0
  19. package/packages/core/dist/{chunk-Q5SLKV2Y.mjs → chunk-2IRRUNIN.mjs} +28 -5
  20. package/packages/core/dist/chunk-2IRRUNIN.mjs.map +1 -0
  21. package/packages/core/dist/{chunk-EXGQLMVB.mjs → chunk-7YYS742B.mjs} +49 -12
  22. package/packages/core/dist/chunk-7YYS742B.mjs.map +1 -0
  23. package/packages/core/dist/{chunk-OSGNGRHF.mjs → chunk-IJJSPJXV.mjs} +51 -25
  24. package/packages/core/dist/chunk-IJJSPJXV.mjs.map +1 -0
  25. package/packages/core/dist/chunk-L5WLVBW4.mjs +355 -0
  26. package/packages/core/dist/chunk-L5WLVBW4.mjs.map +1 -0
  27. package/packages/core/dist/exporters.cjs +327 -58
  28. package/packages/core/dist/exporters.cjs.map +1 -1
  29. package/packages/core/dist/exporters.mjs +281 -49
  30. package/packages/core/dist/exporters.mjs.map +1 -1
  31. package/packages/core/dist/persisted.cjs +361 -9
  32. package/packages/core/dist/persisted.cjs.map +1 -1
  33. package/packages/core/dist/persisted.d.cts +8 -1
  34. package/packages/core/dist/persisted.d.ts +8 -1
  35. package/packages/core/dist/persisted.mjs +3 -2
  36. package/packages/core/dist/persisted.mjs.map +1 -1
  37. package/packages/core/dist/readers.cjs +425 -100
  38. package/packages/core/dist/readers.cjs.map +1 -1
  39. package/packages/core/dist/readers.mjs +3 -3
  40. package/packages/cli/dist/chunk-YXDNWHNJ.mjs.map +0 -1
  41. package/packages/core/dist/chunk-EXGQLMVB.mjs.map +0 -1
  42. package/packages/core/dist/chunk-FWK3Q3OJ.mjs +0 -56
  43. package/packages/core/dist/chunk-FWK3Q3OJ.mjs.map +0 -1
  44. package/packages/core/dist/chunk-LXYPM2ZO.mjs.map +0 -1
  45. package/packages/core/dist/chunk-OSGNGRHF.mjs.map +0 -1
  46. package/packages/core/dist/chunk-Q5SLKV2Y.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;
@@ -1168,6 +1498,23 @@ function persistedInspectEventToInspectEvent(event) {
1168
1498
  if (event.durationMs !== void 0 && Number.isFinite(event.durationMs) && event.durationMs >= 0) {
1169
1499
  out.durationMs = event.durationMs;
1170
1500
  }
1501
+ if (event.startedAt !== void 0) {
1502
+ const started = parseIsoToMs2(event.startedAt);
1503
+ if (!started.invalidTimestamp) {
1504
+ attrs.startedAtMs = started.ms;
1505
+ out.timestamp = started.ms;
1506
+ }
1507
+ }
1508
+ if (event.endedAt !== void 0) {
1509
+ const ended = parseIsoToMs2(event.endedAt);
1510
+ if (!ended.invalidTimestamp) {
1511
+ attrs.endedAtMs = ended.ms;
1512
+ if (out.durationMs === void 0 && typeof attrs.startedAtMs === "number" && ended.ms >= attrs.startedAtMs) {
1513
+ out.durationMs = ended.ms - attrs.startedAtMs;
1514
+ }
1515
+ }
1516
+ }
1517
+ out.attributes = compactAttributes2(attrs);
1171
1518
  return out;
1172
1519
  }
1173
1520
  function persistedInspectEventsToInspectEvents(events, options) {
@@ -1186,66 +1533,18 @@ function persistedInspectEventsToInspectEvents(events, options) {
1186
1533
  }
1187
1534
 
1188
1535
  // packages/core/src/persisted/tree-bridge.ts
1536
+ function logicalToPersisted(event) {
1537
+ const { sourceEventIds: _sourceEventIds, projection: _projection, ...rest } = event;
1538
+ return rest;
1539
+ }
1189
1540
  function persistedInspectEventsToRunTrees(events, options) {
1190
- const inspectEvents = persistedInspectEventsToInspectEvents(events, {
1541
+ const sourceEvents = options?.coalesceLifecycle === true ? projectLogicalEvents(events).logicalEvents.map(logicalToPersisted) : events;
1542
+ const inspectEvents = persistedInspectEventsToInspectEvents(sourceEvents, {
1191
1543
  skipInvalid: options?.skipInvalid
1192
1544
  });
1193
1545
  return new TreeBuilder().build(inspectEvents);
1194
1546
  }
1195
1547
 
1196
- // packages/core/src/diagnostics/programmatic.ts
1197
- var PROGRAMMATIC_DIAGNOSTIC_SPECS = Object.freeze({
1198
- AI_TRACE_INPUT_INVALID: {
1199
- code: "AI_TRACE_INPUT_INVALID",
1200
- summary: 'Expected { type: "file", path }, { type: "directory", path }, { type: "string", content }, { type: "buffer", content }, or { type: "stdin" }.',
1201
- remediation: "For a file path, use openTraceFile(path).",
1202
- relatedCodes: ["invalid_input"]
1203
- },
1204
- AI_TRACE_FORMAT_UNSUPPORTED: {
1205
- code: "AI_TRACE_FORMAT_UNSUPPORTED",
1206
- summary: "No trace reader could detect the input format.",
1207
- remediation: "Pass an AgentInspect JSONL file via openTraceFile, or set options.format to a registered reader.",
1208
- relatedCodes: ["unsupported_format"]
1209
- },
1210
- AI_TRACE_FORMAT_AMBIGUOUS: {
1211
- code: "AI_TRACE_FORMAT_AMBIGUOUS",
1212
- summary: "Multiple trace readers matched the input with equal confidence.",
1213
- remediation: "Set options.format explicitly to disambiguate the reader.",
1214
- relatedCodes: ["ambiguous_format"]
1215
- },
1216
- AI_TRACE_FACTS_INPUT_NOT_NORMALIZED: {
1217
- code: "AI_TRACE_FACTS_INPUT_NOT_NORMALIZED",
1218
- summary: "TraceFacts requires TraceReadResult or PersistedInspectEvent[].",
1219
- remediation: "Use openTraceFile() to normalize a JSONL trace first."
1220
- },
1221
- AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED: {
1222
- code: "AI_TRACE_CONTRACT_RUN_SELECTION_REQUIRED",
1223
- summary: "Multiple runs are available; select a run before executing checks.",
1224
- remediation: "Pass options.runId or TraceCheckInput.selectedRun.",
1225
- relatedCodes: ["AI_CHECK_RUN_SELECTION_REQUIRED"]
1226
- },
1227
- AI_TRACE_RELATIONSHIP_SELF_PARENT: {
1228
- code: "AI_TRACE_RELATIONSHIP_SELF_PARENT",
1229
- summary: "A parentId equals its own event/step id.",
1230
- remediation: "Reject at capture (AI_LANGGRAPH_SELF_PARENT_REJECTED) or drop via logical projection; do not invent replacement parents.",
1231
- relatedCodes: [
1232
- "AI_LANGGRAPH_SELF_PARENT_REJECTED",
1233
- "AI_LOGICAL_SELF_PARENT_REMOVED"
1234
- ]
1235
- },
1236
- AI_TRACE_RELATIONSHIP_CYCLE: {
1237
- code: "AI_TRACE_RELATIONSHIP_CYCLE",
1238
- summary: "Trace contains a parentId cycle.",
1239
- remediation: "Use visibility-first tree linking for legacy fixtures; prefer acyclic capture for new adapter output.",
1240
- relatedCodes: ["structure.cycle"]
1241
- }
1242
- });
1243
- function formatProgrammaticDiagnostic(code, detail) {
1244
- const spec = PROGRAMMATIC_DIAGNOSTIC_SPECS[code];
1245
- const summary = detail?.trim() ? detail.trim() : spec.summary;
1246
- return `${code}: ${summary} Remediation: ${spec.remediation}`;
1247
- }
1248
-
1249
1548
  // packages/core/src/readers/mapping-ledger.ts
1250
1549
  var OPENINFERENCE_MAPPING_LEDGER = {
1251
1550
  id: "openinference-to-agent-inspect",
@@ -1651,7 +1950,7 @@ function persistedEventsForParsedTrace(parsed) {
1651
1950
  sourceName: "agent-inspect-jsonl-reader"
1652
1951
  });
1653
1952
  }
1654
- function isRecord5(value) {
1953
+ function isRecord6(value) {
1655
1954
  return typeof value === "object" && value !== null && !Array.isArray(value);
1656
1955
  }
1657
1956
  function isNonEmptyString3(value) {
@@ -1666,13 +1965,13 @@ function readStringField(record, keys) {
1666
1965
  }
1667
1966
  function readRecordField(record, key) {
1668
1967
  const value = record[key];
1669
- return isRecord5(value) ? value : void 0;
1968
+ return isRecord6(value) ? value : void 0;
1670
1969
  }
1671
1970
  function parseJsonDocument(content) {
1672
1971
  return JSON.parse(content);
1673
1972
  }
1674
1973
  function looksLikeOpenInferenceSpan(value) {
1675
- if (!isRecord5(value)) return false;
1974
+ if (!isRecord6(value)) return false;
1676
1975
  const attributes = readRecordField(value, "attributes");
1677
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);
1678
1977
  }
@@ -1697,7 +1996,7 @@ function extractOpenInferenceDocument(root) {
1697
1996
  unsupportedFields
1698
1997
  };
1699
1998
  }
1700
- if (!isRecord5(root)) return void 0;
1999
+ if (!isRecord6(root)) return void 0;
1701
2000
  const rootFormat = root.format;
1702
2001
  const rootCompatibility = root.compatibility;
1703
2002
  const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
@@ -1837,7 +2136,7 @@ function summarizeAttributeValue(value) {
1837
2136
  if (Array.isArray(value)) {
1838
2137
  return { type: "array", length: value.length };
1839
2138
  }
1840
- if (isRecord5(value)) {
2139
+ if (isRecord6(value)) {
1841
2140
  return { type: "object", keyCount: Object.keys(value).length };
1842
2141
  }
1843
2142
  if (value === null) {
@@ -1924,7 +2223,7 @@ function mapOpenInferenceKind(span, attributes, pathPrefix) {
1924
2223
  }
1925
2224
  }
1926
2225
  function mapOpenInferenceStatus(status) {
1927
- if (!isRecord5(status)) return void 0;
2226
+ if (!isRecord6(status)) return void 0;
1928
2227
  const rawCode = status.code;
1929
2228
  if (typeof rawCode !== "string") return void 0;
1930
2229
  switch (rawCode.toUpperCase()) {
@@ -2032,10 +2331,10 @@ function mapOpenInferenceSpan(span, index, version) {
2032
2331
  warnings.push(...kindWarnings);
2033
2332
  const status = mapOpenInferenceStatus(span.status);
2034
2333
  const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
2035
- 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;
2036
2335
  const event = {
2037
2336
  schemaVersion: "0.2",
2038
- 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}`,
2039
2338
  runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
2040
2339
  kind,
2041
2340
  name,
@@ -2086,12 +2385,16 @@ function mapOpenInferenceEvents(document) {
2086
2385
  const mapped = document.spans.map(
2087
2386
  (span, index) => mapOpenInferenceSpan(span, index, document.version)
2088
2387
  );
2089
- const spanIdToEventId = new Map(
2090
- 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
+ })
2091
2393
  );
2092
2394
  for (const span of mapped) {
2093
2395
  if (span.parentSpanId === void 0) continue;
2094
- 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;
2095
2398
  }
2096
2399
  return {
2097
2400
  events: mapped.map((span) => span.event),
@@ -2178,7 +2481,7 @@ var openInferenceJsonReader = {
2178
2481
  }
2179
2482
  };
2180
2483
  function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
2181
- if (!isRecord5(value)) {
2484
+ if (!isRecord6(value)) {
2182
2485
  unsupportedFields.push(field);
2183
2486
  warnings.push({
2184
2487
  code: "otlp_attribute_value_invalid",
@@ -2200,15 +2503,15 @@ function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
2200
2503
  if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
2201
2504
  return value.doubleValue;
2202
2505
  }
2203
- if (isRecord5(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
2506
+ if (isRecord6(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
2204
2507
  return value.arrayValue.values.map(
2205
2508
  (item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
2206
2509
  );
2207
2510
  }
2208
- if (isRecord5(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
2511
+ if (isRecord6(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
2209
2512
  const out = {};
2210
2513
  for (const [index, item] of value.kvlistValue.values.entries()) {
2211
- if (!isRecord5(item) || typeof item.key !== "string") {
2514
+ if (!isRecord6(item) || typeof item.key !== "string") {
2212
2515
  unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
2213
2516
  continue;
2214
2517
  }
@@ -2259,7 +2562,7 @@ function parseOtlpAttributes(value, pathPrefix) {
2259
2562
  }
2260
2563
  for (const [index, item] of value.entries()) {
2261
2564
  const field = `${pathPrefix}[${index}]`;
2262
- if (!isRecord5(item) || typeof item.key !== "string") {
2565
+ if (!isRecord6(item) || typeof item.key !== "string") {
2263
2566
  unsupportedFields.push(field);
2264
2567
  warnings.push({
2265
2568
  code: "otlp_attribute_invalid",
@@ -2282,16 +2585,16 @@ function parseOtlpAttributes(value, pathPrefix) {
2282
2585
  return { attributes, warnings, unsupportedFields };
2283
2586
  }
2284
2587
  function looksLikeOtlpSpan(value) {
2285
- 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;
2286
2589
  }
2287
2590
  function extractOtlpDocument(root) {
2288
- if (!isRecord5(root) || !Array.isArray(root.resourceSpans)) return void 0;
2591
+ if (!isRecord6(root) || !Array.isArray(root.resourceSpans)) return void 0;
2289
2592
  const spans = [];
2290
2593
  const warnings = [];
2291
2594
  const unsupportedFields = [];
2292
2595
  for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
2293
2596
  const resourcePath = `resourceSpans[${resourceIndex}]`;
2294
- if (!isRecord5(resourceSpan)) {
2597
+ if (!isRecord6(resourceSpan)) {
2295
2598
  unsupportedFields.push(resourcePath);
2296
2599
  continue;
2297
2600
  }
@@ -2314,7 +2617,7 @@ function extractOtlpDocument(root) {
2314
2617
  }
2315
2618
  for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
2316
2619
  const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
2317
- if (!isRecord5(scopeSpan)) {
2620
+ if (!isRecord6(scopeSpan)) {
2318
2621
  unsupportedFields.push(scopePath);
2319
2622
  continue;
2320
2623
  }
@@ -2381,22 +2684,40 @@ function extractOtlpDocument(root) {
2381
2684
  };
2382
2685
  }
2383
2686
  function mapOtlpStatus(status) {
2384
- if (!isRecord5(status)) return void 0;
2687
+ if (!isRecord6(status)) return void 0;
2385
2688
  const rawCode = status.code;
2386
- if (typeof rawCode !== "string") return void 0;
2387
- switch (rawCode.toUpperCase()) {
2388
- case "STATUS_CODE_OK":
2389
- case "OK":
2390
- return "ok";
2391
- case "STATUS_CODE_ERROR":
2392
- case "ERROR":
2393
- return "error";
2394
- case "STATUS_CODE_UNSET":
2395
- case "UNSET":
2396
- return "unknown";
2397
- default:
2398
- return "unknown";
2689
+ if (typeof rawCode === "number" && Number.isFinite(rawCode)) {
2690
+ switch (rawCode) {
2691
+ case 0:
2692
+ return "unknown";
2693
+ case 1:
2694
+ return "ok";
2695
+ case 2:
2696
+ return "error";
2697
+ default:
2698
+ return "unknown";
2699
+ }
2700
+ }
2701
+ if (typeof rawCode === "string") {
2702
+ const trimmed = rawCode.trim();
2703
+ if (/^\d+$/.test(trimmed)) {
2704
+ return mapOtlpStatus({ code: Number(trimmed) });
2705
+ }
2706
+ switch (trimmed.toUpperCase()) {
2707
+ case "STATUS_CODE_OK":
2708
+ case "OK":
2709
+ return "ok";
2710
+ case "STATUS_CODE_ERROR":
2711
+ case "ERROR":
2712
+ return "error";
2713
+ case "STATUS_CODE_UNSET":
2714
+ case "UNSET":
2715
+ return "unknown";
2716
+ default:
2717
+ return "unknown";
2718
+ }
2399
2719
  }
2720
+ return void 0;
2400
2721
  }
2401
2722
  function readOtlpKind(attributes, pathPrefix) {
2402
2723
  const warnings = [];
@@ -2481,7 +2802,7 @@ function mapOtlpEvents(value, pathPrefix) {
2481
2802
  const events = [];
2482
2803
  for (const [index, event] of value.entries()) {
2483
2804
  const eventPath = `${pathPrefix}[${index}]`;
2484
- if (!isRecord5(event)) {
2805
+ if (!isRecord6(event)) {
2485
2806
  unsupportedFields.push(eventPath);
2486
2807
  continue;
2487
2808
  }
@@ -2619,10 +2940,10 @@ function mapOtlpSpan(context) {
2619
2940
  warnings.push(...kindWarnings);
2620
2941
  const status = mapOtlpStatus(span.status);
2621
2942
  const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
2622
- 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;
2623
2944
  const event = {
2624
2945
  schemaVersion: "0.2",
2625
- 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}`,
2626
2947
  runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
2627
2948
  kind,
2628
2949
  name: readStringField(span, ["name"]) ?? spanId,
@@ -2671,12 +2992,16 @@ function mapOtlpSpan(context) {
2671
2992
  }
2672
2993
  function mapOtlpEventsToPersisted(document) {
2673
2994
  const mapped = document.spans.map((span) => mapOtlpSpan(span));
2674
- const spanIdToEventId = new Map(
2675
- 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
+ })
2676
3000
  );
2677
3001
  for (const span of mapped) {
2678
3002
  if (span.parentSpanId === void 0) continue;
2679
- 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;
2680
3005
  }
2681
3006
  return {
2682
3007
  events: mapped.map((span) => span.event),