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.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-QV73NM25.mjs → chunk-SWUZRRDT.mjs} +158 -21
- package/packages/cli/dist/chunk-SWUZRRDT.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +312 -52
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +156 -36
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-KFOBXFPN.mjs → src-XFIPYODW.mjs} +3 -3
- package/packages/cli/dist/{src-KFOBXFPN.mjs.map → src-XFIPYODW.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +200 -24
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +1 -1
- package/packages/core/dist/advanced.d.ts +1 -1
- package/packages/core/dist/advanced.mjs +89 -15
- package/packages/core/dist/advanced.mjs.map +1 -1
- package/packages/core/dist/checks.mjs +2 -2
- package/packages/core/dist/{chunk-LXYPM2ZO.mjs → chunk-2CCRUI42.mjs} +19 -318
- package/packages/core/dist/chunk-2CCRUI42.mjs.map +1 -0
- package/packages/core/dist/{chunk-QLYUWKK7.mjs → chunk-2IRRUNIN.mjs} +11 -5
- package/packages/core/dist/chunk-2IRRUNIN.mjs.map +1 -0
- package/packages/core/dist/{chunk-VQUB3WRI.mjs → chunk-3SPBELJB.mjs} +14 -3
- package/packages/core/dist/chunk-3SPBELJB.mjs.map +1 -0
- package/packages/core/dist/{chunk-3RV3JILQ.mjs → chunk-IJJSPJXV.mjs} +20 -12
- package/packages/core/dist/chunk-IJJSPJXV.mjs.map +1 -0
- package/packages/core/dist/chunk-L5WLVBW4.mjs +355 -0
- package/packages/core/dist/chunk-L5WLVBW4.mjs.map +1 -0
- package/packages/core/dist/exporters.cjs +110 -18
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +110 -18
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/index.cjs +12 -1
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.mjs +2 -2
- package/packages/core/dist/persisted.cjs +344 -9
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +8 -1
- package/packages/core/dist/persisted.d.ts +8 -1
- package/packages/core/dist/persisted.mjs +3 -2
- package/packages/core/dist/persisted.mjs.map +1 -1
- package/packages/core/dist/readers.cjs +377 -87
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.mjs +3 -3
- package/packages/cli/dist/chunk-QV73NM25.mjs.map +0 -1
- package/packages/core/dist/chunk-3RV3JILQ.mjs.map +0 -1
- package/packages/core/dist/chunk-FWK3Q3OJ.mjs +0 -56
- package/packages/core/dist/chunk-FWK3Q3OJ.mjs.map +0 -1
- package/packages/core/dist/chunk-LXYPM2ZO.mjs.map +0 -1
- package/packages/core/dist/chunk-QLYUWKK7.mjs.map +0 -1
- 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
|
|
434
|
-
if (
|
|
435
|
-
if (
|
|
436
|
-
if (
|
|
437
|
-
if (
|
|
438
|
-
if (
|
|
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
|
|
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
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
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 (!
|
|
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 =
|
|
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
|
|
2107
|
-
mapped.map((span) =>
|
|
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.
|
|
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 (!
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
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
|
|
2710
|
-
mapped.map((span) =>
|
|
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.
|
|
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),
|