agent-inspect 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +14 -4
- package/docs/ADAPTER-CONFORMANCE.md +35 -0
- package/docs/ADAPTERS.md +79 -1
- package/docs/API.md +184 -10
- package/docs/ARCHITECTURE.md +4 -0
- package/docs/CLI.md +41 -12
- package/docs/KNOWN-ISSUES.md +11 -1
- package/docs/LIMITATIONS.md +19 -2
- package/docs/SCHEMA.md +17 -7
- package/package.json +23 -2
- package/packages/cli/dist/index.cjs +2449 -157
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +2450 -158
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/core/dist/advanced.cjs +839 -18
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.d.cts +98 -3
- package/packages/core/dist/advanced.d.ts +98 -3
- package/packages/core/dist/advanced.mjs +7 -4
- package/packages/core/dist/chunk-57S5D6HR.mjs +655 -0
- package/packages/core/dist/chunk-57S5D6HR.mjs.map +1 -0
- package/packages/core/dist/chunk-6QSLZCBJ.mjs +743 -0
- package/packages/core/dist/chunk-6QSLZCBJ.mjs.map +1 -0
- package/packages/core/dist/chunk-6SZPTECC.mjs +342 -0
- package/packages/core/dist/chunk-6SZPTECC.mjs.map +1 -0
- package/packages/core/dist/{chunk-QX3ZMPUF.mjs → chunk-74XZ6N7Q.mjs} +13 -55
- package/packages/core/dist/chunk-74XZ6N7Q.mjs.map +1 -0
- package/packages/core/dist/{chunk-QPAU2TPA.mjs → chunk-HR7G62IE.mjs} +4 -4
- package/packages/core/dist/{chunk-QPAU2TPA.mjs.map → chunk-HR7G62IE.mjs.map} +1 -1
- package/packages/core/dist/chunk-S4YWKV4G.mjs +48 -0
- package/packages/core/dist/chunk-S4YWKV4G.mjs.map +1 -0
- package/packages/core/dist/chunk-TFLPUZ56.mjs +1571 -0
- package/packages/core/dist/chunk-TFLPUZ56.mjs.map +1 -0
- package/packages/core/dist/{chunk-Q6EPNB3V.mjs → chunk-TZISEVLQ.mjs} +34 -183
- package/packages/core/dist/chunk-TZISEVLQ.mjs.map +1 -0
- package/packages/core/dist/chunk-U2BGPESY.mjs +150 -0
- package/packages/core/dist/chunk-U2BGPESY.mjs.map +1 -0
- package/packages/core/dist/chunk-VTIB5MDK.mjs +304 -0
- package/packages/core/dist/chunk-VTIB5MDK.mjs.map +1 -0
- package/packages/core/dist/{chunk-5EMIZZXD.mjs → chunk-Y56BPA3B.mjs} +87 -4
- package/packages/core/dist/chunk-Y56BPA3B.mjs.map +1 -0
- package/packages/core/dist/diff.d.cts +3 -2
- package/packages/core/dist/diff.d.ts +3 -2
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.d.cts +3 -2
- package/packages/core/dist/exporters.d.ts +3 -2
- package/packages/core/dist/exporters.mjs +2 -2
- package/packages/core/dist/index.cjs +2975 -229
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.d.cts +27 -6
- package/packages/core/dist/index.d.ts +27 -6
- package/packages/core/dist/index.mjs +113 -60
- package/packages/core/dist/index.mjs.map +1 -1
- package/packages/core/dist/{log-config-BzGmDYum.d.cts → inspect-event-Des4JDHo.d.cts} +1 -31
- package/packages/core/dist/{log-config-BzGmDYum.d.ts → inspect-event-Des4JDHo.d.ts} +1 -31
- package/packages/core/dist/log-config-BnH8Ykcb.d.cts +33 -0
- package/packages/core/dist/log-config-C1GcJPIM.d.ts +33 -0
- package/packages/core/dist/logs.d.cts +3 -2
- package/packages/core/dist/logs.d.ts +3 -2
- package/packages/core/dist/logs.mjs +3 -3
- package/packages/core/dist/persisted-inspect-event-0kaRADsp.d.cts +56 -0
- package/packages/core/dist/persisted-inspect-event-DiFto0K2.d.ts +56 -0
- package/packages/core/dist/persisted.cjs +38 -40
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +6 -55
- package/packages/core/dist/persisted.d.ts +6 -55
- package/packages/core/dist/persisted.mjs +4 -2
- package/packages/core/dist/readers.cjs +2590 -0
- package/packages/core/dist/readers.cjs.map +1 -0
- package/packages/core/dist/readers.d.cts +80 -0
- package/packages/core/dist/readers.d.ts +80 -0
- package/packages/core/dist/readers.mjs +9 -0
- package/packages/core/dist/readers.mjs.map +1 -0
- package/packages/core/dist/{types-CNbheSdk.d.cts → types-DB8jB6Jg.d.cts} +7 -1
- package/packages/core/dist/{types-Bkt7LS01.d.ts → types-tSix7tfv.d.ts} +7 -1
- package/packages/core/dist/writers.cjs +997 -0
- package/packages/core/dist/writers.cjs.map +1 -0
- package/packages/core/dist/writers.d.cts +62 -0
- package/packages/core/dist/writers.d.ts +62 -0
- package/packages/core/dist/writers.mjs +9 -0
- package/packages/core/dist/writers.mjs.map +1 -0
- package/packages/core/dist/chunk-5EMIZZXD.mjs.map +0 -1
- package/packages/core/dist/chunk-Q6EPNB3V.mjs.map +0 -1
- package/packages/core/dist/chunk-QX3ZMPUF.mjs.map +0 -1
- package/packages/core/dist/chunk-XDBND27A.mjs +0 -975
- package/packages/core/dist/chunk-XDBND27A.mjs.map +0 -1
|
@@ -148,6 +148,7 @@ function isPersistedTokenUsage(value) {
|
|
|
148
148
|
if (!isOptionalNonNegativeNumber(value.input)) return false;
|
|
149
149
|
if (!isOptionalNonNegativeNumber(value.output)) return false;
|
|
150
150
|
if (!isOptionalNonNegativeNumber(value.total)) return false;
|
|
151
|
+
if (!isOptionalNonNegativeNumber(value.cached)) return false;
|
|
151
152
|
return true;
|
|
152
153
|
}
|
|
153
154
|
function isPersistedTraceContext(value) {
|
|
@@ -238,6 +239,32 @@ function buildRunStartedMetadata(options) {
|
|
|
238
239
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
239
240
|
}
|
|
240
241
|
|
|
242
|
+
// packages/core/src/persisted/token-usage.ts
|
|
243
|
+
function isRecord3(value) {
|
|
244
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
245
|
+
}
|
|
246
|
+
function nonNegativeFinite(value) {
|
|
247
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
248
|
+
}
|
|
249
|
+
function normalizeTokenUsage(value) {
|
|
250
|
+
if (!isRecord3(value)) return void 0;
|
|
251
|
+
const input = nonNegativeFinite(value.input);
|
|
252
|
+
const output = nonNegativeFinite(value.output);
|
|
253
|
+
const suppliedTotal = nonNegativeFinite(value.total);
|
|
254
|
+
const cached = nonNegativeFinite(value.cached);
|
|
255
|
+
const derivedTotal = input !== void 0 && output !== void 0 && Number.isFinite(input + output) ? input + output : void 0;
|
|
256
|
+
const total = suppliedTotal ?? derivedTotal;
|
|
257
|
+
if (input === void 0 && output === void 0 && total === void 0 && cached === void 0) {
|
|
258
|
+
return void 0;
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
...input !== void 0 ? { input } : {},
|
|
262
|
+
...output !== void 0 ? { output } : {},
|
|
263
|
+
...total !== void 0 ? { total } : {},
|
|
264
|
+
...cached !== void 0 ? { cached } : {}
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
241
268
|
// packages/core/src/persisted/from-trace-event.ts
|
|
242
269
|
function sanitizeIdPart(value) {
|
|
243
270
|
return value.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -310,22 +337,7 @@ function mapErrorInfo(error) {
|
|
|
310
337
|
return out;
|
|
311
338
|
}
|
|
312
339
|
function mapTokenUsageFromMetadata(metadata) {
|
|
313
|
-
|
|
314
|
-
if (!tokens || typeof tokens !== "object") {
|
|
315
|
-
return void 0;
|
|
316
|
-
}
|
|
317
|
-
const input = typeof tokens.input === "number" && Number.isFinite(tokens.input) && tokens.input >= 0 ? tokens.input : void 0;
|
|
318
|
-
const output = typeof tokens.output === "number" && Number.isFinite(tokens.output) && tokens.output >= 0 ? tokens.output : void 0;
|
|
319
|
-
if (input === void 0 && output === void 0) {
|
|
320
|
-
return void 0;
|
|
321
|
-
}
|
|
322
|
-
const usage = {};
|
|
323
|
-
if (input !== void 0) usage.input = input;
|
|
324
|
-
if (output !== void 0) usage.output = output;
|
|
325
|
-
if (input !== void 0 && output !== void 0) {
|
|
326
|
-
usage.total = input + output;
|
|
327
|
-
}
|
|
328
|
-
return usage;
|
|
340
|
+
return normalizeTokenUsage(metadata?.tokens);
|
|
329
341
|
}
|
|
330
342
|
function compactAttributes(entries) {
|
|
331
343
|
const out = {};
|
|
@@ -529,23 +541,7 @@ function mapInspectSourceToPersisted(source, options) {
|
|
|
529
541
|
}
|
|
530
542
|
}
|
|
531
543
|
function mapTokenUsageFromAttributes(attributes) {
|
|
532
|
-
|
|
533
|
-
if (!tokens || typeof tokens !== "object" || Array.isArray(tokens)) {
|
|
534
|
-
return void 0;
|
|
535
|
-
}
|
|
536
|
-
const rec = tokens;
|
|
537
|
-
const input = typeof rec.input === "number" && Number.isFinite(rec.input) && rec.input >= 0 ? rec.input : void 0;
|
|
538
|
-
const output = typeof rec.output === "number" && Number.isFinite(rec.output) && rec.output >= 0 ? rec.output : void 0;
|
|
539
|
-
if (input === void 0 && output === void 0) {
|
|
540
|
-
return void 0;
|
|
541
|
-
}
|
|
542
|
-
const usage = {};
|
|
543
|
-
if (input !== void 0) usage.input = input;
|
|
544
|
-
if (output !== void 0) usage.output = output;
|
|
545
|
-
if (input !== void 0 && output !== void 0) {
|
|
546
|
-
usage.total = input + output;
|
|
547
|
-
}
|
|
548
|
-
return usage;
|
|
544
|
+
return normalizeTokenUsage(attributes?.tokens);
|
|
549
545
|
}
|
|
550
546
|
function mapErrorFromAttributes(event) {
|
|
551
547
|
if (event.status !== "error" || !event.attributes) {
|
|
@@ -802,10 +798,10 @@ function mapPersistedStatusToRunStatus(status) {
|
|
|
802
798
|
return void 0;
|
|
803
799
|
}
|
|
804
800
|
}
|
|
805
|
-
function mapPersistedError(error) {
|
|
801
|
+
function mapPersistedError(error, attributes) {
|
|
806
802
|
if (!error?.message) return void 0;
|
|
807
803
|
const out = { message: error.message };
|
|
808
|
-
const stack = typeof
|
|
804
|
+
const stack = typeof attributes?.errorStack === "string" && attributes.errorStack.length > 0 ? attributes.errorStack : void 0;
|
|
809
805
|
if (stack) {
|
|
810
806
|
out.stack = stack;
|
|
811
807
|
}
|
|
@@ -819,7 +815,9 @@ function mapTokenUsageToMetadata(tokenUsage, attributes) {
|
|
|
819
815
|
if (tokenUsage) {
|
|
820
816
|
metadata.tokens = {
|
|
821
817
|
...tokenUsage.input !== void 0 ? { input: tokenUsage.input } : {},
|
|
822
|
-
...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {}
|
|
818
|
+
...tokenUsage.output !== void 0 ? { output: tokenUsage.output } : {},
|
|
819
|
+
...tokenUsage.total !== void 0 ? { total: tokenUsage.total } : {},
|
|
820
|
+
...tokenUsage.cached !== void 0 ? { cached: tokenUsage.cached } : {}
|
|
823
821
|
};
|
|
824
822
|
}
|
|
825
823
|
return Object.keys(metadata).length > 0 ? metadata : void 0;
|
|
@@ -892,7 +890,7 @@ function fromLegacyRunCompleted(event) {
|
|
|
892
890
|
endTime,
|
|
893
891
|
durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
|
|
894
892
|
};
|
|
895
|
-
const error = mapPersistedError(event.error);
|
|
893
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
896
894
|
if (error) out.error = error;
|
|
897
895
|
return out;
|
|
898
896
|
}
|
|
@@ -926,7 +924,7 @@ function fromLegacyStepCompleted(event) {
|
|
|
926
924
|
endTime,
|
|
927
925
|
durationMs: event.durationMs ?? Math.max(0, endTime - timestamp)
|
|
928
926
|
};
|
|
929
|
-
const error = mapPersistedError(event.error);
|
|
927
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
930
928
|
if (error) out.error = error;
|
|
931
929
|
return out;
|
|
932
930
|
}
|
|
@@ -957,7 +955,7 @@ function fromNativeRun(event) {
|
|
|
957
955
|
endTime,
|
|
958
956
|
durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
|
|
959
957
|
};
|
|
960
|
-
const error = mapPersistedError(event.error);
|
|
958
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
961
959
|
if (error) completed.error = error;
|
|
962
960
|
out.push(completed);
|
|
963
961
|
}
|
|
@@ -999,7 +997,7 @@ function fromNativeStep(event) {
|
|
|
999
997
|
endTime,
|
|
1000
998
|
durationMs: event.durationMs ?? Math.max(0, endTime - startTime)
|
|
1001
999
|
};
|
|
1002
|
-
const error = mapPersistedError(event.error);
|
|
1000
|
+
const error = mapPersistedError(event.error, event.attributes);
|
|
1003
1001
|
if (error) completed.error = error;
|
|
1004
1002
|
out.push(completed);
|
|
1005
1003
|
}
|
|
@@ -1092,7 +1090,7 @@ var TreeBuilder = class {
|
|
|
1092
1090
|
const startedAt = sorted.length > 0 ? sorted[0].timestamp : void 0;
|
|
1093
1091
|
const endedAt = sorted.length > 0 ? sorted[sorted.length - 1].timestamp : void 0;
|
|
1094
1092
|
const status = computeRunStatus(sorted);
|
|
1095
|
-
const
|
|
1093
|
+
const durationMs2 = startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt && status !== "running" ? endedAt - startedAt : void 0;
|
|
1096
1094
|
const name = sorted.find((e) => e.kind === "RUN")?.name;
|
|
1097
1095
|
out.push({
|
|
1098
1096
|
runId,
|
|
@@ -1100,7 +1098,7 @@ var TreeBuilder = class {
|
|
|
1100
1098
|
status,
|
|
1101
1099
|
startedAt,
|
|
1102
1100
|
endedAt: status === "running" ? void 0 : endedAt,
|
|
1103
|
-
durationMs,
|
|
1101
|
+
durationMs: durationMs2,
|
|
1104
1102
|
children: roots,
|
|
1105
1103
|
metadata: {
|
|
1106
1104
|
totalEvents: sorted.length,
|
|
@@ -1125,7 +1123,7 @@ function traceEventsToPersistedRunTrees(events) {
|
|
|
1125
1123
|
const persisted = traceEventsToPersistedInspectEvents(events);
|
|
1126
1124
|
return persistedInspectEventsToRunTrees(persisted);
|
|
1127
1125
|
}
|
|
1128
|
-
function
|
|
1126
|
+
function isRecord4(v) {
|
|
1129
1127
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1130
1128
|
}
|
|
1131
1129
|
function isNonEmptyStringArray(v) {
|
|
@@ -1137,7 +1135,7 @@ function validateRedact(redact) {
|
|
|
1137
1135
|
}
|
|
1138
1136
|
for (const r of redact) {
|
|
1139
1137
|
if (typeof r === "string") continue;
|
|
1140
|
-
if (!
|
|
1138
|
+
if (!isRecord4(r)) {
|
|
1141
1139
|
throw new Error("Invalid config: redact entries must be strings or objects");
|
|
1142
1140
|
}
|
|
1143
1141
|
if (typeof r.key !== "string" || r.key.trim() === "") {
|
|
@@ -1156,7 +1154,7 @@ function validateRedact(redact) {
|
|
|
1156
1154
|
}
|
|
1157
1155
|
}
|
|
1158
1156
|
function validateMappings(mappings) {
|
|
1159
|
-
if (!
|
|
1157
|
+
if (!isRecord4(mappings)) {
|
|
1160
1158
|
throw new Error("Invalid config: mappings must be an object");
|
|
1161
1159
|
}
|
|
1162
1160
|
}
|
|
@@ -1206,7 +1204,7 @@ async function loadLogIngestConfig(configPath) {
|
|
|
1206
1204
|
const msg = e instanceof Error ? e.message : String(e);
|
|
1207
1205
|
throw new Error(`Invalid JSON in config file: ${configPath} (${msg})`);
|
|
1208
1206
|
}
|
|
1209
|
-
if (!
|
|
1207
|
+
if (!isRecord4(parsed)) {
|
|
1210
1208
|
throw new Error("Invalid config: expected a JSON object at top-level");
|
|
1211
1209
|
}
|
|
1212
1210
|
const user = parsed;
|
|
@@ -1243,7 +1241,7 @@ async function loadLogIngestConfig(configPath) {
|
|
|
1243
1241
|
}
|
|
1244
1242
|
return mergeLogIngestConfig(DEFAULT_LOG_INGEST_CONFIG, user);
|
|
1245
1243
|
}
|
|
1246
|
-
function
|
|
1244
|
+
function isRecord5(v) {
|
|
1247
1245
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1248
1246
|
}
|
|
1249
1247
|
var JsonLogParser = class {
|
|
@@ -1268,7 +1266,7 @@ var JsonLogParser = class {
|
|
|
1268
1266
|
});
|
|
1269
1267
|
continue;
|
|
1270
1268
|
}
|
|
1271
|
-
if (!
|
|
1269
|
+
if (!isRecord5(parsed)) {
|
|
1272
1270
|
warnings.push({
|
|
1273
1271
|
code: "MALFORMED_JSON",
|
|
1274
1272
|
message: "JSON log line must be an object",
|
|
@@ -1299,7 +1297,7 @@ var JsonLogParser = class {
|
|
|
1299
1297
|
return this.parseLines(lines, filePath);
|
|
1300
1298
|
}
|
|
1301
1299
|
};
|
|
1302
|
-
function
|
|
1300
|
+
function isRecord6(v) {
|
|
1303
1301
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1304
1302
|
}
|
|
1305
1303
|
function findLastJsonObjectSubstring(line) {
|
|
@@ -1375,7 +1373,7 @@ var Log4jsParser = class {
|
|
|
1375
1373
|
});
|
|
1376
1374
|
continue;
|
|
1377
1375
|
}
|
|
1378
|
-
if (!
|
|
1376
|
+
if (!isRecord6(parsed)) {
|
|
1379
1377
|
warnings.push({
|
|
1380
1378
|
code: "UNSUPPORTED_LOG4JS_PAYLOAD",
|
|
1381
1379
|
message: "Embedded JSON payload must be an object",
|
|
@@ -1453,7 +1451,7 @@ var DEFAULT_REDACT_KEYS = [
|
|
|
1453
1451
|
"secret",
|
|
1454
1452
|
"email"
|
|
1455
1453
|
];
|
|
1456
|
-
function
|
|
1454
|
+
function isRecord7(v) {
|
|
1457
1455
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1458
1456
|
}
|
|
1459
1457
|
function toKey(s) {
|
|
@@ -1526,7 +1524,7 @@ var Redactor = class {
|
|
|
1526
1524
|
if (Array.isArray(value)) {
|
|
1527
1525
|
return value.map((v) => this.#redactNested(v));
|
|
1528
1526
|
}
|
|
1529
|
-
if (
|
|
1527
|
+
if (isRecord7(value)) {
|
|
1530
1528
|
const out = {};
|
|
1531
1529
|
for (const [k, v] of Object.entries(value)) {
|
|
1532
1530
|
out[k] = this.redactValue(k, v);
|
|
@@ -1654,13 +1652,13 @@ var EventNormalizer = class {
|
|
|
1654
1652
|
const timestampMissing = parsedTs === void 0;
|
|
1655
1653
|
const parentIdKey = cfg.parentIdKey;
|
|
1656
1654
|
const parentId = parentIdKey ? safeString(raw[parentIdKey]) : void 0;
|
|
1657
|
-
let
|
|
1655
|
+
let durationMs2;
|
|
1658
1656
|
const durationKey = cfg.durationKey;
|
|
1659
1657
|
if (durationKey) {
|
|
1660
1658
|
const v = raw[durationKey];
|
|
1661
|
-
if (isFiniteNumber(v))
|
|
1659
|
+
if (isFiniteNumber(v)) durationMs2 = v;
|
|
1662
1660
|
} else if (isFiniteNumber(raw.durationMs)) {
|
|
1663
|
-
|
|
1661
|
+
durationMs2 = raw.durationMs;
|
|
1664
1662
|
}
|
|
1665
1663
|
let status;
|
|
1666
1664
|
const statusKey = cfg.statusKey;
|
|
@@ -1707,7 +1705,7 @@ var EventNormalizer = class {
|
|
|
1707
1705
|
kind,
|
|
1708
1706
|
timestamp,
|
|
1709
1707
|
...status ? { status } : {},
|
|
1710
|
-
...
|
|
1708
|
+
...durationMs2 !== void 0 ? { durationMs: durationMs2 } : {},
|
|
1711
1709
|
...Object.keys(attributes).length > 0 ? { attributes } : {},
|
|
1712
1710
|
confidence,
|
|
1713
1711
|
source: {
|
|
@@ -2286,69 +2284,81 @@ function truncateStringForProfile(value, key, maxMetadataValueLength, maxPreview
|
|
|
2286
2284
|
}
|
|
2287
2285
|
|
|
2288
2286
|
// packages/core/src/read-trace.ts
|
|
2289
|
-
function
|
|
2287
|
+
function isRecord8(value) {
|
|
2290
2288
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2291
2289
|
}
|
|
2292
2290
|
function detectLineFormat(parsed) {
|
|
2293
|
-
if (!
|
|
2291
|
+
if (!isRecord8(parsed)) return "unknown";
|
|
2294
2292
|
if (parsed.schemaVersion === "0.1") return "0.1";
|
|
2295
2293
|
if (parsed.schemaVersion === "0.2") return "0.2";
|
|
2296
2294
|
return "unknown";
|
|
2297
2295
|
}
|
|
2298
2296
|
function parseTraceJsonl(raw, options = {}) {
|
|
2299
2297
|
const validate = options.validate ?? isTraceEvent;
|
|
2298
|
+
const emitWarning = (message) => {
|
|
2299
|
+
if (options.warnings !== false) warn(message);
|
|
2300
|
+
};
|
|
2300
2301
|
const persisted = [];
|
|
2301
2302
|
const traceEvents = [];
|
|
2303
|
+
const rows = [];
|
|
2304
|
+
let sourceEventCount = 0;
|
|
2302
2305
|
let saw01 = false;
|
|
2303
2306
|
let saw02 = false;
|
|
2307
|
+
let lineNumber = 0;
|
|
2304
2308
|
for (const line of raw.split(/\r?\n/)) {
|
|
2309
|
+
lineNumber += 1;
|
|
2305
2310
|
const trimmed = line.trim();
|
|
2306
2311
|
if (trimmed === "") continue;
|
|
2307
2312
|
let parsed;
|
|
2308
2313
|
try {
|
|
2309
2314
|
parsed = JSON.parse(trimmed);
|
|
2310
2315
|
} catch {
|
|
2311
|
-
|
|
2316
|
+
emitWarning("Skipped invalid JSON line in trace file");
|
|
2312
2317
|
continue;
|
|
2313
2318
|
}
|
|
2314
2319
|
const format2 = detectLineFormat(parsed);
|
|
2315
2320
|
if (format2 === "0.1") {
|
|
2316
2321
|
saw01 = true;
|
|
2317
2322
|
if (validate(parsed)) {
|
|
2323
|
+
sourceEventCount += 1;
|
|
2318
2324
|
traceEvents.push(parsed);
|
|
2325
|
+
rows.push({ format: "0.1", event: parsed, sourceLine: lineNumber });
|
|
2319
2326
|
} else {
|
|
2320
|
-
|
|
2327
|
+
emitWarning("Skipped invalid trace event line in trace file");
|
|
2321
2328
|
}
|
|
2322
2329
|
continue;
|
|
2323
2330
|
}
|
|
2324
2331
|
if (format2 === "0.2") {
|
|
2325
2332
|
saw02 = true;
|
|
2326
2333
|
if (isPersistedInspectEvent(parsed)) {
|
|
2334
|
+
sourceEventCount += 1;
|
|
2327
2335
|
persisted.push(parsed);
|
|
2336
|
+
rows.push({ format: "0.2", event: parsed, sourceLine: lineNumber });
|
|
2337
|
+
traceEvents.push(...persistedInspectEventToTraceEvents(parsed));
|
|
2328
2338
|
} else {
|
|
2329
|
-
|
|
2339
|
+
emitWarning("Skipped invalid persisted inspect event line in trace file");
|
|
2330
2340
|
}
|
|
2331
2341
|
continue;
|
|
2332
2342
|
}
|
|
2333
|
-
|
|
2343
|
+
emitWarning("Skipped trace line with unknown schemaVersion");
|
|
2334
2344
|
}
|
|
2335
2345
|
if (saw01 && saw02) {
|
|
2336
|
-
|
|
2346
|
+
emitWarning(
|
|
2347
|
+
"Trace file mixes schemaVersion 0.1 and 0.2 lines; normalizing all rows"
|
|
2348
|
+
);
|
|
2337
2349
|
}
|
|
2338
|
-
const converted = persisted.length > 0 ? persistedInspectEventsToTraceEvents(persisted) : [];
|
|
2339
|
-
const events = [...traceEvents, ...converted];
|
|
2340
2350
|
let format = "empty";
|
|
2341
2351
|
if (saw01 && saw02) format = "mixed";
|
|
2342
2352
|
else if (saw01) format = "0.1";
|
|
2343
2353
|
else if (saw02) format = "0.2";
|
|
2344
|
-
return { format, events, persisted };
|
|
2354
|
+
return { format, sourceEventCount, events: traceEvents, persisted, rows };
|
|
2345
2355
|
}
|
|
2346
2356
|
function unknownTraceFormatMessage() {
|
|
2347
2357
|
return "Unsupported trace format. Expected schemaVersion 0.1 (TraceEvent) or 0.2 (PersistedInspectEvent).";
|
|
2348
2358
|
}
|
|
2349
2359
|
|
|
2350
2360
|
// packages/core/src/storage.ts
|
|
2351
|
-
function
|
|
2361
|
+
function isRecord9(value) {
|
|
2352
2362
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2353
2363
|
}
|
|
2354
2364
|
function nonEmptyString(value) {
|
|
@@ -2359,7 +2369,7 @@ function finiteNumber(value) {
|
|
|
2359
2369
|
}
|
|
2360
2370
|
function optionalErrorInfo(value) {
|
|
2361
2371
|
if (value === void 0) return true;
|
|
2362
|
-
if (!
|
|
2372
|
+
if (!isRecord9(value)) return false;
|
|
2363
2373
|
if (typeof value.message !== "string") return false;
|
|
2364
2374
|
if ("stack" in value && value.stack !== void 0) {
|
|
2365
2375
|
if (typeof value.stack !== "string") return false;
|
|
@@ -2367,7 +2377,7 @@ function optionalErrorInfo(value) {
|
|
|
2367
2377
|
return true;
|
|
2368
2378
|
}
|
|
2369
2379
|
function validateEvent(event) {
|
|
2370
|
-
if (!
|
|
2380
|
+
if (!isRecord9(event)) return false;
|
|
2371
2381
|
if (event.schemaVersion !== "0.1") return false;
|
|
2372
2382
|
if (!finiteNumber(event.timestamp)) return false;
|
|
2373
2383
|
if (typeof event.event !== "string") return false;
|
|
@@ -2376,7 +2386,7 @@ function validateEvent(event) {
|
|
|
2376
2386
|
if (!nonEmptyString(event.runId) || !nonEmptyString(event.name) || !finiteNumber(event.startTime)) {
|
|
2377
2387
|
return false;
|
|
2378
2388
|
}
|
|
2379
|
-
if (event.metadata !== void 0 && !
|
|
2389
|
+
if (event.metadata !== void 0 && !isRecord9(event.metadata)) {
|
|
2380
2390
|
return false;
|
|
2381
2391
|
}
|
|
2382
2392
|
return true;
|
|
@@ -2391,7 +2401,7 @@ function validateEvent(event) {
|
|
|
2391
2401
|
if (event.parentId !== void 0 && typeof event.parentId !== "string") {
|
|
2392
2402
|
return false;
|
|
2393
2403
|
}
|
|
2394
|
-
if (event.metadata !== void 0 && !
|
|
2404
|
+
if (event.metadata !== void 0 && !isRecord9(event.metadata)) {
|
|
2395
2405
|
return false;
|
|
2396
2406
|
}
|
|
2397
2407
|
return true;
|
|
@@ -2482,16 +2492,25 @@ async function readTraceFile(runId, traceDir) {
|
|
|
2482
2492
|
}
|
|
2483
2493
|
async function readTraceEvents(runId, traceDir) {
|
|
2484
2494
|
try {
|
|
2485
|
-
const
|
|
2486
|
-
|
|
2487
|
-
return [];
|
|
2488
|
-
}
|
|
2489
|
-
return parseTraceJsonl(raw, { validate: validateEvent }).events;
|
|
2495
|
+
const filePath = getTraceFilePath(runId, traceDir);
|
|
2496
|
+
return await readTraceEventsFromFile(filePath);
|
|
2490
2497
|
} catch (e) {
|
|
2491
2498
|
warn("Failed to read trace events", e);
|
|
2492
2499
|
return [];
|
|
2493
2500
|
}
|
|
2494
2501
|
}
|
|
2502
|
+
async function readTraceEventsFromFile(filePath) {
|
|
2503
|
+
try {
|
|
2504
|
+
const raw = await promises.readFile(filePath, "utf-8");
|
|
2505
|
+
return parseTraceJsonl(raw, { validate: validateEvent }).events;
|
|
2506
|
+
} catch (e) {
|
|
2507
|
+
if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
|
|
2508
|
+
return [];
|
|
2509
|
+
}
|
|
2510
|
+
warn("Failed to read trace events from file", e);
|
|
2511
|
+
return [];
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2495
2514
|
async function listTraceFiles(traceDir) {
|
|
2496
2515
|
try {
|
|
2497
2516
|
const usable = path__default.default.resolve(traceDir);
|
|
@@ -2531,7 +2550,7 @@ function getRunIdFromTraceFileName(fileName) {
|
|
|
2531
2550
|
var DEFAULT_MAX_METADATA_VALUE_LENGTH = 2e3;
|
|
2532
2551
|
var DEFAULT_MAX_PREVIEW_LENGTH = 500;
|
|
2533
2552
|
var DEFAULT_MAX_EVENT_BYTES = 65536;
|
|
2534
|
-
function
|
|
2553
|
+
function isRecord10(value) {
|
|
2535
2554
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2536
2555
|
}
|
|
2537
2556
|
function isPreviewKey2(key) {
|
|
@@ -2553,7 +2572,7 @@ function resolveTraceSafetyOptions(options) {
|
|
|
2553
2572
|
redactEnabled = false;
|
|
2554
2573
|
} else if (redact === true || redact === void 0) {
|
|
2555
2574
|
redactEnabled = true;
|
|
2556
|
-
} else if (
|
|
2575
|
+
} else if (isRecord10(redact)) {
|
|
2557
2576
|
redactEnabled = true;
|
|
2558
2577
|
redactionRules = redact.rules;
|
|
2559
2578
|
}
|
|
@@ -2584,6 +2603,21 @@ function resolveTraceSafetyOptions(options) {
|
|
|
2584
2603
|
}
|
|
2585
2604
|
function boundMetadataValue(key, value, opts, seen, depth) {
|
|
2586
2605
|
if (depth > 32) return "[MaxDepth]";
|
|
2606
|
+
if (typeof value === "bigint") {
|
|
2607
|
+
return `${value.toString()}n`;
|
|
2608
|
+
}
|
|
2609
|
+
if (typeof value === "function") {
|
|
2610
|
+
return "[Function]";
|
|
2611
|
+
}
|
|
2612
|
+
if (typeof value === "symbol") {
|
|
2613
|
+
return "[Symbol]";
|
|
2614
|
+
}
|
|
2615
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
2616
|
+
return String(value);
|
|
2617
|
+
}
|
|
2618
|
+
if (value === void 0) {
|
|
2619
|
+
return null;
|
|
2620
|
+
}
|
|
2587
2621
|
if (value === null || typeof value !== "object") {
|
|
2588
2622
|
if (typeof value === "string") {
|
|
2589
2623
|
const max = isPreviewKey2(key) ? opts.maxPreviewLength : opts.maxMetadataValueLength;
|
|
@@ -2605,8 +2639,12 @@ function boundMetadataValue(key, value, opts, seen, depth) {
|
|
|
2605
2639
|
}
|
|
2606
2640
|
const record = value;
|
|
2607
2641
|
const out = {};
|
|
2608
|
-
|
|
2609
|
-
|
|
2642
|
+
try {
|
|
2643
|
+
for (const [k, v] of Object.entries(record)) {
|
|
2644
|
+
out[k] = boundMetadataValue(k, v, opts, seen, depth + 1);
|
|
2645
|
+
}
|
|
2646
|
+
} catch {
|
|
2647
|
+
return { truncated: true, reason: "metadataEnumerationFailed" };
|
|
2610
2648
|
}
|
|
2611
2649
|
return out;
|
|
2612
2650
|
}
|
|
@@ -2620,16 +2658,25 @@ function redactMetadata(metadata, opts) {
|
|
|
2620
2658
|
}
|
|
2621
2659
|
function prepareMetadataForDisk(metadata, opts) {
|
|
2622
2660
|
try {
|
|
2623
|
-
const
|
|
2624
|
-
|
|
2661
|
+
const preBounded = boundMetadataValue(
|
|
2662
|
+
"metadata",
|
|
2663
|
+
metadata,
|
|
2664
|
+
opts,
|
|
2665
|
+
/* @__PURE__ */ new WeakSet(),
|
|
2666
|
+
0
|
|
2667
|
+
);
|
|
2668
|
+
const redacted = redactMetadata(
|
|
2669
|
+
isRecord10(preBounded) ? preBounded : {},
|
|
2670
|
+
opts
|
|
2671
|
+
);
|
|
2625
2672
|
const bounded = boundMetadataValue(
|
|
2626
2673
|
"metadata",
|
|
2627
2674
|
redacted,
|
|
2628
2675
|
opts,
|
|
2629
|
-
|
|
2676
|
+
/* @__PURE__ */ new WeakSet(),
|
|
2630
2677
|
0
|
|
2631
2678
|
);
|
|
2632
|
-
return
|
|
2679
|
+
return isRecord10(bounded) ? bounded : {};
|
|
2633
2680
|
} catch {
|
|
2634
2681
|
return { truncated: true, reason: "metadataPreparationFailed" };
|
|
2635
2682
|
}
|
|
@@ -2750,6 +2797,210 @@ function prepareTraceEventForDisk(event, opts) {
|
|
|
2750
2797
|
return event;
|
|
2751
2798
|
}
|
|
2752
2799
|
}
|
|
2800
|
+
function safeGet(record, key) {
|
|
2801
|
+
try {
|
|
2802
|
+
return record[key];
|
|
2803
|
+
} catch {
|
|
2804
|
+
return void 0;
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
function optionalBoundedString(value, _key, opts) {
|
|
2808
|
+
if (typeof value !== "string") return void 0;
|
|
2809
|
+
return truncateString(value, opts.maxMetadataValueLength);
|
|
2810
|
+
}
|
|
2811
|
+
function requiredBoundedString(value, key, opts) {
|
|
2812
|
+
const out = optionalBoundedString(value, key, opts);
|
|
2813
|
+
return out && out.length > 0 ? out : void 0;
|
|
2814
|
+
}
|
|
2815
|
+
function preparePersistedSummaryForDisk(key, value, opts) {
|
|
2816
|
+
try {
|
|
2817
|
+
const redactor = new Redactor({
|
|
2818
|
+
rules: opts.redactionRules,
|
|
2819
|
+
extraKeys: opts.profileExtraKeys
|
|
2820
|
+
});
|
|
2821
|
+
const redacted = opts.redactEnabled ? redactor.redactValue(key, value) : value;
|
|
2822
|
+
return boundMetadataValue(key, redacted, opts, /* @__PURE__ */ new WeakSet(), 0);
|
|
2823
|
+
} catch {
|
|
2824
|
+
return { truncated: true, reason: "summaryPreparationFailed" };
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
function preparePersistedErrorForDisk(value, opts) {
|
|
2828
|
+
if (!isRecord10(value)) return void 0;
|
|
2829
|
+
try {
|
|
2830
|
+
const redactor = new Redactor({
|
|
2831
|
+
rules: opts.redactionRules,
|
|
2832
|
+
extraKeys: opts.profileExtraKeys
|
|
2833
|
+
});
|
|
2834
|
+
const rawMessage = safeGet(value, "message");
|
|
2835
|
+
const redactedMessage = opts.redactEnabled ? redactor.redactValue("message", rawMessage) : rawMessage;
|
|
2836
|
+
const boundedMessage = boundMetadataValue(
|
|
2837
|
+
"message",
|
|
2838
|
+
redactedMessage,
|
|
2839
|
+
opts,
|
|
2840
|
+
/* @__PURE__ */ new WeakSet(),
|
|
2841
|
+
0
|
|
2842
|
+
);
|
|
2843
|
+
const message = typeof boundedMessage === "string" && boundedMessage.length > 0 ? boundedMessage : "Unknown error";
|
|
2844
|
+
const out = { message };
|
|
2845
|
+
const name = optionalBoundedString(safeGet(value, "name"), "name", opts);
|
|
2846
|
+
const code = optionalBoundedString(safeGet(value, "code"), "code", opts);
|
|
2847
|
+
if (name !== void 0) out.name = name;
|
|
2848
|
+
if (code !== void 0) out.code = code;
|
|
2849
|
+
return out;
|
|
2850
|
+
} catch {
|
|
2851
|
+
return { message: "Error preparation failed" };
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
function prepareTokenUsage(value) {
|
|
2855
|
+
if (!isRecord10(value)) return void 0;
|
|
2856
|
+
const out = {};
|
|
2857
|
+
for (const key of ["input", "output", "total", "cached"]) {
|
|
2858
|
+
const item = safeGet(value, key);
|
|
2859
|
+
if (typeof item === "number" && Number.isFinite(item) && item >= 0) {
|
|
2860
|
+
out[key] = item;
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2864
|
+
}
|
|
2865
|
+
function prepareTraceContext(value, opts) {
|
|
2866
|
+
if (!isRecord10(value)) return void 0;
|
|
2867
|
+
const out = {};
|
|
2868
|
+
const traceId = optionalBoundedString(safeGet(value, "traceId"), "traceId", opts);
|
|
2869
|
+
const spanId = optionalBoundedString(safeGet(value, "spanId"), "spanId", opts);
|
|
2870
|
+
const parentSpanId = optionalBoundedString(
|
|
2871
|
+
safeGet(value, "parentSpanId"),
|
|
2872
|
+
"parentSpanId",
|
|
2873
|
+
opts
|
|
2874
|
+
);
|
|
2875
|
+
if (traceId !== void 0) out.traceId = traceId;
|
|
2876
|
+
if (spanId !== void 0) out.spanId = spanId;
|
|
2877
|
+
if (parentSpanId !== void 0) out.parentSpanId = parentSpanId;
|
|
2878
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2879
|
+
}
|
|
2880
|
+
function serializedPersistedEvent(event) {
|
|
2881
|
+
try {
|
|
2882
|
+
return JSON.stringify(event);
|
|
2883
|
+
} catch {
|
|
2884
|
+
return void 0;
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
function persistedEventByteLength(event) {
|
|
2888
|
+
const serialized = serializedPersistedEvent(event);
|
|
2889
|
+
return serialized === void 0 ? void 0 : byteLength(serialized);
|
|
2890
|
+
}
|
|
2891
|
+
function minimalPersistedEvent(event, opts, originalApproxBytes) {
|
|
2892
|
+
return {
|
|
2893
|
+
schemaVersion: "0.2",
|
|
2894
|
+
eventId: truncateString(event.eventId, 128),
|
|
2895
|
+
runId: truncateString(event.runId, 128),
|
|
2896
|
+
kind: event.kind,
|
|
2897
|
+
name: truncateString(event.name, 128),
|
|
2898
|
+
...event.status !== void 0 ? { status: event.status } : {},
|
|
2899
|
+
timestamp: truncateString(event.timestamp, 128),
|
|
2900
|
+
confidence: event.confidence,
|
|
2901
|
+
source: {
|
|
2902
|
+
type: event.source.type,
|
|
2903
|
+
...event.source.name !== void 0 ? { name: truncateString(event.source.name, 128) } : {},
|
|
2904
|
+
...event.source.version !== void 0 ? { version: truncateString(event.source.version, 128) } : {}
|
|
2905
|
+
},
|
|
2906
|
+
attributes: {
|
|
2907
|
+
truncated: true,
|
|
2908
|
+
reason: "maxEventBytes",
|
|
2909
|
+
originalApproxBytes,
|
|
2910
|
+
maxEventBytes: opts.maxEventBytes
|
|
2911
|
+
}
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2914
|
+
function tinyPersistedEvent(event) {
|
|
2915
|
+
return {
|
|
2916
|
+
schemaVersion: "0.2",
|
|
2917
|
+
eventId: truncateString(event.eventId, 32),
|
|
2918
|
+
runId: truncateString(event.runId, 32),
|
|
2919
|
+
kind: event.kind,
|
|
2920
|
+
name: truncateString(event.name, 32),
|
|
2921
|
+
timestamp: truncateString(event.timestamp, 32),
|
|
2922
|
+
confidence: event.confidence,
|
|
2923
|
+
source: { type: event.source.type },
|
|
2924
|
+
attributes: { truncated: true, reason: "maxEventBytes" }
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2927
|
+
function enforcePersistedEventSize(event, opts) {
|
|
2928
|
+
const bytes = persistedEventByteLength(event);
|
|
2929
|
+
if (bytes === void 0) return void 0;
|
|
2930
|
+
if (bytes <= opts.maxEventBytes) return event;
|
|
2931
|
+
const minimal = minimalPersistedEvent(event, opts, bytes);
|
|
2932
|
+
const minimalBytes = persistedEventByteLength(minimal);
|
|
2933
|
+
if (minimalBytes !== void 0 && minimalBytes <= opts.maxEventBytes) {
|
|
2934
|
+
return minimal;
|
|
2935
|
+
}
|
|
2936
|
+
const tiny = tinyPersistedEvent(event);
|
|
2937
|
+
return isPersistedInspectEvent(tiny) ? tiny : void 0;
|
|
2938
|
+
}
|
|
2939
|
+
function preparePersistedInspectEventForWrite(value, opts = resolveTraceSafetyOptions()) {
|
|
2940
|
+
try {
|
|
2941
|
+
if (!isRecord10(value)) return void 0;
|
|
2942
|
+
const source = safeGet(value, "source");
|
|
2943
|
+
if (!isRecord10(source)) return void 0;
|
|
2944
|
+
const candidate = {
|
|
2945
|
+
schemaVersion: safeGet(value, "schemaVersion"),
|
|
2946
|
+
eventId: requiredBoundedString(safeGet(value, "eventId"), "eventId", opts) ?? "",
|
|
2947
|
+
runId: requiredBoundedString(safeGet(value, "runId"), "runId", opts) ?? "",
|
|
2948
|
+
kind: safeGet(value, "kind"),
|
|
2949
|
+
name: requiredBoundedString(safeGet(value, "name"), "name", opts) ?? "",
|
|
2950
|
+
timestamp: requiredBoundedString(safeGet(value, "timestamp"), "timestamp", opts) ?? "",
|
|
2951
|
+
confidence: safeGet(value, "confidence"),
|
|
2952
|
+
source: {
|
|
2953
|
+
type: safeGet(source, "type")
|
|
2954
|
+
}
|
|
2955
|
+
};
|
|
2956
|
+
const parentId = requiredBoundedString(safeGet(value, "parentId"), "parentId", opts);
|
|
2957
|
+
const status = safeGet(value, "status");
|
|
2958
|
+
const startedAt = optionalBoundedString(safeGet(value, "startedAt"), "startedAt", opts);
|
|
2959
|
+
const endedAt = optionalBoundedString(safeGet(value, "endedAt"), "endedAt", opts);
|
|
2960
|
+
const durationMs2 = safeGet(value, "durationMs");
|
|
2961
|
+
const sourceName = optionalBoundedString(safeGet(source, "name"), "name", opts);
|
|
2962
|
+
const sourceVersion = optionalBoundedString(safeGet(source, "version"), "version", opts);
|
|
2963
|
+
if (parentId !== void 0) candidate.parentId = parentId;
|
|
2964
|
+
if (status === "running" || status === "ok" || status === "error" || status === "unknown") {
|
|
2965
|
+
candidate.status = status;
|
|
2966
|
+
}
|
|
2967
|
+
if (startedAt !== void 0) candidate.startedAt = startedAt;
|
|
2968
|
+
if (endedAt !== void 0) candidate.endedAt = endedAt;
|
|
2969
|
+
if (typeof durationMs2 === "number" && Number.isFinite(durationMs2) && durationMs2 >= 0) {
|
|
2970
|
+
candidate.durationMs = durationMs2;
|
|
2971
|
+
}
|
|
2972
|
+
if (sourceName !== void 0) candidate.source.name = sourceName;
|
|
2973
|
+
if (sourceVersion !== void 0) candidate.source.version = sourceVersion;
|
|
2974
|
+
const attributes = safeGet(value, "attributes");
|
|
2975
|
+
if (isRecord10(attributes)) {
|
|
2976
|
+
candidate.attributes = prepareMetadataForDisk(attributes, opts);
|
|
2977
|
+
}
|
|
2978
|
+
if (safeGet(value, "inputSummary") !== void 0) {
|
|
2979
|
+
candidate.inputSummary = preparePersistedSummaryForDisk(
|
|
2980
|
+
"input",
|
|
2981
|
+
safeGet(value, "inputSummary"),
|
|
2982
|
+
opts
|
|
2983
|
+
);
|
|
2984
|
+
}
|
|
2985
|
+
if (safeGet(value, "outputSummary") !== void 0) {
|
|
2986
|
+
candidate.outputSummary = preparePersistedSummaryForDisk(
|
|
2987
|
+
"output",
|
|
2988
|
+
safeGet(value, "outputSummary"),
|
|
2989
|
+
opts
|
|
2990
|
+
);
|
|
2991
|
+
}
|
|
2992
|
+
const error = preparePersistedErrorForDisk(safeGet(value, "error"), opts);
|
|
2993
|
+
if (error !== void 0) candidate.error = error;
|
|
2994
|
+
const tokenUsage = prepareTokenUsage(safeGet(value, "tokenUsage"));
|
|
2995
|
+
if (tokenUsage !== void 0) candidate.tokenUsage = tokenUsage;
|
|
2996
|
+
const trace = prepareTraceContext(safeGet(value, "trace"), opts);
|
|
2997
|
+
if (trace !== void 0) candidate.trace = trace;
|
|
2998
|
+
if (!isPersistedInspectEvent(candidate)) return void 0;
|
|
2999
|
+
return enforcePersistedEventSize(candidate, opts);
|
|
3000
|
+
} catch {
|
|
3001
|
+
return void 0;
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
2753
3004
|
|
|
2754
3005
|
// packages/core/src/context.ts
|
|
2755
3006
|
var storage = new async_hooks.AsyncLocalStorage();
|
|
@@ -2934,12 +3185,10 @@ var TraceDirectory = class {
|
|
|
2934
3185
|
function isFiniteNumber2(v) {
|
|
2935
3186
|
return typeof v === "number" && Number.isFinite(v);
|
|
2936
3187
|
}
|
|
2937
|
-
function
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
return void 0;
|
|
2942
|
-
}
|
|
3188
|
+
function parseIsoToMs3(value) {
|
|
3189
|
+
if (value === void 0) return void 0;
|
|
3190
|
+
const parsed = Date.parse(value);
|
|
3191
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
2943
3192
|
}
|
|
2944
3193
|
async function extractMetadata(filePath, _quickScan) {
|
|
2945
3194
|
const stats = await promises.stat(filePath);
|
|
@@ -2948,8 +3197,7 @@ async function extractMetadata(filePath, _quickScan) {
|
|
|
2948
3197
|
runIdFromFile = runIdFromFile.slice(0, -".jsonl".length);
|
|
2949
3198
|
}
|
|
2950
3199
|
const raw = await promises.readFile(filePath, "utf-8");
|
|
2951
|
-
const
|
|
2952
|
-
let eventCount = 0;
|
|
3200
|
+
const parsedTrace = parseTraceJsonl(raw, { warnings: false });
|
|
2953
3201
|
let runId;
|
|
2954
3202
|
let name;
|
|
2955
3203
|
let startedAt;
|
|
@@ -2959,16 +3207,32 @@ async function extractMetadata(filePath, _quickScan) {
|
|
|
2959
3207
|
let hasRunCompleted = false;
|
|
2960
3208
|
let runCompletedStatus;
|
|
2961
3209
|
let anyStepError = false;
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
3210
|
+
const anyKnownEvent = parsedTrace.sourceEventCount > 0;
|
|
3211
|
+
let persistedStatus;
|
|
3212
|
+
const persistedRun = parsedTrace.persisted.find(
|
|
3213
|
+
(event) => event.kind === "RUN"
|
|
3214
|
+
);
|
|
3215
|
+
if (persistedRun) {
|
|
3216
|
+
runId = persistedRun.runId;
|
|
3217
|
+
if (persistedRun.name.trim() !== "") {
|
|
3218
|
+
name = persistedRun.name;
|
|
3219
|
+
}
|
|
3220
|
+
startedAt = parseIsoToMs3(persistedRun.startedAt) ?? parseIsoToMs3(persistedRun.timestamp);
|
|
3221
|
+
endedAt = parseIsoToMs3(persistedRun.endedAt);
|
|
3222
|
+
if (isFiniteNumber2(persistedRun.durationMs)) {
|
|
3223
|
+
explicitDurationMs = persistedRun.durationMs;
|
|
3224
|
+
if (endedAt === void 0 && startedAt !== void 0) {
|
|
3225
|
+
endedAt = startedAt + persistedRun.durationMs;
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
if (persistedRun.status === "ok") persistedStatus = "success";
|
|
3229
|
+
else if (persistedRun.status === "error") persistedStatus = "error";
|
|
3230
|
+
else if (persistedRun.status === "running") persistedStatus = "running";
|
|
3231
|
+
else if (persistedRun.status === "unknown") persistedStatus = "unknown";
|
|
3232
|
+
} else {
|
|
3233
|
+
runId = parsedTrace.persisted[0]?.runId;
|
|
3234
|
+
}
|
|
3235
|
+
for (const e of parsedTrace.events) {
|
|
2972
3236
|
if (runId === void 0 && typeof e.runId === "string") {
|
|
2973
3237
|
runId = e.runId;
|
|
2974
3238
|
}
|
|
@@ -3005,6 +3269,8 @@ async function extractMetadata(filePath, _quickScan) {
|
|
|
3005
3269
|
status = runCompletedStatus;
|
|
3006
3270
|
} else if (anyStepError) {
|
|
3007
3271
|
status = "error";
|
|
3272
|
+
} else if (persistedStatus !== void 0) {
|
|
3273
|
+
status = persistedStatus;
|
|
3008
3274
|
} else if (hasRunStarted && !hasRunCompleted) {
|
|
3009
3275
|
status = "running";
|
|
3010
3276
|
} else if (anyKnownEvent) {
|
|
@@ -3012,20 +3278,23 @@ async function extractMetadata(filePath, _quickScan) {
|
|
|
3012
3278
|
} else {
|
|
3013
3279
|
status = "unknown";
|
|
3014
3280
|
}
|
|
3015
|
-
const
|
|
3281
|
+
const durationMs2 = explicitDurationMs ?? (startedAt !== void 0 && endedAt !== void 0 && Number.isFinite(startedAt) && Number.isFinite(endedAt) && endedAt >= startedAt ? endedAt - startedAt : void 0);
|
|
3016
3282
|
return {
|
|
3017
3283
|
runId: resolvedRunId,
|
|
3018
3284
|
name,
|
|
3019
3285
|
status,
|
|
3020
3286
|
startedAt,
|
|
3021
3287
|
endedAt,
|
|
3022
|
-
durationMs,
|
|
3023
|
-
eventCount,
|
|
3288
|
+
durationMs: durationMs2,
|
|
3289
|
+
eventCount: parsedTrace.sourceEventCount,
|
|
3024
3290
|
filePath,
|
|
3025
3291
|
fileSize: stats.size,
|
|
3026
3292
|
createdAt: stats.birthtime
|
|
3027
3293
|
};
|
|
3028
3294
|
}
|
|
3295
|
+
function isNonNegativeFiniteNumber(value) {
|
|
3296
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
3297
|
+
}
|
|
3029
3298
|
function buildRunSummary(events) {
|
|
3030
3299
|
const started = events.find(
|
|
3031
3300
|
(e) => e.event === "run_started"
|
|
@@ -3037,7 +3306,7 @@ function buildRunSummary(events) {
|
|
|
3037
3306
|
const runId = started?.runId ?? events.find((e) => typeof e.runId === "string")?.runId ?? "unknown-run";
|
|
3038
3307
|
const name = typeof started?.name === "string" && started.name.trim() !== "" ? started.name : void 0;
|
|
3039
3308
|
const status = lastCompleted ? lastCompleted.status : started ? "running" : "unknown";
|
|
3040
|
-
const
|
|
3309
|
+
const durationMs2 = lastCompleted && isFiniteNumber2(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
3041
3310
|
started && isFiniteNumber2(started.startTime) ? started.startTime : void 0;
|
|
3042
3311
|
const steps = /* @__PURE__ */ new Map();
|
|
3043
3312
|
for (const e of events) {
|
|
@@ -3048,8 +3317,10 @@ function buildRunSummary(events) {
|
|
|
3048
3317
|
name: s.name,
|
|
3049
3318
|
status: "running",
|
|
3050
3319
|
parentId: s.parentId,
|
|
3051
|
-
tokensInput:
|
|
3052
|
-
tokensOutput:
|
|
3320
|
+
tokensInput: isNonNegativeFiniteNumber(s.metadata?.tokens?.input) ? s.metadata.tokens.input : void 0,
|
|
3321
|
+
tokensOutput: isNonNegativeFiniteNumber(s.metadata?.tokens?.output) ? s.metadata.tokens.output : void 0,
|
|
3322
|
+
tokensTotal: isNonNegativeFiniteNumber(s.metadata?.tokens?.total) ? s.metadata.tokens.total : void 0,
|
|
3323
|
+
tokensCached: isNonNegativeFiniteNumber(s.metadata?.tokens?.cached) ? s.metadata.tokens.cached : void 0
|
|
3053
3324
|
});
|
|
3054
3325
|
}
|
|
3055
3326
|
}
|
|
@@ -3071,7 +3342,11 @@ function buildRunSummary(events) {
|
|
|
3071
3342
|
let longestStep;
|
|
3072
3343
|
let totalTokensInput = 0;
|
|
3073
3344
|
let totalTokensOutput = 0;
|
|
3074
|
-
let
|
|
3345
|
+
let totalTokensTotal = 0;
|
|
3346
|
+
let totalTokensCached = 0;
|
|
3347
|
+
let tokenBearingSteps = 0;
|
|
3348
|
+
let stepsWithKnownTotal = 0;
|
|
3349
|
+
let hasCachedTokens = false;
|
|
3075
3350
|
const depthCache = /* @__PURE__ */ new Map();
|
|
3076
3351
|
const computeDepth = (stepId) => {
|
|
3077
3352
|
const cached = depthCache.get(stepId);
|
|
@@ -3100,17 +3375,28 @@ function buildRunSummary(events) {
|
|
|
3100
3375
|
longestStep = { name: s.name, durationMs: s.durationMs, type: s.type };
|
|
3101
3376
|
}
|
|
3102
3377
|
}
|
|
3103
|
-
if (
|
|
3104
|
-
|
|
3105
|
-
if (
|
|
3106
|
-
if (
|
|
3378
|
+
if (s.tokensInput !== void 0 || s.tokensOutput !== void 0 || s.tokensTotal !== void 0 || s.tokensCached !== void 0) {
|
|
3379
|
+
tokenBearingSteps += 1;
|
|
3380
|
+
if (s.tokensInput !== void 0) totalTokensInput += s.tokensInput;
|
|
3381
|
+
if (s.tokensOutput !== void 0) totalTokensOutput += s.tokensOutput;
|
|
3382
|
+
if (s.tokensTotal !== void 0) {
|
|
3383
|
+
totalTokensTotal += s.tokensTotal;
|
|
3384
|
+
stepsWithKnownTotal += 1;
|
|
3385
|
+
} else if (s.tokensInput !== void 0 && s.tokensOutput !== void 0) {
|
|
3386
|
+
totalTokensTotal += s.tokensInput + s.tokensOutput;
|
|
3387
|
+
stepsWithKnownTotal += 1;
|
|
3388
|
+
}
|
|
3389
|
+
if (s.tokensCached !== void 0) {
|
|
3390
|
+
totalTokensCached += s.tokensCached;
|
|
3391
|
+
hasCachedTokens = true;
|
|
3392
|
+
}
|
|
3107
3393
|
}
|
|
3108
3394
|
}
|
|
3109
3395
|
const summary = {
|
|
3110
3396
|
runId,
|
|
3111
3397
|
name,
|
|
3112
3398
|
status,
|
|
3113
|
-
durationMs,
|
|
3399
|
+
durationMs: durationMs2,
|
|
3114
3400
|
totalSteps,
|
|
3115
3401
|
llmSteps,
|
|
3116
3402
|
toolSteps,
|
|
@@ -3118,7 +3404,14 @@ function buildRunSummary(events) {
|
|
|
3118
3404
|
errorSteps,
|
|
3119
3405
|
maxDepth,
|
|
3120
3406
|
...longestStep ? { longestStep } : {},
|
|
3121
|
-
...
|
|
3407
|
+
...tokenBearingSteps > 0 ? {
|
|
3408
|
+
totalTokens: {
|
|
3409
|
+
input: totalTokensInput,
|
|
3410
|
+
output: totalTokensOutput,
|
|
3411
|
+
...stepsWithKnownTotal === tokenBearingSteps ? { total: totalTokensTotal } : {},
|
|
3412
|
+
...hasCachedTokens ? { cached: totalTokensCached } : {}
|
|
3413
|
+
}
|
|
3414
|
+
} : {}
|
|
3122
3415
|
};
|
|
3123
3416
|
return summary;
|
|
3124
3417
|
}
|
|
@@ -3423,9 +3716,17 @@ function renderRunWhat(summary, options = {}) {
|
|
|
3423
3716
|
`Status: ${summary.status} \xB7 Duration: ${duration} \xB7 Steps: ${summary.totalSteps} (${stepMixLine(summary)})`
|
|
3424
3717
|
);
|
|
3425
3718
|
if (summary.totalTokens) {
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3719
|
+
const tokenParts = [
|
|
3720
|
+
`${summary.totalTokens.input} in`,
|
|
3721
|
+
`${summary.totalTokens.output} out`
|
|
3722
|
+
];
|
|
3723
|
+
if (summary.totalTokens.total !== void 0) {
|
|
3724
|
+
tokenParts.push(`${summary.totalTokens.total} total`);
|
|
3725
|
+
}
|
|
3726
|
+
if (summary.totalTokens.cached !== void 0) {
|
|
3727
|
+
tokenParts.push(`${summary.totalTokens.cached} cached`);
|
|
3728
|
+
}
|
|
3729
|
+
lines.push(`Tokens: ${tokenParts.join(" / ")}`);
|
|
3429
3730
|
}
|
|
3430
3731
|
if (showCorrelation && summary.correlation) {
|
|
3431
3732
|
const parts = [];
|
|
@@ -3881,7 +4182,7 @@ function manualTraceEventsToRunTree(events) {
|
|
|
3881
4182
|
}
|
|
3882
4183
|
const startedAt = started.startTime;
|
|
3883
4184
|
const endedAt = lastCompleted !== void 0 && runStatus !== "running" ? lastCompleted.endTime : void 0;
|
|
3884
|
-
const
|
|
4185
|
+
const durationMs2 = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
3885
4186
|
const steps = /* @__PURE__ */ new Map();
|
|
3886
4187
|
for (const e of events) {
|
|
3887
4188
|
if (e.event !== "step_started") continue;
|
|
@@ -3970,7 +4271,7 @@ function manualTraceEventsToRunTree(events) {
|
|
|
3970
4271
|
status: runStatus,
|
|
3971
4272
|
startedAt,
|
|
3972
4273
|
endedAt,
|
|
3973
|
-
durationMs,
|
|
4274
|
+
durationMs: durationMs2,
|
|
3974
4275
|
children: roots,
|
|
3975
4276
|
metadata: {
|
|
3976
4277
|
totalEvents: inspectNodes.size,
|
|
@@ -3981,7 +4282,7 @@ function manualTraceEventsToRunTree(events) {
|
|
|
3981
4282
|
}
|
|
3982
4283
|
|
|
3983
4284
|
// packages/core/src/exporters/redact-export.ts
|
|
3984
|
-
function
|
|
4285
|
+
function isRecord11(value) {
|
|
3985
4286
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3986
4287
|
}
|
|
3987
4288
|
function deepClone(value) {
|
|
@@ -4055,7 +4356,7 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
|
|
|
4055
4356
|
0
|
|
4056
4357
|
);
|
|
4057
4358
|
const err = bounded.error;
|
|
4058
|
-
if (
|
|
4359
|
+
if (isRecord11(err) && typeof err.message === "string") {
|
|
4059
4360
|
bounded.error = {
|
|
4060
4361
|
...err,
|
|
4061
4362
|
message: truncateStringForProfile(
|
|
@@ -4076,6 +4377,89 @@ function redactEventAttributes(attrs, redactor, maxMetadataValueLength, maxPrevi
|
|
|
4076
4377
|
}
|
|
4077
4378
|
return bounded;
|
|
4078
4379
|
}
|
|
4380
|
+
function redactErrorInfo(error, redactor, maxMetadataValueLength, maxPreviewLength) {
|
|
4381
|
+
if (error === void 0) return void 0;
|
|
4382
|
+
const record = redactEventAttributes(
|
|
4383
|
+
{ error },
|
|
4384
|
+
redactor,
|
|
4385
|
+
maxMetadataValueLength,
|
|
4386
|
+
maxPreviewLength
|
|
4387
|
+
);
|
|
4388
|
+
const redacted = record?.error;
|
|
4389
|
+
if (!isRecord11(redacted) || typeof redacted.message !== "string") {
|
|
4390
|
+
return void 0;
|
|
4391
|
+
}
|
|
4392
|
+
return {
|
|
4393
|
+
message: redacted.message,
|
|
4394
|
+
...typeof redacted.stack === "string" ? { stack: redacted.stack } : {}
|
|
4395
|
+
};
|
|
4396
|
+
}
|
|
4397
|
+
function redactTraceEventsForReport(events, options) {
|
|
4398
|
+
const profile = options?.redactionProfile ?? "local";
|
|
4399
|
+
if (profile === "local") {
|
|
4400
|
+
return deepClone(events);
|
|
4401
|
+
}
|
|
4402
|
+
const resolved = resolveRedactionProfile(profile);
|
|
4403
|
+
const { maxMetadataValueLength, maxPreviewLength } = applyProfileMetadataCaps(
|
|
4404
|
+
2e3,
|
|
4405
|
+
500,
|
|
4406
|
+
resolved
|
|
4407
|
+
);
|
|
4408
|
+
const redactor = new Redactor({ extraKeys: resolved.extraKeys });
|
|
4409
|
+
return events.map((event) => {
|
|
4410
|
+
switch (event.event) {
|
|
4411
|
+
case "run_started":
|
|
4412
|
+
return {
|
|
4413
|
+
...event,
|
|
4414
|
+
name: truncateStringForProfile(
|
|
4415
|
+
event.name,
|
|
4416
|
+
"name",
|
|
4417
|
+
maxMetadataValueLength,
|
|
4418
|
+
maxPreviewLength
|
|
4419
|
+
),
|
|
4420
|
+
...event.metadata !== void 0 ? {
|
|
4421
|
+
metadata: redactEventAttributes(
|
|
4422
|
+
event.metadata,
|
|
4423
|
+
redactor,
|
|
4424
|
+
maxMetadataValueLength,
|
|
4425
|
+
maxPreviewLength
|
|
4426
|
+
)
|
|
4427
|
+
} : {}
|
|
4428
|
+
};
|
|
4429
|
+
case "step_started":
|
|
4430
|
+
return {
|
|
4431
|
+
...event,
|
|
4432
|
+
name: truncateStringForProfile(
|
|
4433
|
+
event.name,
|
|
4434
|
+
"name",
|
|
4435
|
+
maxMetadataValueLength,
|
|
4436
|
+
maxPreviewLength
|
|
4437
|
+
),
|
|
4438
|
+
...event.metadata !== void 0 ? {
|
|
4439
|
+
metadata: redactEventAttributes(
|
|
4440
|
+
event.metadata,
|
|
4441
|
+
redactor,
|
|
4442
|
+
maxMetadataValueLength,
|
|
4443
|
+
maxPreviewLength
|
|
4444
|
+
)
|
|
4445
|
+
} : {}
|
|
4446
|
+
};
|
|
4447
|
+
case "run_completed":
|
|
4448
|
+
case "step_completed":
|
|
4449
|
+
return {
|
|
4450
|
+
...event,
|
|
4451
|
+
...event.error !== void 0 ? {
|
|
4452
|
+
error: redactErrorInfo(
|
|
4453
|
+
event.error,
|
|
4454
|
+
redactor,
|
|
4455
|
+
maxMetadataValueLength,
|
|
4456
|
+
maxPreviewLength
|
|
4457
|
+
)
|
|
4458
|
+
} : {}
|
|
4459
|
+
};
|
|
4460
|
+
}
|
|
4461
|
+
});
|
|
4462
|
+
}
|
|
4079
4463
|
function redactRunTreeForExport(tree, options) {
|
|
4080
4464
|
const profile = options?.redactionProfile ?? "local";
|
|
4081
4465
|
if (profile === "local") {
|
|
@@ -4139,12 +4523,15 @@ footer{margin-top:2rem;font-size:0.85rem;color:#555}
|
|
|
4139
4523
|
`.trim();
|
|
4140
4524
|
function buildRunReport(events, options) {
|
|
4141
4525
|
const profile = options.redactionProfile ?? "local";
|
|
4142
|
-
const
|
|
4526
|
+
const safeEvents = redactTraceEventsForReport(events, {
|
|
4527
|
+
redactionProfile: profile
|
|
4528
|
+
});
|
|
4529
|
+
const whatSummary = buildRunWhatSummary(safeEvents);
|
|
4143
4530
|
const whatText = renderRunWhat(whatSummary, {
|
|
4144
4531
|
correlation: options.correlation !== false
|
|
4145
4532
|
});
|
|
4146
|
-
const timelineText = renderTimeline(buildRunTimeline(
|
|
4147
|
-
const tree = resolveTree(
|
|
4533
|
+
const timelineText = renderTimeline(buildRunTimeline(safeEvents));
|
|
4534
|
+
const tree = resolveTree(safeEvents, profile);
|
|
4148
4535
|
const exportOpts = {
|
|
4149
4536
|
includeMetadata: false,
|
|
4150
4537
|
includeAttributes: options.includeAttributes === true,
|
|
@@ -4225,6 +4612,8 @@ ${attrsSection}
|
|
|
4225
4612
|
fileExtension: ".html"
|
|
4226
4613
|
};
|
|
4227
4614
|
}
|
|
4615
|
+
|
|
4616
|
+
// packages/core/src/stats.ts
|
|
4228
4617
|
function percentile(sorted, p) {
|
|
4229
4618
|
if (sorted.length === 0) return void 0;
|
|
4230
4619
|
const idx = Math.min(
|
|
@@ -4235,19 +4624,10 @@ function percentile(sorted, p) {
|
|
|
4235
4624
|
}
|
|
4236
4625
|
async function readRunStartedMetadata(filePath) {
|
|
4237
4626
|
try {
|
|
4238
|
-
const
|
|
4239
|
-
for (const
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
let parsed;
|
|
4243
|
-
try {
|
|
4244
|
-
parsed = JSON.parse(trimmed);
|
|
4245
|
-
} catch {
|
|
4246
|
-
continue;
|
|
4247
|
-
}
|
|
4248
|
-
if (!isTraceEvent(parsed)) continue;
|
|
4249
|
-
if (parsed.event !== "run_started") continue;
|
|
4250
|
-
const rs = parsed;
|
|
4627
|
+
const events = await readTraceEventsFromFile(filePath);
|
|
4628
|
+
for (const event of events) {
|
|
4629
|
+
if (event.event !== "run_started") continue;
|
|
4630
|
+
const rs = event;
|
|
4251
4631
|
if (rs.metadata && typeof rs.metadata === "object") {
|
|
4252
4632
|
return rs.metadata;
|
|
4253
4633
|
}
|
|
@@ -4306,7 +4686,7 @@ async function buildTraceStats(metas, options) {
|
|
|
4306
4686
|
});
|
|
4307
4687
|
}
|
|
4308
4688
|
try {
|
|
4309
|
-
const events = await
|
|
4689
|
+
const events = await readTraceEventsFromFile(m.filePath);
|
|
4310
4690
|
if (events.length === 0) continue;
|
|
4311
4691
|
const summary = buildRunSummary(events);
|
|
4312
4692
|
totalSteps += summary.totalSteps;
|
|
@@ -4494,7 +4874,7 @@ async function searchTraces(metas, options) {
|
|
|
4494
4874
|
if (options.status && m.status !== options.status) continue;
|
|
4495
4875
|
let events = [];
|
|
4496
4876
|
try {
|
|
4497
|
-
events = await
|
|
4877
|
+
events = await readTraceEventsFromFile(m.filePath);
|
|
4498
4878
|
} catch {
|
|
4499
4879
|
continue;
|
|
4500
4880
|
}
|
|
@@ -4630,7 +5010,7 @@ var KNOWN_EVENTS = /* @__PURE__ */ new Set([
|
|
|
4630
5010
|
"step_started",
|
|
4631
5011
|
"step_completed"
|
|
4632
5012
|
]);
|
|
4633
|
-
function
|
|
5013
|
+
function isRecord12(value) {
|
|
4634
5014
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4635
5015
|
}
|
|
4636
5016
|
function safeParse(line) {
|
|
@@ -4652,7 +5032,7 @@ async function isAgentInspectTrace(filePath) {
|
|
|
4652
5032
|
if (trimmed === "") continue;
|
|
4653
5033
|
const parsed = safeParse(trimmed);
|
|
4654
5034
|
if (!parsed) continue;
|
|
4655
|
-
if (!
|
|
5035
|
+
if (!isRecord12(parsed)) continue;
|
|
4656
5036
|
checked += 1;
|
|
4657
5037
|
if (isTraceEvent(parsed)) return true;
|
|
4658
5038
|
const ev = parsed.event;
|
|
@@ -4667,64 +5047,2417 @@ async function isAgentInspectTrace(filePath) {
|
|
|
4667
5047
|
return false;
|
|
4668
5048
|
}
|
|
4669
5049
|
}
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
}
|
|
4678
|
-
function mapStepStatus2(s) {
|
|
4679
|
-
if (s === void 0) return "running";
|
|
4680
|
-
return s;
|
|
5050
|
+
function invoke2(fn) {
|
|
5051
|
+
return new Promise((resolve, reject) => {
|
|
5052
|
+
try {
|
|
5053
|
+
Promise.resolve(fn()).then(resolve, reject);
|
|
5054
|
+
} catch (error) {
|
|
5055
|
+
reject(error);
|
|
5056
|
+
}
|
|
5057
|
+
});
|
|
4681
5058
|
}
|
|
4682
|
-
function
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
throw new Error("Invalid trace: missing run_started");
|
|
5059
|
+
function normalizeError(error) {
|
|
5060
|
+
if (error instanceof Error && error.message.trim() !== "") {
|
|
5061
|
+
return error.message;
|
|
4686
5062
|
}
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
const completedAll = events.filter((e) => e.event === "run_completed");
|
|
4690
|
-
const lastCompleted = completedAll[completedAll.length - 1];
|
|
4691
|
-
let runStatus;
|
|
4692
|
-
if (lastCompleted === void 0) runStatus = "running";
|
|
4693
|
-
else runStatus = lastCompleted.status;
|
|
4694
|
-
const durationMs = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
4695
|
-
const steps = /* @__PURE__ */ new Map();
|
|
4696
|
-
let order = 0;
|
|
4697
|
-
for (const e of events) {
|
|
4698
|
-
if (e.event !== "step_started") continue;
|
|
4699
|
-
const s = e;
|
|
4700
|
-
const meta = s.metadata ? { ...s.metadata } : void 0;
|
|
4701
|
-
steps.set(s.stepId, {
|
|
4702
|
-
id: s.stepId,
|
|
4703
|
-
parentId: s.parentId,
|
|
4704
|
-
name: s.name,
|
|
4705
|
-
type: s.type,
|
|
4706
|
-
order: order++,
|
|
4707
|
-
timestamp: s.timestamp,
|
|
4708
|
-
metadata: meta
|
|
4709
|
-
});
|
|
5063
|
+
if (typeof error === "string" && error.trim() !== "") {
|
|
5064
|
+
return error;
|
|
4710
5065
|
}
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
5066
|
+
return "Unknown inspector runtime error";
|
|
5067
|
+
}
|
|
5068
|
+
var runtimeSequence = 0;
|
|
5069
|
+
function createRuntimeId() {
|
|
5070
|
+
runtimeSequence += 1;
|
|
5071
|
+
return `runtime_${runtimeSequence.toString(36)}`;
|
|
5072
|
+
}
|
|
5073
|
+
function publicContext(store) {
|
|
5074
|
+
return {
|
|
5075
|
+
runtimeId: store.runtimeId,
|
|
5076
|
+
runId: store.runId,
|
|
5077
|
+
runName: store.runName,
|
|
5078
|
+
traceDir: store.traceDir,
|
|
5079
|
+
silent: store.silent,
|
|
5080
|
+
metadata: store.metadata
|
|
5081
|
+
};
|
|
5082
|
+
}
|
|
5083
|
+
function createInspectorRuntime(options = {}) {
|
|
5084
|
+
const storage2 = new async_hooks.AsyncLocalStorage();
|
|
5085
|
+
const enabled = options.enabled ?? true;
|
|
5086
|
+
const runtimeId = createRuntimeId();
|
|
5087
|
+
const traceSafety = options.traceSafety ?? resolveTraceSafetyOptions();
|
|
5088
|
+
let closed = false;
|
|
5089
|
+
let instrumentationErrors = 0;
|
|
5090
|
+
let lastInstrumentationError;
|
|
5091
|
+
function recordInstrumentationError(error) {
|
|
5092
|
+
instrumentationErrors += 1;
|
|
5093
|
+
lastInstrumentationError = normalizeError(error);
|
|
5094
|
+
}
|
|
5095
|
+
function currentStore() {
|
|
5096
|
+
try {
|
|
5097
|
+
return storage2.getStore();
|
|
5098
|
+
} catch (error) {
|
|
5099
|
+
recordInstrumentationError(error);
|
|
5100
|
+
return void 0;
|
|
4721
5101
|
}
|
|
4722
5102
|
}
|
|
4723
|
-
const
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
5103
|
+
const runtime = {
|
|
5104
|
+
runtimeId,
|
|
5105
|
+
enabled,
|
|
5106
|
+
runWithContext(context, fn) {
|
|
5107
|
+
if (!enabled) return invoke2(fn);
|
|
5108
|
+
const store = {
|
|
5109
|
+
runtimeId,
|
|
5110
|
+
runId: context.runId,
|
|
5111
|
+
runName: context.runName,
|
|
5112
|
+
traceDir: context.traceDir,
|
|
5113
|
+
silent: context.silent,
|
|
5114
|
+
metadata: context.metadata,
|
|
5115
|
+
traceSafety,
|
|
5116
|
+
currentDepth: 0
|
|
5117
|
+
};
|
|
5118
|
+
return new Promise((resolve, reject) => {
|
|
5119
|
+
storage2.run(store, () => {
|
|
5120
|
+
invoke2(fn).then(resolve, reject);
|
|
5121
|
+
});
|
|
5122
|
+
});
|
|
5123
|
+
},
|
|
5124
|
+
runWithStepContext(stepId, fn) {
|
|
5125
|
+
if (!enabled) return invoke2(fn);
|
|
5126
|
+
const parent = currentStore();
|
|
5127
|
+
if (!parent) return invoke2(fn);
|
|
5128
|
+
const store = {
|
|
5129
|
+
runtimeId,
|
|
5130
|
+
runId: parent.runId,
|
|
5131
|
+
runName: parent.runName,
|
|
5132
|
+
traceDir: parent.traceDir,
|
|
5133
|
+
silent: parent.silent,
|
|
5134
|
+
metadata: parent.metadata,
|
|
5135
|
+
traceSafety: parent.traceSafety,
|
|
5136
|
+
currentStepId: stepId,
|
|
5137
|
+
currentDepth: parent.currentDepth + 1
|
|
5138
|
+
};
|
|
5139
|
+
return new Promise((resolve, reject) => {
|
|
5140
|
+
storage2.run(store, () => {
|
|
5141
|
+
invoke2(fn).then(resolve, reject);
|
|
5142
|
+
});
|
|
5143
|
+
});
|
|
5144
|
+
},
|
|
5145
|
+
getCurrentContext() {
|
|
5146
|
+
const store = currentStore();
|
|
5147
|
+
return store ? publicContext(store) : void 0;
|
|
5148
|
+
},
|
|
5149
|
+
getCurrentCorrelationMetadata() {
|
|
5150
|
+
return extractCorrelationMetadata(currentStore()?.metadata);
|
|
5151
|
+
},
|
|
5152
|
+
getCurrentStepId() {
|
|
5153
|
+
return currentStore()?.currentStepId;
|
|
5154
|
+
},
|
|
5155
|
+
getCurrentDepth() {
|
|
5156
|
+
const depth = currentStore()?.currentDepth;
|
|
5157
|
+
return typeof depth === "number" && Number.isFinite(depth) ? depth : 0;
|
|
5158
|
+
},
|
|
5159
|
+
getTraceSafety() {
|
|
5160
|
+
return traceSafety;
|
|
5161
|
+
},
|
|
5162
|
+
async write(event) {
|
|
5163
|
+
if (!enabled || closed || !options.writer) return;
|
|
5164
|
+
try {
|
|
5165
|
+
const safe = preparePersistedInspectEventForWrite(event, traceSafety);
|
|
5166
|
+
if (safe === void 0) {
|
|
5167
|
+
recordInstrumentationError("Invalid persisted inspect event");
|
|
5168
|
+
return;
|
|
5169
|
+
}
|
|
5170
|
+
await options.writer.write(safe);
|
|
5171
|
+
} catch (error) {
|
|
5172
|
+
recordInstrumentationError(error);
|
|
5173
|
+
}
|
|
5174
|
+
},
|
|
5175
|
+
async flush() {
|
|
5176
|
+
if (!options.writer) return;
|
|
5177
|
+
try {
|
|
5178
|
+
await options.writer.flush?.();
|
|
5179
|
+
} catch (error) {
|
|
5180
|
+
recordInstrumentationError(error);
|
|
5181
|
+
}
|
|
5182
|
+
},
|
|
5183
|
+
async close() {
|
|
5184
|
+
if (closed) return;
|
|
5185
|
+
try {
|
|
5186
|
+
await options.writer?.close?.();
|
|
5187
|
+
} catch (error) {
|
|
5188
|
+
recordInstrumentationError(error);
|
|
5189
|
+
} finally {
|
|
5190
|
+
closed = true;
|
|
5191
|
+
}
|
|
5192
|
+
},
|
|
5193
|
+
getDiagnostics() {
|
|
5194
|
+
const diagnostics = {
|
|
5195
|
+
instrumentationErrors
|
|
5196
|
+
};
|
|
5197
|
+
if (lastInstrumentationError !== void 0) {
|
|
5198
|
+
diagnostics.lastInstrumentationError = lastInstrumentationError;
|
|
5199
|
+
}
|
|
5200
|
+
const writerStats = options.writer?.getStats?.();
|
|
5201
|
+
if (writerStats !== void 0) {
|
|
5202
|
+
diagnostics.writerStats = writerStats;
|
|
5203
|
+
}
|
|
5204
|
+
return diagnostics;
|
|
5205
|
+
}
|
|
5206
|
+
};
|
|
5207
|
+
return runtime;
|
|
5208
|
+
}
|
|
5209
|
+
|
|
5210
|
+
// packages/core/src/inspector.ts
|
|
5211
|
+
function normalizeName(name, fallback) {
|
|
5212
|
+
if (typeof name !== "string" || name.trim() === "") return fallback;
|
|
5213
|
+
return truncateName(name.trim(), 100);
|
|
5214
|
+
}
|
|
5215
|
+
function nowIso() {
|
|
5216
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
5217
|
+
}
|
|
5218
|
+
function durationMs(startedAt, endedAt) {
|
|
5219
|
+
return Math.max(0, Date.parse(endedAt) - Date.parse(startedAt));
|
|
5220
|
+
}
|
|
5221
|
+
function mergeMetadata(base, override) {
|
|
5222
|
+
if (base === void 0 && override === void 0) return void 0;
|
|
5223
|
+
return {
|
|
5224
|
+
...base ?? {},
|
|
5225
|
+
...override ?? {}
|
|
5226
|
+
};
|
|
5227
|
+
}
|
|
5228
|
+
function toPersistedError(error) {
|
|
5229
|
+
if (error instanceof Error) {
|
|
5230
|
+
return {
|
|
5231
|
+
name: error.name,
|
|
5232
|
+
message: error.message
|
|
5233
|
+
};
|
|
5234
|
+
}
|
|
5235
|
+
if (typeof error === "string") {
|
|
5236
|
+
return { message: error };
|
|
5237
|
+
}
|
|
5238
|
+
return { message: "Unknown error" };
|
|
5239
|
+
}
|
|
5240
|
+
function summarizeValue(value) {
|
|
5241
|
+
if (value === null) return { type: "null" };
|
|
5242
|
+
if (Array.isArray(value)) return { type: "array", length: value.length };
|
|
5243
|
+
if (typeof value === "string") return { type: "string", length: value.length };
|
|
5244
|
+
if (typeof value === "number") {
|
|
5245
|
+
return { type: "number", finite: Number.isFinite(value) };
|
|
5246
|
+
}
|
|
5247
|
+
if (typeof value === "bigint") return { type: "bigint" };
|
|
5248
|
+
if (typeof value === "boolean") return { type: "boolean" };
|
|
5249
|
+
if (typeof value === "undefined") return { type: "undefined" };
|
|
5250
|
+
if (typeof value === "symbol") return { type: "symbol" };
|
|
5251
|
+
if (typeof value === "function") {
|
|
5252
|
+
return { type: "function", name: value.name || void 0 };
|
|
5253
|
+
}
|
|
5254
|
+
if (typeof value === "object") {
|
|
5255
|
+
const record = value;
|
|
5256
|
+
let keyCount;
|
|
5257
|
+
try {
|
|
5258
|
+
keyCount = Object.keys(record).length;
|
|
5259
|
+
} catch {
|
|
5260
|
+
keyCount = void 0;
|
|
5261
|
+
}
|
|
5262
|
+
return {
|
|
5263
|
+
type: "object",
|
|
5264
|
+
constructorName: value?.constructor?.name,
|
|
5265
|
+
...keyCount !== void 0 ? { keyCount } : {}
|
|
5266
|
+
};
|
|
5267
|
+
}
|
|
5268
|
+
return { type: typeof value };
|
|
5269
|
+
}
|
|
5270
|
+
function summarizeCapturedError(error) {
|
|
5271
|
+
if (error instanceof Error) {
|
|
5272
|
+
return { type: "error", name: error.name };
|
|
5273
|
+
}
|
|
5274
|
+
return summarizeValue(error);
|
|
5275
|
+
}
|
|
5276
|
+
function stepTypeToKind(type) {
|
|
5277
|
+
switch (type) {
|
|
5278
|
+
case "llm":
|
|
5279
|
+
return "LLM";
|
|
5280
|
+
case "tool":
|
|
5281
|
+
return "TOOL";
|
|
5282
|
+
case "decision":
|
|
5283
|
+
return "DECISION";
|
|
5284
|
+
case "run":
|
|
5285
|
+
return "RUN";
|
|
5286
|
+
default:
|
|
5287
|
+
return "LOGIC";
|
|
5288
|
+
}
|
|
5289
|
+
}
|
|
5290
|
+
function createInspector(options = {}) {
|
|
5291
|
+
const traceSafety = options.traceSafety ?? resolveTraceSafetyOptions({
|
|
5292
|
+
redactionProfile: options.redactionProfile
|
|
5293
|
+
});
|
|
5294
|
+
const runtime = createInspectorRuntime({
|
|
5295
|
+
enabled: options.enabled,
|
|
5296
|
+
writer: options.writer,
|
|
5297
|
+
traceSafety
|
|
5298
|
+
});
|
|
5299
|
+
async function write(event) {
|
|
5300
|
+
const safe = preparePersistedInspectEventForWrite(event, traceSafety);
|
|
5301
|
+
if (safe !== void 0) {
|
|
5302
|
+
await runtime.write(safe);
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
async function run(name, fn, runOptions = {}) {
|
|
5306
|
+
if (typeof fn !== "function") {
|
|
5307
|
+
throw new TypeError("inspector.run requires `fn` to be a function");
|
|
5308
|
+
}
|
|
5309
|
+
if (options.enabled === false) {
|
|
5310
|
+
return Promise.resolve(fn());
|
|
5311
|
+
}
|
|
5312
|
+
const runName = normalizeName(name, "unnamed-run");
|
|
5313
|
+
const runId = runOptions.runId ?? createRunId();
|
|
5314
|
+
const traceDir = runOptions.traceDir ?? options.traceDir ?? getDefaultTraceDir();
|
|
5315
|
+
const metadata = mergeMetadata(options.metadata, runOptions.metadata);
|
|
5316
|
+
const startedAt = nowIso();
|
|
5317
|
+
return runtime.runWithContext(
|
|
5318
|
+
{
|
|
5319
|
+
runId,
|
|
5320
|
+
runName,
|
|
5321
|
+
traceDir,
|
|
5322
|
+
silent: runOptions.silent ?? options.silent ?? true,
|
|
5323
|
+
metadata
|
|
5324
|
+
},
|
|
5325
|
+
async () => {
|
|
5326
|
+
await write({
|
|
5327
|
+
schemaVersion: "0.2",
|
|
5328
|
+
eventId: `${runId}_started`,
|
|
5329
|
+
runId,
|
|
5330
|
+
kind: "RUN",
|
|
5331
|
+
name: runName,
|
|
5332
|
+
status: "running",
|
|
5333
|
+
timestamp: startedAt,
|
|
5334
|
+
startedAt,
|
|
5335
|
+
confidence: "explicit",
|
|
5336
|
+
source: { type: "manual", name: "createInspector" },
|
|
5337
|
+
attributes: {
|
|
5338
|
+
legacyEvent: "run_started",
|
|
5339
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
5340
|
+
}
|
|
5341
|
+
});
|
|
5342
|
+
try {
|
|
5343
|
+
const result = await Promise.resolve(fn());
|
|
5344
|
+
const endedAt = nowIso();
|
|
5345
|
+
await write({
|
|
5346
|
+
schemaVersion: "0.2",
|
|
5347
|
+
eventId: `${runId}_completed`,
|
|
5348
|
+
runId,
|
|
5349
|
+
kind: "RUN",
|
|
5350
|
+
name: runName,
|
|
5351
|
+
status: "ok",
|
|
5352
|
+
timestamp: endedAt,
|
|
5353
|
+
endedAt,
|
|
5354
|
+
durationMs: durationMs(startedAt, endedAt),
|
|
5355
|
+
confidence: "explicit",
|
|
5356
|
+
source: { type: "manual", name: "createInspector" },
|
|
5357
|
+
attributes: { legacyEvent: "run_completed" },
|
|
5358
|
+
...options.capture?.onSuccess === "metadata-only" ? { outputSummary: summarizeValue(result) } : {}
|
|
5359
|
+
});
|
|
5360
|
+
return result;
|
|
5361
|
+
} catch (error) {
|
|
5362
|
+
const endedAt = nowIso();
|
|
5363
|
+
await write({
|
|
5364
|
+
schemaVersion: "0.2",
|
|
5365
|
+
eventId: `${runId}_completed`,
|
|
5366
|
+
runId,
|
|
5367
|
+
kind: "RUN",
|
|
5368
|
+
name: runName,
|
|
5369
|
+
status: "error",
|
|
5370
|
+
timestamp: endedAt,
|
|
5371
|
+
endedAt,
|
|
5372
|
+
durationMs: durationMs(startedAt, endedAt),
|
|
5373
|
+
confidence: "explicit",
|
|
5374
|
+
source: { type: "manual", name: "createInspector" },
|
|
5375
|
+
attributes: { legacyEvent: "run_completed" },
|
|
5376
|
+
...options.capture?.onError === "metadata-only" ? { outputSummary: summarizeCapturedError(error) } : {},
|
|
5377
|
+
error: toPersistedError(error)
|
|
5378
|
+
});
|
|
5379
|
+
throw error;
|
|
5380
|
+
}
|
|
5381
|
+
}
|
|
5382
|
+
);
|
|
5383
|
+
}
|
|
5384
|
+
async function step2(name, fn, stepOptions = {}) {
|
|
5385
|
+
if (typeof fn !== "function") {
|
|
5386
|
+
throw new TypeError("inspector.step requires `fn` to be a function");
|
|
5387
|
+
}
|
|
5388
|
+
if (options.enabled === false || !runtime.getCurrentContext()) {
|
|
5389
|
+
return Promise.resolve(fn());
|
|
5390
|
+
}
|
|
5391
|
+
const context = runtime.getCurrentContext();
|
|
5392
|
+
const stepName = normalizeName(name, "unnamed-step");
|
|
5393
|
+
const stepId = createStepId();
|
|
5394
|
+
const parentId = runtime.getCurrentStepId();
|
|
5395
|
+
const stepType = stepOptions.type ?? "logic";
|
|
5396
|
+
const startedAt = nowIso();
|
|
5397
|
+
const attributes = {
|
|
5398
|
+
legacyEvent: "step_started",
|
|
5399
|
+
stepId,
|
|
5400
|
+
stepType,
|
|
5401
|
+
...stepOptions.metadata !== void 0 ? { metadata: stepOptions.metadata } : {}
|
|
5402
|
+
};
|
|
5403
|
+
await write({
|
|
5404
|
+
schemaVersion: "0.2",
|
|
5405
|
+
eventId: `${stepId}_started`,
|
|
5406
|
+
runId: context.runId,
|
|
5407
|
+
...parentId !== void 0 ? { parentId } : {},
|
|
5408
|
+
kind: stepTypeToKind(stepType),
|
|
5409
|
+
name: stepName,
|
|
5410
|
+
status: "running",
|
|
5411
|
+
timestamp: startedAt,
|
|
5412
|
+
startedAt,
|
|
5413
|
+
confidence: "explicit",
|
|
5414
|
+
source: { type: "manual", name: "createInspector" },
|
|
5415
|
+
attributes
|
|
5416
|
+
});
|
|
5417
|
+
return runtime.runWithStepContext(stepId, async () => {
|
|
5418
|
+
try {
|
|
5419
|
+
const result = await Promise.resolve(fn());
|
|
5420
|
+
const endedAt = nowIso();
|
|
5421
|
+
await write({
|
|
5422
|
+
schemaVersion: "0.2",
|
|
5423
|
+
eventId: `${stepId}_completed`,
|
|
5424
|
+
runId: context.runId,
|
|
5425
|
+
kind: stepTypeToKind(stepType),
|
|
5426
|
+
name: stepName,
|
|
5427
|
+
status: "ok",
|
|
5428
|
+
timestamp: endedAt,
|
|
5429
|
+
endedAt,
|
|
5430
|
+
durationMs: durationMs(startedAt, endedAt),
|
|
5431
|
+
confidence: "explicit",
|
|
5432
|
+
source: { type: "manual", name: "createInspector" },
|
|
5433
|
+
attributes: {
|
|
5434
|
+
legacyEvent: "step_completed",
|
|
5435
|
+
stepId,
|
|
5436
|
+
stepType
|
|
5437
|
+
},
|
|
5438
|
+
...options.capture?.onSuccess === "metadata-only" ? { outputSummary: summarizeValue(result) } : {}
|
|
5439
|
+
});
|
|
5440
|
+
return result;
|
|
5441
|
+
} catch (error) {
|
|
5442
|
+
const endedAt = nowIso();
|
|
5443
|
+
await write({
|
|
5444
|
+
schemaVersion: "0.2",
|
|
5445
|
+
eventId: `${stepId}_completed`,
|
|
5446
|
+
runId: context.runId,
|
|
5447
|
+
kind: stepTypeToKind(stepType),
|
|
5448
|
+
name: stepName,
|
|
5449
|
+
status: "error",
|
|
5450
|
+
timestamp: endedAt,
|
|
5451
|
+
endedAt,
|
|
5452
|
+
durationMs: durationMs(startedAt, endedAt),
|
|
5453
|
+
confidence: "explicit",
|
|
5454
|
+
source: { type: "manual", name: "createInspector" },
|
|
5455
|
+
attributes: {
|
|
5456
|
+
legacyEvent: "step_completed",
|
|
5457
|
+
stepId,
|
|
5458
|
+
stepType
|
|
5459
|
+
},
|
|
5460
|
+
...options.capture?.onError === "metadata-only" ? { outputSummary: summarizeCapturedError(error) } : {},
|
|
5461
|
+
error: toPersistedError(error)
|
|
5462
|
+
});
|
|
5463
|
+
throw error;
|
|
5464
|
+
}
|
|
5465
|
+
});
|
|
5466
|
+
}
|
|
5467
|
+
const inspector = {
|
|
5468
|
+
runtime,
|
|
5469
|
+
run,
|
|
5470
|
+
step: step2,
|
|
5471
|
+
tool(name, fn, toolOptions) {
|
|
5472
|
+
const toolName = normalizeName(name, "unknown-tool");
|
|
5473
|
+
return step2(`tool:${toolName}`, fn, {
|
|
5474
|
+
...toolOptions,
|
|
5475
|
+
type: "tool",
|
|
5476
|
+
metadata: {
|
|
5477
|
+
...toolOptions?.metadata ?? {},
|
|
5478
|
+
toolName
|
|
5479
|
+
}
|
|
5480
|
+
});
|
|
5481
|
+
},
|
|
5482
|
+
llm(name, fn, llmOptions) {
|
|
5483
|
+
const model = normalizeName(name, "unknown-model");
|
|
5484
|
+
return step2(`llm:${model}`, fn, {
|
|
5485
|
+
...llmOptions,
|
|
5486
|
+
type: "llm",
|
|
5487
|
+
metadata: {
|
|
5488
|
+
...llmOptions?.metadata ?? {},
|
|
5489
|
+
model
|
|
5490
|
+
}
|
|
5491
|
+
});
|
|
5492
|
+
},
|
|
5493
|
+
observe(name, fn, observeOptions) {
|
|
5494
|
+
return async (...args) => step2(name, () => Promise.resolve(fn(...args)), observeOptions);
|
|
5495
|
+
},
|
|
5496
|
+
getDiagnostics() {
|
|
5497
|
+
return runtime.getDiagnostics();
|
|
5498
|
+
},
|
|
5499
|
+
flush() {
|
|
5500
|
+
return runtime.flush();
|
|
5501
|
+
},
|
|
5502
|
+
close() {
|
|
5503
|
+
return runtime.close();
|
|
5504
|
+
}
|
|
5505
|
+
};
|
|
5506
|
+
return inspector;
|
|
5507
|
+
}
|
|
5508
|
+
var DEFAULT_TRACE_SAFETY = resolveTraceSafetyOptions();
|
|
5509
|
+
function createInitialStats() {
|
|
5510
|
+
return {
|
|
5511
|
+
writtenEvents: 0,
|
|
5512
|
+
droppedEvents: 0,
|
|
5513
|
+
flushCount: 0
|
|
5514
|
+
};
|
|
5515
|
+
}
|
|
5516
|
+
function markFlush(stats) {
|
|
5517
|
+
stats.flushCount += 1;
|
|
5518
|
+
stats.lastFlushAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5519
|
+
}
|
|
5520
|
+
function cloneStats(stats) {
|
|
5521
|
+
return { ...stats };
|
|
5522
|
+
}
|
|
5523
|
+
function normalizeError2(error) {
|
|
5524
|
+
if (error instanceof Error && error.message.trim() !== "") {
|
|
5525
|
+
return error.message;
|
|
5526
|
+
}
|
|
5527
|
+
if (typeof error === "string" && error.trim() !== "") {
|
|
5528
|
+
return error;
|
|
5529
|
+
}
|
|
5530
|
+
return "Unknown trace writer error";
|
|
5531
|
+
}
|
|
5532
|
+
function recordDropped(stats, error) {
|
|
5533
|
+
stats.droppedEvents += 1;
|
|
5534
|
+
stats.lastError = normalizeError2(error);
|
|
5535
|
+
}
|
|
5536
|
+
function prepareWriterEvent(event) {
|
|
5537
|
+
return preparePersistedInspectEventForWrite(event, DEFAULT_TRACE_SAFETY);
|
|
5538
|
+
}
|
|
5539
|
+
function resolveFilePath(event, options) {
|
|
5540
|
+
if (options.filePath && options.filePath.trim() !== "") {
|
|
5541
|
+
return path__default.default.resolve(options.filePath);
|
|
5542
|
+
}
|
|
5543
|
+
return getTraceFilePath(event.runId, options.dir);
|
|
5544
|
+
}
|
|
5545
|
+
function serializeEvent2(event) {
|
|
5546
|
+
return `${JSON.stringify(event)}
|
|
5547
|
+
`;
|
|
5548
|
+
}
|
|
5549
|
+
async function appendEventLine(event, options) {
|
|
5550
|
+
const filePath = resolveFilePath(event, options);
|
|
5551
|
+
await promises.mkdir(path__default.default.dirname(filePath), { recursive: true });
|
|
5552
|
+
await promises.appendFile(filePath, serializeEvent2(event), "utf-8");
|
|
5553
|
+
}
|
|
5554
|
+
async function appendEventBatch(events, options) {
|
|
5555
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
5556
|
+
let dropped = 0;
|
|
5557
|
+
let lastError;
|
|
5558
|
+
for (const event of events) {
|
|
5559
|
+
try {
|
|
5560
|
+
const filePath = resolveFilePath(event, options);
|
|
5561
|
+
const line = serializeEvent2(event);
|
|
5562
|
+
const lines = byPath.get(filePath);
|
|
5563
|
+
if (lines) {
|
|
5564
|
+
lines.push(line);
|
|
5565
|
+
} else {
|
|
5566
|
+
byPath.set(filePath, [line]);
|
|
5567
|
+
}
|
|
5568
|
+
} catch (error) {
|
|
5569
|
+
dropped += 1;
|
|
5570
|
+
lastError = normalizeError2(error);
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
let written = 0;
|
|
5574
|
+
for (const [filePath, lines] of byPath) {
|
|
5575
|
+
try {
|
|
5576
|
+
await promises.mkdir(path__default.default.dirname(filePath), { recursive: true });
|
|
5577
|
+
await promises.appendFile(filePath, lines.join(""), "utf-8");
|
|
5578
|
+
written += lines.length;
|
|
5579
|
+
} catch (error) {
|
|
5580
|
+
dropped += lines.length;
|
|
5581
|
+
lastError = normalizeError2(error);
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
return lastError ? { written, dropped, lastError } : { written, dropped };
|
|
5585
|
+
}
|
|
5586
|
+
function memoryWriter() {
|
|
5587
|
+
const events = [];
|
|
5588
|
+
const stats = createInitialStats();
|
|
5589
|
+
return {
|
|
5590
|
+
async write(event) {
|
|
5591
|
+
const safe = prepareWriterEvent(event);
|
|
5592
|
+
if (safe === void 0) {
|
|
5593
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
5594
|
+
return;
|
|
5595
|
+
}
|
|
5596
|
+
events.push(safe);
|
|
5597
|
+
stats.writtenEvents += 1;
|
|
5598
|
+
},
|
|
5599
|
+
async flush() {
|
|
5600
|
+
markFlush(stats);
|
|
5601
|
+
},
|
|
5602
|
+
async close() {
|
|
5603
|
+
},
|
|
5604
|
+
getStats() {
|
|
5605
|
+
return cloneStats(stats);
|
|
5606
|
+
},
|
|
5607
|
+
getEvents() {
|
|
5608
|
+
return events.map((event) => structuredClone(event));
|
|
5609
|
+
},
|
|
5610
|
+
clear() {
|
|
5611
|
+
events.length = 0;
|
|
5612
|
+
}
|
|
5613
|
+
};
|
|
5614
|
+
}
|
|
5615
|
+
function nullWriter() {
|
|
5616
|
+
const stats = createInitialStats();
|
|
5617
|
+
return {
|
|
5618
|
+
async write() {
|
|
5619
|
+
stats.writtenEvents += 1;
|
|
5620
|
+
},
|
|
5621
|
+
async flush() {
|
|
5622
|
+
markFlush(stats);
|
|
5623
|
+
},
|
|
5624
|
+
async close() {
|
|
5625
|
+
},
|
|
5626
|
+
getStats() {
|
|
5627
|
+
return cloneStats(stats);
|
|
5628
|
+
}
|
|
5629
|
+
};
|
|
5630
|
+
}
|
|
5631
|
+
function fileWriter(options = {}) {
|
|
5632
|
+
const stats = createInitialStats();
|
|
5633
|
+
let closed = false;
|
|
5634
|
+
let queue = Promise.resolve();
|
|
5635
|
+
const enqueue = (event) => {
|
|
5636
|
+
const operation = queue.then(async () => {
|
|
5637
|
+
if (closed) {
|
|
5638
|
+
recordDropped(stats, "Trace writer is closed");
|
|
5639
|
+
return;
|
|
5640
|
+
}
|
|
5641
|
+
try {
|
|
5642
|
+
await appendEventLine(event, options);
|
|
5643
|
+
stats.writtenEvents += 1;
|
|
5644
|
+
} catch (error) {
|
|
5645
|
+
recordDropped(stats, error);
|
|
5646
|
+
}
|
|
5647
|
+
});
|
|
5648
|
+
queue = operation.catch(() => {
|
|
5649
|
+
});
|
|
5650
|
+
return operation.catch(() => {
|
|
5651
|
+
});
|
|
5652
|
+
};
|
|
5653
|
+
return {
|
|
5654
|
+
write(event) {
|
|
5655
|
+
const safe = prepareWriterEvent(event);
|
|
5656
|
+
if (safe === void 0) {
|
|
5657
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
5658
|
+
return Promise.resolve();
|
|
5659
|
+
}
|
|
5660
|
+
return enqueue(safe);
|
|
5661
|
+
},
|
|
5662
|
+
async flush() {
|
|
5663
|
+
await queue;
|
|
5664
|
+
markFlush(stats);
|
|
5665
|
+
},
|
|
5666
|
+
async close() {
|
|
5667
|
+
if (closed) return;
|
|
5668
|
+
await queue;
|
|
5669
|
+
closed = true;
|
|
5670
|
+
},
|
|
5671
|
+
getStats() {
|
|
5672
|
+
return cloneStats(stats);
|
|
5673
|
+
}
|
|
5674
|
+
};
|
|
5675
|
+
}
|
|
5676
|
+
function positiveInteger(value, fallback) {
|
|
5677
|
+
if (value === void 0) return fallback;
|
|
5678
|
+
if (!Number.isFinite(value) || value <= 0) return fallback;
|
|
5679
|
+
return Math.floor(value);
|
|
5680
|
+
}
|
|
5681
|
+
function nonNegativeInteger(value, fallback) {
|
|
5682
|
+
if (value === void 0) return fallback;
|
|
5683
|
+
if (!Number.isFinite(value) || value < 0) return fallback;
|
|
5684
|
+
return Math.floor(value);
|
|
5685
|
+
}
|
|
5686
|
+
function bufferedFileWriter(options = {}) {
|
|
5687
|
+
const stats = createInitialStats();
|
|
5688
|
+
const maxQueueSize = positiveInteger(options.maxQueueSize, 1e3);
|
|
5689
|
+
const flushIntervalMs = nonNegativeInteger(options.flushIntervalMs, 250);
|
|
5690
|
+
const maxBatchSize = positiveInteger(options.maxBatchSize, 100);
|
|
5691
|
+
const overflow = options.overflow ?? "drop-oldest";
|
|
5692
|
+
const pending = [];
|
|
5693
|
+
let closed = false;
|
|
5694
|
+
let timer;
|
|
5695
|
+
let chain = Promise.resolve();
|
|
5696
|
+
const clearTimer = () => {
|
|
5697
|
+
if (timer !== void 0) {
|
|
5698
|
+
clearTimeout(timer);
|
|
5699
|
+
timer = void 0;
|
|
5700
|
+
}
|
|
5701
|
+
};
|
|
5702
|
+
const scheduleFlush = () => {
|
|
5703
|
+
if (closed || timer !== void 0 || pending.length === 0) return;
|
|
5704
|
+
timer = setTimeout(() => {
|
|
5705
|
+
timer = void 0;
|
|
5706
|
+
void drain(false);
|
|
5707
|
+
}, flushIntervalMs);
|
|
5708
|
+
if (timer && typeof timer === "object" && "unref" in timer && typeof timer.unref === "function") {
|
|
5709
|
+
timer.unref();
|
|
5710
|
+
}
|
|
5711
|
+
};
|
|
5712
|
+
const drainBatch = async (drainAll) => {
|
|
5713
|
+
clearTimer();
|
|
5714
|
+
do {
|
|
5715
|
+
const batch = pending.splice(0, maxBatchSize);
|
|
5716
|
+
if (batch.length === 0) break;
|
|
5717
|
+
const result = await appendEventBatch(batch, options);
|
|
5718
|
+
stats.writtenEvents += result.written;
|
|
5719
|
+
stats.droppedEvents += result.dropped;
|
|
5720
|
+
if (result.lastError) {
|
|
5721
|
+
stats.lastError = result.lastError;
|
|
5722
|
+
}
|
|
5723
|
+
} while (drainAll && pending.length > 0);
|
|
5724
|
+
if (pending.length > 0) scheduleFlush();
|
|
5725
|
+
};
|
|
5726
|
+
const drain = (drainAll) => {
|
|
5727
|
+
const operation = chain.then(() => drainBatch(drainAll));
|
|
5728
|
+
chain = operation.catch(() => {
|
|
5729
|
+
});
|
|
5730
|
+
return operation.catch(() => {
|
|
5731
|
+
});
|
|
5732
|
+
};
|
|
5733
|
+
return {
|
|
5734
|
+
async write(event) {
|
|
5735
|
+
if (closed) {
|
|
5736
|
+
recordDropped(stats, "Trace writer is closed");
|
|
5737
|
+
return;
|
|
5738
|
+
}
|
|
5739
|
+
const safe = prepareWriterEvent(event);
|
|
5740
|
+
if (safe === void 0) {
|
|
5741
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
5742
|
+
return;
|
|
5743
|
+
}
|
|
5744
|
+
if (pending.length >= maxQueueSize) {
|
|
5745
|
+
if (overflow === "drop-newest") {
|
|
5746
|
+
recordDropped(stats, "Trace writer queue overflow");
|
|
5747
|
+
return;
|
|
5748
|
+
}
|
|
5749
|
+
pending.shift();
|
|
5750
|
+
recordDropped(stats, "Trace writer queue overflow");
|
|
5751
|
+
}
|
|
5752
|
+
try {
|
|
5753
|
+
pending.push(safe);
|
|
5754
|
+
} catch (error) {
|
|
5755
|
+
recordDropped(stats, error);
|
|
5756
|
+
return;
|
|
5757
|
+
}
|
|
5758
|
+
scheduleFlush();
|
|
5759
|
+
},
|
|
5760
|
+
async flush() {
|
|
5761
|
+
await drain(true);
|
|
5762
|
+
markFlush(stats);
|
|
5763
|
+
},
|
|
5764
|
+
async close() {
|
|
5765
|
+
if (closed) return;
|
|
5766
|
+
await drain(true);
|
|
5767
|
+
closed = true;
|
|
5768
|
+
clearTimer();
|
|
5769
|
+
},
|
|
5770
|
+
getStats() {
|
|
5771
|
+
return cloneStats(stats);
|
|
5772
|
+
}
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
function compositeWriter(writersOrOptions) {
|
|
5776
|
+
const stats = createInitialStats();
|
|
5777
|
+
const writers = Array.isArray(writersOrOptions) ? [...writersOrOptions] : [...writersOrOptions.writers];
|
|
5778
|
+
let closed = false;
|
|
5779
|
+
const recordChildFailure = (error) => {
|
|
5780
|
+
stats.droppedEvents += 1;
|
|
5781
|
+
stats.lastError = normalizeError2(error);
|
|
5782
|
+
};
|
|
5783
|
+
return {
|
|
5784
|
+
async write(event) {
|
|
5785
|
+
if (closed) {
|
|
5786
|
+
recordDropped(stats, "Trace writer is closed");
|
|
5787
|
+
return;
|
|
5788
|
+
}
|
|
5789
|
+
const safe = prepareWriterEvent(event);
|
|
5790
|
+
if (safe === void 0) {
|
|
5791
|
+
recordDropped(stats, "Invalid persisted inspect event");
|
|
5792
|
+
return;
|
|
5793
|
+
}
|
|
5794
|
+
const childResults = await Promise.all(
|
|
5795
|
+
writers.map(async (writer) => {
|
|
5796
|
+
try {
|
|
5797
|
+
await writer.write(structuredClone(safe));
|
|
5798
|
+
return true;
|
|
5799
|
+
} catch (error) {
|
|
5800
|
+
recordChildFailure(error);
|
|
5801
|
+
return false;
|
|
5802
|
+
}
|
|
5803
|
+
})
|
|
5804
|
+
);
|
|
5805
|
+
if (childResults.some(Boolean)) {
|
|
5806
|
+
stats.writtenEvents += 1;
|
|
5807
|
+
} else {
|
|
5808
|
+
recordDropped(stats, "No composite trace writer accepted the event");
|
|
5809
|
+
}
|
|
5810
|
+
},
|
|
5811
|
+
async flush() {
|
|
5812
|
+
await Promise.all(
|
|
5813
|
+
writers.map(async (writer) => {
|
|
5814
|
+
try {
|
|
5815
|
+
await writer.flush?.();
|
|
5816
|
+
} catch (error) {
|
|
5817
|
+
stats.lastError = normalizeError2(error);
|
|
5818
|
+
}
|
|
5819
|
+
})
|
|
5820
|
+
);
|
|
5821
|
+
markFlush(stats);
|
|
5822
|
+
},
|
|
5823
|
+
async close() {
|
|
5824
|
+
if (closed) return;
|
|
5825
|
+
await Promise.all(
|
|
5826
|
+
writers.map(async (writer) => {
|
|
5827
|
+
try {
|
|
5828
|
+
await writer.close?.();
|
|
5829
|
+
} catch (error) {
|
|
5830
|
+
stats.lastError = normalizeError2(error);
|
|
5831
|
+
}
|
|
5832
|
+
})
|
|
5833
|
+
);
|
|
5834
|
+
closed = true;
|
|
5835
|
+
},
|
|
5836
|
+
getStats() {
|
|
5837
|
+
return cloneStats(stats);
|
|
5838
|
+
}
|
|
5839
|
+
};
|
|
5840
|
+
}
|
|
5841
|
+
var DEFAULT_MAX_TRACE_INPUT_BYTES = 10 * 1024 * 1024;
|
|
5842
|
+
var MIN_DETECTION_CONFIDENCE = 0.5;
|
|
5843
|
+
var AMBIGUOUS_CONFIDENCE_DELTA = 0.05;
|
|
5844
|
+
var resolvedInputCache = /* @__PURE__ */ new WeakMap();
|
|
5845
|
+
var OPENINFERENCE_READER_FORMAT = "openinference-json";
|
|
5846
|
+
var OTLP_READER_FORMAT = "otlp-json";
|
|
5847
|
+
var OPENINFERENCE_SPAN_KEYS = /* @__PURE__ */ new Set([
|
|
5848
|
+
"trace_id",
|
|
5849
|
+
"traceId",
|
|
5850
|
+
"span_id",
|
|
5851
|
+
"spanId",
|
|
5852
|
+
"parent_span_id",
|
|
5853
|
+
"parentSpanId",
|
|
5854
|
+
"name",
|
|
5855
|
+
"start_time_unix_nano",
|
|
5856
|
+
"startTimeUnixNano",
|
|
5857
|
+
"end_time_unix_nano",
|
|
5858
|
+
"endTimeUnixNano",
|
|
5859
|
+
"start_time",
|
|
5860
|
+
"startTime",
|
|
5861
|
+
"end_time",
|
|
5862
|
+
"endTime",
|
|
5863
|
+
"attributes",
|
|
5864
|
+
"status",
|
|
5865
|
+
"kind",
|
|
5866
|
+
"span_kind",
|
|
5867
|
+
"spanKind"
|
|
5868
|
+
]);
|
|
5869
|
+
var OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS = [
|
|
5870
|
+
"input.value",
|
|
5871
|
+
"output.value",
|
|
5872
|
+
"input.mime_type",
|
|
5873
|
+
"output.mime_type",
|
|
5874
|
+
"llm.input_messages",
|
|
5875
|
+
"llm.output_messages",
|
|
5876
|
+
"llm.prompts",
|
|
5877
|
+
"llm.completions",
|
|
5878
|
+
"retrieval.documents",
|
|
5879
|
+
"reranker.input_documents",
|
|
5880
|
+
"reranker.output_documents",
|
|
5881
|
+
"document.content",
|
|
5882
|
+
"gen_ai.prompt",
|
|
5883
|
+
"gen_ai.completion",
|
|
5884
|
+
"gen_ai.input.messages",
|
|
5885
|
+
"gen_ai.output.messages"
|
|
5886
|
+
];
|
|
5887
|
+
var OTLP_SPAN_KEYS = /* @__PURE__ */ new Set([
|
|
5888
|
+
"traceId",
|
|
5889
|
+
"spanId",
|
|
5890
|
+
"parentSpanId",
|
|
5891
|
+
"name",
|
|
5892
|
+
"kind",
|
|
5893
|
+
"startTimeUnixNano",
|
|
5894
|
+
"endTimeUnixNano",
|
|
5895
|
+
"attributes",
|
|
5896
|
+
"events",
|
|
5897
|
+
"status",
|
|
5898
|
+
"droppedAttributesCount",
|
|
5899
|
+
"droppedEventsCount",
|
|
5900
|
+
"droppedLinksCount",
|
|
5901
|
+
"links",
|
|
5902
|
+
"flags"
|
|
5903
|
+
]);
|
|
5904
|
+
var TraceReadError = class extends Error {
|
|
5905
|
+
code;
|
|
5906
|
+
warnings;
|
|
5907
|
+
constructor(code, message, warnings = []) {
|
|
5908
|
+
super(message);
|
|
5909
|
+
this.name = "TraceReadError";
|
|
5910
|
+
this.code = code;
|
|
5911
|
+
this.warnings = warnings;
|
|
5912
|
+
}
|
|
5913
|
+
};
|
|
5914
|
+
function normalizeCandidate(reader, candidate) {
|
|
5915
|
+
const confidence = Number.isFinite(candidate.confidence) ? Math.max(0, Math.min(1, candidate.confidence)) : 0;
|
|
5916
|
+
return {
|
|
5917
|
+
...candidate,
|
|
5918
|
+
format: candidate.format || reader.format,
|
|
5919
|
+
confidence,
|
|
5920
|
+
readerName: candidate.readerName ?? reader.name
|
|
5921
|
+
};
|
|
5922
|
+
}
|
|
5923
|
+
function sortCandidates(candidates) {
|
|
5924
|
+
return [...candidates].sort((a, b) => {
|
|
5925
|
+
if (b.confidence !== a.confidence) return b.confidence - a.confidence;
|
|
5926
|
+
return a.format.localeCompare(b.format);
|
|
5927
|
+
});
|
|
5928
|
+
}
|
|
5929
|
+
function collectWarnings(candidates) {
|
|
5930
|
+
return candidates.flatMap((candidate) => candidate.warnings ?? []);
|
|
5931
|
+
}
|
|
5932
|
+
function dedupeWarnings(warnings) {
|
|
5933
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5934
|
+
const out = [];
|
|
5935
|
+
for (const warning of warnings) {
|
|
5936
|
+
const key = [
|
|
5937
|
+
warning.code,
|
|
5938
|
+
warning.message,
|
|
5939
|
+
warning.severity ?? "",
|
|
5940
|
+
warning.sourceFile ?? "",
|
|
5941
|
+
warning.line ?? "",
|
|
5942
|
+
warning.field ?? ""
|
|
5943
|
+
].join("\0");
|
|
5944
|
+
if (seen.has(key)) continue;
|
|
5945
|
+
seen.add(key);
|
|
5946
|
+
out.push(warning);
|
|
5947
|
+
}
|
|
5948
|
+
return out;
|
|
5949
|
+
}
|
|
5950
|
+
function attachSingleSourceFile(warnings, resolved) {
|
|
5951
|
+
if (resolved.sourceFiles.length !== 1) return [...warnings];
|
|
5952
|
+
const [sourceFile] = resolved.sourceFiles;
|
|
5953
|
+
return warnings.map((warning) => ({
|
|
5954
|
+
...warning,
|
|
5955
|
+
sourceFile: warning.sourceFile ?? sourceFile
|
|
5956
|
+
}));
|
|
5957
|
+
}
|
|
5958
|
+
function findReaderByFormat(format, readers) {
|
|
5959
|
+
return readers.find((reader) => reader.format === format);
|
|
5960
|
+
}
|
|
5961
|
+
async function jsonlFilesInDirectory(dirPath) {
|
|
5962
|
+
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
5963
|
+
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => path__default.default.join(dirPath, entry.name)).sort((a, b) => a.localeCompare(b));
|
|
5964
|
+
}
|
|
5965
|
+
async function resolveInput(input) {
|
|
5966
|
+
const cached = resolvedInputCache.get(input);
|
|
5967
|
+
if (cached) return cached;
|
|
5968
|
+
const promise = resolveInputUncached(input);
|
|
5969
|
+
resolvedInputCache.set(input, promise);
|
|
5970
|
+
return promise;
|
|
5971
|
+
}
|
|
5972
|
+
function assertInputWithinBounds(content, sourceFile) {
|
|
5973
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
5974
|
+
if (bytes <= DEFAULT_MAX_TRACE_INPUT_BYTES) return;
|
|
5975
|
+
throw new TraceReadError("unsupported_format", "Trace input exceeds the local reader size limit.", [
|
|
5976
|
+
{
|
|
5977
|
+
code: "input_too_large",
|
|
5978
|
+
message: `Trace input is ${bytes} bytes; max is ${DEFAULT_MAX_TRACE_INPUT_BYTES} bytes.`,
|
|
5979
|
+
severity: "error",
|
|
5980
|
+
...sourceFile !== void 0 ? { sourceFile } : {}
|
|
5981
|
+
}
|
|
5982
|
+
]);
|
|
5983
|
+
}
|
|
5984
|
+
async function resolveInputUncached(input) {
|
|
5985
|
+
if (input.type === "string") {
|
|
5986
|
+
assertInputWithinBounds(input.content);
|
|
5987
|
+
return { content: input.content, sourceFiles: [] };
|
|
5988
|
+
}
|
|
5989
|
+
if (input.type === "buffer") {
|
|
5990
|
+
const content = input.content.toString("utf-8");
|
|
5991
|
+
assertInputWithinBounds(content);
|
|
5992
|
+
return { content, sourceFiles: [] };
|
|
5993
|
+
}
|
|
5994
|
+
if (input.type === "file") {
|
|
5995
|
+
const content = await promises.readFile(input.path, "utf-8");
|
|
5996
|
+
assertInputWithinBounds(content, input.path);
|
|
5997
|
+
return { content, sourceFiles: [input.path] };
|
|
5998
|
+
}
|
|
5999
|
+
if (input.type === "directory") {
|
|
6000
|
+
const files = await jsonlFilesInDirectory(input.path);
|
|
6001
|
+
const parts = await Promise.all(
|
|
6002
|
+
files.map(async (file) => (await promises.readFile(file, "utf-8")).trimEnd())
|
|
6003
|
+
);
|
|
6004
|
+
const content = parts.filter((part) => part.trim() !== "").join("\n");
|
|
6005
|
+
assertInputWithinBounds(content, input.path);
|
|
6006
|
+
return {
|
|
6007
|
+
content,
|
|
6008
|
+
sourceFiles: files
|
|
6009
|
+
};
|
|
6010
|
+
}
|
|
6011
|
+
return void 0;
|
|
6012
|
+
}
|
|
6013
|
+
function detectJsonlFormat(content) {
|
|
6014
|
+
let saw01 = false;
|
|
6015
|
+
let saw02 = false;
|
|
6016
|
+
let validRows = 0;
|
|
6017
|
+
let invalidJsonRows = 0;
|
|
6018
|
+
let unknownSchemaRows = 0;
|
|
6019
|
+
let firstInvalidJsonLine;
|
|
6020
|
+
let firstUnknownSchemaLine;
|
|
6021
|
+
let lineNumber = 0;
|
|
6022
|
+
for (const line of content.split(/\r?\n/)) {
|
|
6023
|
+
lineNumber += 1;
|
|
6024
|
+
const trimmed = line.trim();
|
|
6025
|
+
if (trimmed === "") continue;
|
|
6026
|
+
let parsed;
|
|
6027
|
+
try {
|
|
6028
|
+
parsed = JSON.parse(trimmed);
|
|
6029
|
+
} catch {
|
|
6030
|
+
invalidJsonRows += 1;
|
|
6031
|
+
firstInvalidJsonLine ??= lineNumber;
|
|
6032
|
+
continue;
|
|
6033
|
+
}
|
|
6034
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && "schemaVersion" in parsed) {
|
|
6035
|
+
const version = parsed.schemaVersion;
|
|
6036
|
+
if (version === "0.1") {
|
|
6037
|
+
saw01 = true;
|
|
6038
|
+
validRows += 1;
|
|
6039
|
+
continue;
|
|
6040
|
+
}
|
|
6041
|
+
if (version === "0.2") {
|
|
6042
|
+
saw02 = true;
|
|
6043
|
+
validRows += 1;
|
|
6044
|
+
continue;
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
unknownSchemaRows += 1;
|
|
6048
|
+
firstUnknownSchemaLine ??= lineNumber;
|
|
6049
|
+
}
|
|
6050
|
+
const warnings = [];
|
|
6051
|
+
if (invalidJsonRows > 0) {
|
|
6052
|
+
warnings.push({
|
|
6053
|
+
code: "invalid_jsonl_rows",
|
|
6054
|
+
message: `Skipped ${invalidJsonRows} invalid JSONL row(s) during format detection.`,
|
|
6055
|
+
severity: "warning",
|
|
6056
|
+
...firstInvalidJsonLine !== void 0 ? { line: firstInvalidJsonLine } : {}
|
|
6057
|
+
});
|
|
6058
|
+
}
|
|
6059
|
+
if (unknownSchemaRows > 0) {
|
|
6060
|
+
warnings.push({
|
|
6061
|
+
code: "unknown_schema_rows",
|
|
6062
|
+
message: `Skipped ${unknownSchemaRows} row(s) with unknown schemaVersion during format detection.`,
|
|
6063
|
+
severity: "warning",
|
|
6064
|
+
...firstUnknownSchemaLine !== void 0 ? { line: firstUnknownSchemaLine } : {}
|
|
6065
|
+
});
|
|
6066
|
+
}
|
|
6067
|
+
let format = "empty";
|
|
6068
|
+
if (saw01 && saw02) format = "mixed";
|
|
6069
|
+
else if (saw01) format = "0.1";
|
|
6070
|
+
else if (saw02) format = "0.2";
|
|
6071
|
+
return { format, validRows, warnings };
|
|
6072
|
+
}
|
|
6073
|
+
function agentInspectFormatLabel(format) {
|
|
6074
|
+
switch (format) {
|
|
6075
|
+
case "0.1":
|
|
6076
|
+
return "agent-inspect-v0.1-jsonl";
|
|
6077
|
+
case "0.2":
|
|
6078
|
+
return "agent-inspect-v0.2-jsonl";
|
|
6079
|
+
case "mixed":
|
|
6080
|
+
return "agent-inspect-mixed-jsonl";
|
|
6081
|
+
default:
|
|
6082
|
+
return "agent-inspect-jsonl";
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
function persistedEventsForParsedTrace(parsed) {
|
|
6086
|
+
if (parsed.format === "0.2" && parsed.persisted.length > 0) {
|
|
6087
|
+
return [...parsed.persisted];
|
|
6088
|
+
}
|
|
6089
|
+
if (parsed.format === "mixed" && parsed.rows.length > 0) {
|
|
6090
|
+
return parsed.rows.map((row, index) => {
|
|
6091
|
+
if (row.format === "0.2") return row.event;
|
|
6092
|
+
return traceEventToPersistedInspectEvent(row.event, {
|
|
6093
|
+
eventIndex: index,
|
|
6094
|
+
sourceName: "agent-inspect-jsonl-reader"
|
|
6095
|
+
});
|
|
6096
|
+
});
|
|
6097
|
+
}
|
|
6098
|
+
return traceEventsToPersistedInspectEvents(parsed.events, {
|
|
6099
|
+
sourceName: "agent-inspect-jsonl-reader"
|
|
6100
|
+
});
|
|
6101
|
+
}
|
|
6102
|
+
function isRecord13(value) {
|
|
6103
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6104
|
+
}
|
|
6105
|
+
function isNonEmptyString3(value) {
|
|
6106
|
+
return typeof value === "string" && value.trim() !== "";
|
|
6107
|
+
}
|
|
6108
|
+
function readStringField(record, keys) {
|
|
6109
|
+
for (const key of keys) {
|
|
6110
|
+
const value = record[key];
|
|
6111
|
+
if (isNonEmptyString3(value)) return value;
|
|
6112
|
+
}
|
|
6113
|
+
return void 0;
|
|
6114
|
+
}
|
|
6115
|
+
function readRecordField(record, key) {
|
|
6116
|
+
const value = record[key];
|
|
6117
|
+
return isRecord13(value) ? value : void 0;
|
|
6118
|
+
}
|
|
6119
|
+
function parseJsonDocument(content) {
|
|
6120
|
+
return JSON.parse(content);
|
|
6121
|
+
}
|
|
6122
|
+
function looksLikeOpenInferenceSpan(value) {
|
|
6123
|
+
if (!isRecord13(value)) return false;
|
|
6124
|
+
const attributes = readRecordField(value, "attributes");
|
|
6125
|
+
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);
|
|
6126
|
+
}
|
|
6127
|
+
function extractOpenInferenceDocument(root) {
|
|
6128
|
+
const warnings = [];
|
|
6129
|
+
const unsupportedFields = [];
|
|
6130
|
+
if (Array.isArray(root)) {
|
|
6131
|
+
const spans = root.filter(looksLikeOpenInferenceSpan);
|
|
6132
|
+
if (spans.length === 0) return void 0;
|
|
6133
|
+
if (spans.length !== root.length) {
|
|
6134
|
+
warnings.push({
|
|
6135
|
+
code: "openinference_skipped_items",
|
|
6136
|
+
message: "Skipped non-span item(s) in OpenInference span array.",
|
|
6137
|
+
severity: "warning"
|
|
6138
|
+
});
|
|
6139
|
+
}
|
|
6140
|
+
return {
|
|
6141
|
+
spans,
|
|
6142
|
+
confidence: 0.82,
|
|
6143
|
+
description: "OpenInference span array",
|
|
6144
|
+
warnings,
|
|
6145
|
+
unsupportedFields
|
|
6146
|
+
};
|
|
6147
|
+
}
|
|
6148
|
+
if (!isRecord13(root)) return void 0;
|
|
6149
|
+
const rootFormat = root.format;
|
|
6150
|
+
const rootCompatibility = root.compatibility;
|
|
6151
|
+
const version = typeof root.version === "string" && root.version.trim() !== "" ? root.version : void 0;
|
|
6152
|
+
if (Array.isArray(root.spans)) {
|
|
6153
|
+
const spans = root.spans.filter(looksLikeOpenInferenceSpan);
|
|
6154
|
+
if (spans.length === 0 && (rootFormat === "openinference" || rootCompatibility === "openinference-compatible")) {
|
|
6155
|
+
warnings.push({
|
|
6156
|
+
code: "openinference_no_valid_spans",
|
|
6157
|
+
message: "OpenInference document did not contain any valid spans.",
|
|
6158
|
+
severity: "error"
|
|
6159
|
+
});
|
|
6160
|
+
return {
|
|
6161
|
+
spans,
|
|
6162
|
+
confidence: 0.7,
|
|
6163
|
+
description: "Malformed OpenInference document",
|
|
6164
|
+
version,
|
|
6165
|
+
warnings,
|
|
6166
|
+
unsupportedFields
|
|
6167
|
+
};
|
|
6168
|
+
}
|
|
6169
|
+
if (spans.length === 0) return void 0;
|
|
6170
|
+
if (spans.length !== root.spans.length) {
|
|
6171
|
+
warnings.push({
|
|
6172
|
+
code: "openinference_skipped_spans",
|
|
6173
|
+
message: "Skipped invalid OpenInference span item(s).",
|
|
6174
|
+
severity: "warning"
|
|
6175
|
+
});
|
|
6176
|
+
}
|
|
6177
|
+
return {
|
|
6178
|
+
spans,
|
|
6179
|
+
confidence: rootFormat === "openinference" || rootCompatibility === "openinference-compatible" ? 0.9 : 0.84,
|
|
6180
|
+
description: rootFormat === "openinference" || rootCompatibility === "openinference-compatible" ? "OpenInference document" : "OpenInference spans document",
|
|
6181
|
+
version,
|
|
6182
|
+
warnings,
|
|
6183
|
+
unsupportedFields
|
|
6184
|
+
};
|
|
6185
|
+
}
|
|
6186
|
+
if (Array.isArray(root.data)) {
|
|
6187
|
+
const spans = root.data.filter(looksLikeOpenInferenceSpan);
|
|
6188
|
+
if (spans.length === 0) return void 0;
|
|
6189
|
+
if (spans.length !== root.data.length) {
|
|
6190
|
+
warnings.push({
|
|
6191
|
+
code: "openinference_skipped_data_items",
|
|
6192
|
+
message: "Skipped non-span item(s) in OpenInference data array.",
|
|
6193
|
+
severity: "warning"
|
|
6194
|
+
});
|
|
6195
|
+
}
|
|
6196
|
+
return {
|
|
6197
|
+
spans,
|
|
6198
|
+
confidence: 0.8,
|
|
6199
|
+
description: "OpenInference data document",
|
|
6200
|
+
version,
|
|
6201
|
+
warnings,
|
|
6202
|
+
unsupportedFields
|
|
6203
|
+
};
|
|
6204
|
+
}
|
|
6205
|
+
if (looksLikeOpenInferenceSpan(root)) {
|
|
6206
|
+
return {
|
|
6207
|
+
spans: [root],
|
|
6208
|
+
confidence: 0.76,
|
|
6209
|
+
description: "OpenInference single span",
|
|
6210
|
+
version,
|
|
6211
|
+
warnings,
|
|
6212
|
+
unsupportedFields
|
|
6213
|
+
};
|
|
6214
|
+
}
|
|
6215
|
+
if (rootFormat === "openinference" || rootCompatibility === "openinference-compatible") {
|
|
6216
|
+
warnings.push({
|
|
6217
|
+
code: "openinference_missing_spans",
|
|
6218
|
+
message: "OpenInference document is missing a spans array.",
|
|
6219
|
+
severity: "error"
|
|
6220
|
+
});
|
|
6221
|
+
return {
|
|
6222
|
+
spans: [],
|
|
6223
|
+
confidence: 0.7,
|
|
6224
|
+
description: "Malformed OpenInference document",
|
|
6225
|
+
version,
|
|
6226
|
+
warnings,
|
|
6227
|
+
unsupportedFields
|
|
6228
|
+
};
|
|
6229
|
+
}
|
|
6230
|
+
return void 0;
|
|
6231
|
+
}
|
|
6232
|
+
function parseUnixNanoToIso(value) {
|
|
6233
|
+
if (typeof value === "bigint" && value >= 0n) {
|
|
6234
|
+
return new Date(Number(value / 1000000n)).toISOString();
|
|
6235
|
+
}
|
|
6236
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
6237
|
+
return new Date(Math.floor(value / 1e6)).toISOString();
|
|
6238
|
+
}
|
|
6239
|
+
if (typeof value === "string" && /^\d+$/.test(value)) {
|
|
6240
|
+
return new Date(Number(BigInt(value) / 1000000n)).toISOString();
|
|
6241
|
+
}
|
|
6242
|
+
return void 0;
|
|
6243
|
+
}
|
|
6244
|
+
function parseIsoTime(value) {
|
|
6245
|
+
if (!isNonEmptyString3(value)) return void 0;
|
|
6246
|
+
const ms = Date.parse(value);
|
|
6247
|
+
if (!Number.isFinite(ms)) return void 0;
|
|
6248
|
+
return new Date(ms).toISOString();
|
|
6249
|
+
}
|
|
6250
|
+
function readOpenInferenceTimestamp(span, nanoKeys, isoKeys) {
|
|
6251
|
+
for (const key of nanoKeys) {
|
|
6252
|
+
const iso = parseUnixNanoToIso(span[key]);
|
|
6253
|
+
if (iso !== void 0) return iso;
|
|
6254
|
+
}
|
|
6255
|
+
for (const key of isoKeys) {
|
|
6256
|
+
const iso = parseIsoTime(span[key]);
|
|
6257
|
+
if (iso !== void 0) return iso;
|
|
6258
|
+
}
|
|
6259
|
+
return void 0;
|
|
6260
|
+
}
|
|
6261
|
+
function durationBetweenIso(startedAt, endedAt) {
|
|
6262
|
+
if (startedAt === void 0 || endedAt === void 0) return void 0;
|
|
6263
|
+
const startMs = Date.parse(startedAt);
|
|
6264
|
+
const endMs = Date.parse(endedAt);
|
|
6265
|
+
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs < startMs) {
|
|
6266
|
+
return void 0;
|
|
6267
|
+
}
|
|
6268
|
+
return endMs - startMs;
|
|
6269
|
+
}
|
|
6270
|
+
function isSensitiveOpenInferenceAttribute(key) {
|
|
6271
|
+
return OPENINFERENCE_SENSITIVE_ATTRIBUTE_KEYS.some(
|
|
6272
|
+
(sensitiveKey) => key === sensitiveKey || key.startsWith(`${sensitiveKey}.`) || key.endsWith(".message.content") || key.endsWith(".document.content")
|
|
6273
|
+
);
|
|
6274
|
+
}
|
|
6275
|
+
function summarizeAttributeValue(value) {
|
|
6276
|
+
if (typeof value === "string") {
|
|
6277
|
+
return { type: "string", length: value.length };
|
|
6278
|
+
}
|
|
6279
|
+
if (typeof value === "number") {
|
|
6280
|
+
return { type: "number", finite: Number.isFinite(value) };
|
|
6281
|
+
}
|
|
6282
|
+
if (typeof value === "boolean") {
|
|
6283
|
+
return { type: "boolean" };
|
|
6284
|
+
}
|
|
6285
|
+
if (Array.isArray(value)) {
|
|
6286
|
+
return { type: "array", length: value.length };
|
|
6287
|
+
}
|
|
6288
|
+
if (isRecord13(value)) {
|
|
6289
|
+
return { type: "object", keyCount: Object.keys(value).length };
|
|
6290
|
+
}
|
|
6291
|
+
if (value === null) {
|
|
6292
|
+
return { type: "null" };
|
|
6293
|
+
}
|
|
6294
|
+
return { type: typeof value };
|
|
6295
|
+
}
|
|
6296
|
+
function sanitizeOpenInferenceAttributes(attributes, pathPrefix) {
|
|
6297
|
+
const out = {};
|
|
6298
|
+
const warnings = [];
|
|
6299
|
+
const unsupportedFields = [];
|
|
6300
|
+
const summarizedKeys = [];
|
|
6301
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
6302
|
+
if (isSensitiveOpenInferenceAttribute(key)) {
|
|
6303
|
+
summarizedKeys.push(key);
|
|
6304
|
+
out[`${key}.summary`] = summarizeAttributeValue(value);
|
|
6305
|
+
unsupportedFields.push(`${pathPrefix}.attributes.${key}`);
|
|
6306
|
+
continue;
|
|
6307
|
+
}
|
|
6308
|
+
out[key] = value;
|
|
6309
|
+
}
|
|
6310
|
+
if (summarizedKeys.length > 0) {
|
|
6311
|
+
out["openinference.summarized_attributes"] = summarizedKeys;
|
|
6312
|
+
warnings.push({
|
|
6313
|
+
code: "openinference_sensitive_attribute_summarized",
|
|
6314
|
+
message: "OpenInference prompt/output/document attribute(s) were summarized instead of copied verbatim.",
|
|
6315
|
+
severity: "warning"
|
|
6316
|
+
});
|
|
6317
|
+
}
|
|
6318
|
+
return { attributes: out, warnings, unsupportedFields };
|
|
6319
|
+
}
|
|
6320
|
+
function mapOpenInferenceKind(span, attributes, pathPrefix) {
|
|
6321
|
+
const warnings = [];
|
|
6322
|
+
const agentInspectKind = attributes["agent_inspect.kind"];
|
|
6323
|
+
if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
|
|
6324
|
+
return { kind: agentInspectKind, warnings };
|
|
6325
|
+
}
|
|
6326
|
+
const rawKind = readStringField(span, ["kind", "span_kind", "spanKind"]) ?? (typeof attributes["openinference.span.kind"] === "string" ? attributes["openinference.span.kind"] : void 0);
|
|
6327
|
+
const normalized = rawKind?.toUpperCase();
|
|
6328
|
+
switch (normalized) {
|
|
6329
|
+
case "LLM":
|
|
6330
|
+
return { kind: "LLM", warnings };
|
|
6331
|
+
case "TOOL":
|
|
6332
|
+
return { kind: "TOOL", warnings };
|
|
6333
|
+
case "CHAIN":
|
|
6334
|
+
return { kind: "CHAIN", warnings };
|
|
6335
|
+
case "RETRIEVER":
|
|
6336
|
+
return { kind: "RETRIEVER", warnings };
|
|
6337
|
+
case "AGENT":
|
|
6338
|
+
return { kind: "AGENT", warnings };
|
|
6339
|
+
case "EMBEDDING":
|
|
6340
|
+
warnings.push({
|
|
6341
|
+
code: "openinference_kind_semantic_loss",
|
|
6342
|
+
message: "OpenInference EMBEDDING span kind mapped to AgentInspect LLM.",
|
|
6343
|
+
severity: "warning",
|
|
6344
|
+
field: `${pathPrefix}.attributes.openinference.span.kind`
|
|
6345
|
+
});
|
|
6346
|
+
return { kind: "LLM", warnings };
|
|
6347
|
+
case "RERANKER":
|
|
6348
|
+
warnings.push({
|
|
6349
|
+
code: "openinference_kind_semantic_loss",
|
|
6350
|
+
message: "OpenInference RERANKER span kind mapped to AgentInspect RETRIEVER.",
|
|
6351
|
+
severity: "warning",
|
|
6352
|
+
field: `${pathPrefix}.attributes.openinference.span.kind`
|
|
6353
|
+
});
|
|
6354
|
+
return { kind: "RETRIEVER", warnings };
|
|
6355
|
+
case "UNKNOWN":
|
|
6356
|
+
case void 0:
|
|
6357
|
+
warnings.push({
|
|
6358
|
+
code: "openinference_kind_unknown",
|
|
6359
|
+
message: "OpenInference span kind was missing or unknown; mapped to AgentInspect LOGIC.",
|
|
6360
|
+
severity: "warning",
|
|
6361
|
+
field: `${pathPrefix}.attributes.openinference.span.kind`
|
|
6362
|
+
});
|
|
6363
|
+
return { kind: "LOGIC", warnings };
|
|
6364
|
+
default:
|
|
6365
|
+
warnings.push({
|
|
6366
|
+
code: "openinference_kind_unsupported",
|
|
6367
|
+
message: `Unsupported OpenInference span kind "${rawKind}" mapped to AgentInspect LOGIC.`,
|
|
6368
|
+
severity: "warning",
|
|
6369
|
+
field: `${pathPrefix}.attributes.openinference.span.kind`
|
|
6370
|
+
});
|
|
6371
|
+
return { kind: "LOGIC", warnings };
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6374
|
+
function mapOpenInferenceStatus(status) {
|
|
6375
|
+
if (!isRecord13(status)) return void 0;
|
|
6376
|
+
const rawCode = status.code;
|
|
6377
|
+
if (typeof rawCode !== "string") return void 0;
|
|
6378
|
+
switch (rawCode.toUpperCase()) {
|
|
6379
|
+
case "OK":
|
|
6380
|
+
return "ok";
|
|
6381
|
+
case "ERROR":
|
|
6382
|
+
return "error";
|
|
6383
|
+
case "UNSET":
|
|
6384
|
+
return "unknown";
|
|
6385
|
+
default:
|
|
6386
|
+
return "unknown";
|
|
6387
|
+
}
|
|
6388
|
+
}
|
|
6389
|
+
function readOpenInferenceTokenUsage(attributes) {
|
|
6390
|
+
const prompt = attributes["llm.token_count.prompt"];
|
|
6391
|
+
const completion = attributes["llm.token_count.completion"];
|
|
6392
|
+
const total = attributes["llm.token_count.total"];
|
|
6393
|
+
const cached = attributes["llm.token_count.prompt_details.cache_read"];
|
|
6394
|
+
const usage = {};
|
|
6395
|
+
if (typeof prompt === "number" && Number.isFinite(prompt) && prompt >= 0) {
|
|
6396
|
+
usage.input = prompt;
|
|
6397
|
+
}
|
|
6398
|
+
if (typeof completion === "number" && Number.isFinite(completion) && completion >= 0) {
|
|
6399
|
+
usage.output = completion;
|
|
6400
|
+
}
|
|
6401
|
+
if (typeof total === "number" && Number.isFinite(total) && total >= 0) {
|
|
6402
|
+
usage.total = total;
|
|
6403
|
+
}
|
|
6404
|
+
if (typeof cached === "number" && Number.isFinite(cached) && cached >= 0) {
|
|
6405
|
+
usage.cached = cached;
|
|
6406
|
+
}
|
|
6407
|
+
if (usage.total === void 0 && usage.input !== void 0 && usage.output !== void 0) {
|
|
6408
|
+
usage.total = usage.input + usage.output;
|
|
6409
|
+
}
|
|
6410
|
+
return Object.keys(usage).length > 0 ? usage : void 0;
|
|
6411
|
+
}
|
|
6412
|
+
function readOpenInferenceConfidence(attributes) {
|
|
6413
|
+
const confidence = attributes["agent_inspect.confidence"];
|
|
6414
|
+
if (confidence === "explicit" || confidence === "correlated" || confidence === "heuristic" || confidence === "unknown") {
|
|
6415
|
+
return confidence;
|
|
6416
|
+
}
|
|
6417
|
+
return "correlated";
|
|
6418
|
+
}
|
|
6419
|
+
function mapOpenInferenceSpan(span, index, version) {
|
|
6420
|
+
const pathPrefix = `spans[${index}]`;
|
|
6421
|
+
const warnings = [];
|
|
6422
|
+
const unsupportedFields = [];
|
|
6423
|
+
const rawAttributes = readRecordField(span, "attributes") ?? {};
|
|
6424
|
+
const sanitized = sanitizeOpenInferenceAttributes(rawAttributes, pathPrefix);
|
|
6425
|
+
warnings.push(...sanitized.warnings);
|
|
6426
|
+
unsupportedFields.push(...sanitized.unsupportedFields);
|
|
6427
|
+
const attributes = { ...sanitized.attributes };
|
|
6428
|
+
for (const [key, value] of Object.entries(span)) {
|
|
6429
|
+
if (OPENINFERENCE_SPAN_KEYS.has(key)) continue;
|
|
6430
|
+
unsupportedFields.push(`${pathPrefix}.${key}`);
|
|
6431
|
+
if (value === null || typeof value !== "object") {
|
|
6432
|
+
attributes[`openinference.${key}`] = value;
|
|
6433
|
+
} else {
|
|
6434
|
+
attributes[`openinference.${key}.summary`] = summarizeAttributeValue(value);
|
|
6435
|
+
warnings.push({
|
|
6436
|
+
code: "openinference_unsupported_field_summarized",
|
|
6437
|
+
message: `Unsupported OpenInference span field "${key}" was summarized.`,
|
|
6438
|
+
severity: "warning",
|
|
6439
|
+
field: `${pathPrefix}.${key}`
|
|
6440
|
+
});
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
const traceId = readStringField(span, ["trace_id", "traceId"]) ?? `trace-${index}`;
|
|
6444
|
+
const spanId = readStringField(span, ["span_id", "spanId"]) ?? `span-${index}`;
|
|
6445
|
+
const parentSpanId = readStringField(span, ["parent_span_id", "parentSpanId"]);
|
|
6446
|
+
const name = readStringField(span, ["name"]) ?? spanId;
|
|
6447
|
+
const startedAt = readOpenInferenceTimestamp(
|
|
6448
|
+
span,
|
|
6449
|
+
["start_time_unix_nano", "startTimeUnixNano"],
|
|
6450
|
+
["start_time", "startTime"]
|
|
6451
|
+
);
|
|
6452
|
+
const endedAt = readOpenInferenceTimestamp(
|
|
6453
|
+
span,
|
|
6454
|
+
["end_time_unix_nano", "endTimeUnixNano"],
|
|
6455
|
+
["end_time", "endTime"]
|
|
6456
|
+
);
|
|
6457
|
+
const timestamp = startedAt ?? "1970-01-01T00:00:00.000Z";
|
|
6458
|
+
if (startedAt === void 0) {
|
|
6459
|
+
warnings.push({
|
|
6460
|
+
code: "openinference_missing_start_time",
|
|
6461
|
+
message: "OpenInference span is missing a valid start time; using Unix epoch.",
|
|
6462
|
+
severity: "warning",
|
|
6463
|
+
field: `${pathPrefix}.start_time_unix_nano`
|
|
6464
|
+
});
|
|
6465
|
+
unsupportedFields.push(`${pathPrefix}.start_time_unix_nano`);
|
|
6466
|
+
}
|
|
6467
|
+
const { kind, warnings: kindWarnings } = mapOpenInferenceKind(
|
|
6468
|
+
span,
|
|
6469
|
+
rawAttributes,
|
|
6470
|
+
pathPrefix
|
|
6471
|
+
);
|
|
6472
|
+
warnings.push(...kindWarnings);
|
|
6473
|
+
const status = mapOpenInferenceStatus(span.status);
|
|
6474
|
+
const tokenUsage = readOpenInferenceTokenUsage(rawAttributes);
|
|
6475
|
+
const errorMessage = isRecord13(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
|
|
6476
|
+
const event = {
|
|
6477
|
+
schemaVersion: "0.2",
|
|
6478
|
+
eventId: typeof rawAttributes["agent_inspect.event_id"] === "string" ? rawAttributes["agent_inspect.event_id"] : spanId,
|
|
6479
|
+
runId: typeof rawAttributes["agent_inspect.run_id"] === "string" ? rawAttributes["agent_inspect.run_id"] : traceId,
|
|
6480
|
+
kind,
|
|
6481
|
+
name,
|
|
6482
|
+
timestamp,
|
|
6483
|
+
confidence: readOpenInferenceConfidence(rawAttributes),
|
|
6484
|
+
source: {
|
|
6485
|
+
type: "otel",
|
|
6486
|
+
name: "openinference",
|
|
6487
|
+
...version !== void 0 ? { version } : {}
|
|
6488
|
+
},
|
|
6489
|
+
attributes,
|
|
6490
|
+
trace: {
|
|
6491
|
+
traceId,
|
|
6492
|
+
spanId,
|
|
6493
|
+
...parentSpanId !== void 0 ? { parentSpanId } : {}
|
|
6494
|
+
}
|
|
6495
|
+
};
|
|
6496
|
+
if (status !== void 0) {
|
|
6497
|
+
event.status = status;
|
|
6498
|
+
}
|
|
6499
|
+
if (startedAt !== void 0) {
|
|
6500
|
+
event.startedAt = startedAt;
|
|
6501
|
+
}
|
|
6502
|
+
if (endedAt !== void 0) {
|
|
6503
|
+
event.endedAt = endedAt;
|
|
6504
|
+
}
|
|
6505
|
+
const durationMs2 = durationBetweenIso(startedAt, endedAt);
|
|
6506
|
+
if (durationMs2 !== void 0) {
|
|
6507
|
+
event.durationMs = durationMs2;
|
|
6508
|
+
}
|
|
6509
|
+
if (tokenUsage !== void 0) {
|
|
6510
|
+
event.tokenUsage = tokenUsage;
|
|
6511
|
+
}
|
|
6512
|
+
if (status === "error") {
|
|
6513
|
+
event.error = {
|
|
6514
|
+
message: errorMessage !== void 0 && errorMessage.trim() !== "" ? errorMessage : "OpenInference span error"
|
|
6515
|
+
};
|
|
6516
|
+
}
|
|
6517
|
+
return {
|
|
6518
|
+
event,
|
|
6519
|
+
warnings,
|
|
6520
|
+
unsupportedFields,
|
|
6521
|
+
spanId,
|
|
6522
|
+
...parentSpanId !== void 0 ? { parentSpanId } : {}
|
|
6523
|
+
};
|
|
6524
|
+
}
|
|
6525
|
+
function mapOpenInferenceEvents(document) {
|
|
6526
|
+
const mapped = document.spans.map(
|
|
6527
|
+
(span, index) => mapOpenInferenceSpan(span, index, document.version)
|
|
6528
|
+
);
|
|
6529
|
+
const spanIdToEventId = new Map(
|
|
6530
|
+
mapped.map((span) => [span.spanId, span.event.eventId])
|
|
6531
|
+
);
|
|
6532
|
+
for (const span of mapped) {
|
|
6533
|
+
if (span.parentSpanId === void 0) continue;
|
|
6534
|
+
span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
|
|
6535
|
+
}
|
|
6536
|
+
return {
|
|
6537
|
+
events: mapped.map((span) => span.event),
|
|
6538
|
+
warnings: mapped.flatMap((span) => span.warnings),
|
|
6539
|
+
unsupportedFields: mapped.flatMap((span) => span.unsupportedFields)
|
|
6540
|
+
};
|
|
6541
|
+
}
|
|
6542
|
+
var openInferenceJsonReader = {
|
|
6543
|
+
format: OPENINFERENCE_READER_FORMAT,
|
|
6544
|
+
name: "OpenInference JSON",
|
|
6545
|
+
async detect(input) {
|
|
6546
|
+
const resolved = await resolveInput(input);
|
|
6547
|
+
if (!resolved) return void 0;
|
|
6548
|
+
let parsed;
|
|
6549
|
+
try {
|
|
6550
|
+
parsed = parseJsonDocument(resolved.content);
|
|
6551
|
+
} catch {
|
|
6552
|
+
return void 0;
|
|
6553
|
+
}
|
|
6554
|
+
const document = extractOpenInferenceDocument(parsed);
|
|
6555
|
+
if (!document) return void 0;
|
|
6556
|
+
return {
|
|
6557
|
+
format: OPENINFERENCE_READER_FORMAT,
|
|
6558
|
+
confidence: document.confidence,
|
|
6559
|
+
readerName: "OpenInference JSON",
|
|
6560
|
+
description: document.description,
|
|
6561
|
+
warnings: attachSingleSourceFile(document.warnings, resolved)
|
|
6562
|
+
};
|
|
6563
|
+
},
|
|
6564
|
+
async read(input) {
|
|
6565
|
+
const resolved = await resolveInput(input);
|
|
6566
|
+
if (!resolved) {
|
|
6567
|
+
throw new TraceReadError(
|
|
6568
|
+
"unsupported_format",
|
|
6569
|
+
"OpenInference JSON reader requires file, string, or buffer input."
|
|
6570
|
+
);
|
|
6571
|
+
}
|
|
6572
|
+
let parsed;
|
|
6573
|
+
try {
|
|
6574
|
+
parsed = parseJsonDocument(resolved.content);
|
|
6575
|
+
} catch {
|
|
6576
|
+
throw new TraceReadError("unsupported_format", "OpenInference JSON input is not valid JSON.", [
|
|
6577
|
+
{
|
|
6578
|
+
code: "openinference_invalid_json",
|
|
6579
|
+
message: "OpenInference JSON reader could not parse the input as JSON.",
|
|
6580
|
+
severity: "error"
|
|
6581
|
+
}
|
|
6582
|
+
]);
|
|
6583
|
+
}
|
|
6584
|
+
const document = extractOpenInferenceDocument(parsed);
|
|
6585
|
+
if (!document || document.spans.length === 0) {
|
|
6586
|
+
throw new TraceReadError(
|
|
6587
|
+
"unsupported_format",
|
|
6588
|
+
"No valid OpenInference spans found.",
|
|
6589
|
+
attachSingleSourceFile(
|
|
6590
|
+
document?.warnings ?? [
|
|
6591
|
+
{
|
|
6592
|
+
code: "openinference_no_valid_spans",
|
|
6593
|
+
message: "OpenInference JSON input did not contain valid spans.",
|
|
6594
|
+
severity: "error"
|
|
6595
|
+
}
|
|
6596
|
+
],
|
|
6597
|
+
resolved
|
|
6598
|
+
)
|
|
6599
|
+
);
|
|
6600
|
+
}
|
|
6601
|
+
const mapped = mapOpenInferenceEvents(document);
|
|
6602
|
+
const warnings = attachSingleSourceFile(
|
|
6603
|
+
[...document.warnings, ...mapped.warnings],
|
|
6604
|
+
resolved
|
|
6605
|
+
);
|
|
6606
|
+
const unsupportedFields = [
|
|
6607
|
+
...document.unsupportedFields,
|
|
6608
|
+
...mapped.unsupportedFields
|
|
6609
|
+
].sort((a, b) => a.localeCompare(b));
|
|
6610
|
+
return {
|
|
6611
|
+
format: OPENINFERENCE_READER_FORMAT,
|
|
6612
|
+
events: mapped.events,
|
|
6613
|
+
runs: persistedInspectEventsToRunTrees(mapped.events, { skipInvalid: true }),
|
|
6614
|
+
warnings,
|
|
6615
|
+
unsupportedFields,
|
|
6616
|
+
sourceFiles: resolved.sourceFiles
|
|
6617
|
+
};
|
|
6618
|
+
}
|
|
6619
|
+
};
|
|
6620
|
+
function parseOtlpAnyValue(value, field, warnings, unsupportedFields) {
|
|
6621
|
+
if (!isRecord13(value)) {
|
|
6622
|
+
unsupportedFields.push(field);
|
|
6623
|
+
warnings.push({
|
|
6624
|
+
code: "otlp_attribute_value_invalid",
|
|
6625
|
+
message: "OTLP attribute value was not an AnyValue object.",
|
|
6626
|
+
severity: "warning",
|
|
6627
|
+
field
|
|
6628
|
+
});
|
|
6629
|
+
return void 0;
|
|
6630
|
+
}
|
|
6631
|
+
if (typeof value.stringValue === "string") return value.stringValue;
|
|
6632
|
+
if (typeof value.boolValue === "boolean") return value.boolValue;
|
|
6633
|
+
if (typeof value.intValue === "number" && Number.isFinite(value.intValue)) {
|
|
6634
|
+
return value.intValue;
|
|
6635
|
+
}
|
|
6636
|
+
if (typeof value.intValue === "string" && value.intValue.trim() !== "") {
|
|
6637
|
+
const n = Number(value.intValue);
|
|
6638
|
+
if (Number.isFinite(n)) return n;
|
|
6639
|
+
}
|
|
6640
|
+
if (typeof value.doubleValue === "number" && Number.isFinite(value.doubleValue)) {
|
|
6641
|
+
return value.doubleValue;
|
|
6642
|
+
}
|
|
6643
|
+
if (isRecord13(value.arrayValue) && Array.isArray(value.arrayValue.values)) {
|
|
6644
|
+
return value.arrayValue.values.map(
|
|
6645
|
+
(item, index) => parseOtlpAnyValue(item, `${field}.arrayValue.values[${index}]`, warnings, unsupportedFields)
|
|
6646
|
+
);
|
|
6647
|
+
}
|
|
6648
|
+
if (isRecord13(value.kvlistValue) && Array.isArray(value.kvlistValue.values)) {
|
|
6649
|
+
const out = {};
|
|
6650
|
+
for (const [index, item] of value.kvlistValue.values.entries()) {
|
|
6651
|
+
if (!isRecord13(item) || typeof item.key !== "string") {
|
|
6652
|
+
unsupportedFields.push(`${field}.kvlistValue.values[${index}]`);
|
|
6653
|
+
continue;
|
|
6654
|
+
}
|
|
6655
|
+
out[item.key] = parseOtlpAnyValue(
|
|
6656
|
+
item.value,
|
|
6657
|
+
`${field}.kvlistValue.values[${index}].value`,
|
|
6658
|
+
warnings,
|
|
6659
|
+
unsupportedFields
|
|
6660
|
+
);
|
|
6661
|
+
}
|
|
6662
|
+
return out;
|
|
6663
|
+
}
|
|
6664
|
+
if (typeof value.bytesValue === "string") {
|
|
6665
|
+
unsupportedFields.push(field);
|
|
6666
|
+
warnings.push({
|
|
6667
|
+
code: "otlp_bytes_value_summarized",
|
|
6668
|
+
message: "OTLP bytesValue attribute was summarized instead of decoded.",
|
|
6669
|
+
severity: "warning",
|
|
6670
|
+
field
|
|
6671
|
+
});
|
|
6672
|
+
return { type: "bytes", length: value.bytesValue.length };
|
|
6673
|
+
}
|
|
6674
|
+
unsupportedFields.push(field);
|
|
6675
|
+
warnings.push({
|
|
6676
|
+
code: "otlp_attribute_value_unsupported",
|
|
6677
|
+
message: "OTLP attribute value used an unsupported AnyValue shape.",
|
|
6678
|
+
severity: "warning",
|
|
6679
|
+
field
|
|
6680
|
+
});
|
|
6681
|
+
return void 0;
|
|
6682
|
+
}
|
|
6683
|
+
function parseOtlpAttributes(value, pathPrefix) {
|
|
6684
|
+
const attributes = {};
|
|
6685
|
+
const warnings = [];
|
|
6686
|
+
const unsupportedFields = [];
|
|
6687
|
+
if (value === void 0) {
|
|
6688
|
+
return { attributes, warnings, unsupportedFields };
|
|
6689
|
+
}
|
|
6690
|
+
if (!Array.isArray(value)) {
|
|
6691
|
+
unsupportedFields.push(pathPrefix);
|
|
6692
|
+
warnings.push({
|
|
6693
|
+
code: "otlp_attributes_invalid",
|
|
6694
|
+
message: "OTLP attributes field was not an array.",
|
|
6695
|
+
severity: "warning",
|
|
6696
|
+
field: pathPrefix
|
|
6697
|
+
});
|
|
6698
|
+
return { attributes, warnings, unsupportedFields };
|
|
6699
|
+
}
|
|
6700
|
+
for (const [index, item] of value.entries()) {
|
|
6701
|
+
const field = `${pathPrefix}[${index}]`;
|
|
6702
|
+
if (!isRecord13(item) || typeof item.key !== "string") {
|
|
6703
|
+
unsupportedFields.push(field);
|
|
6704
|
+
warnings.push({
|
|
6705
|
+
code: "otlp_attribute_invalid",
|
|
6706
|
+
message: "Skipped OTLP attribute without a string key.",
|
|
6707
|
+
severity: "warning",
|
|
6708
|
+
field
|
|
6709
|
+
});
|
|
6710
|
+
continue;
|
|
6711
|
+
}
|
|
6712
|
+
const parsed = parseOtlpAnyValue(
|
|
6713
|
+
item.value,
|
|
6714
|
+
`${field}.value`,
|
|
6715
|
+
warnings,
|
|
6716
|
+
unsupportedFields
|
|
6717
|
+
);
|
|
6718
|
+
if (parsed !== void 0) {
|
|
6719
|
+
attributes[item.key] = parsed;
|
|
6720
|
+
}
|
|
6721
|
+
}
|
|
6722
|
+
return { attributes, warnings, unsupportedFields };
|
|
6723
|
+
}
|
|
6724
|
+
function looksLikeOtlpSpan(value) {
|
|
6725
|
+
return isRecord13(value) && readStringField(value, ["traceId"]) !== void 0 && readStringField(value, ["spanId"]) !== void 0 && readStringField(value, ["name"]) !== void 0;
|
|
6726
|
+
}
|
|
6727
|
+
function extractOtlpDocument(root) {
|
|
6728
|
+
if (!isRecord13(root) || !Array.isArray(root.resourceSpans)) return void 0;
|
|
6729
|
+
const spans = [];
|
|
6730
|
+
const warnings = [];
|
|
6731
|
+
const unsupportedFields = [];
|
|
6732
|
+
for (const [resourceIndex, resourceSpan] of root.resourceSpans.entries()) {
|
|
6733
|
+
const resourcePath = `resourceSpans[${resourceIndex}]`;
|
|
6734
|
+
if (!isRecord13(resourceSpan)) {
|
|
6735
|
+
unsupportedFields.push(resourcePath);
|
|
6736
|
+
continue;
|
|
6737
|
+
}
|
|
6738
|
+
const resource = readRecordField(resourceSpan, "resource");
|
|
6739
|
+
const resourceParsed = parseOtlpAttributes(
|
|
6740
|
+
resource?.attributes,
|
|
6741
|
+
`${resourcePath}.resource.attributes`
|
|
6742
|
+
);
|
|
6743
|
+
warnings.push(...resourceParsed.warnings);
|
|
6744
|
+
unsupportedFields.push(...resourceParsed.unsupportedFields);
|
|
6745
|
+
if (!Array.isArray(resourceSpan.scopeSpans)) {
|
|
6746
|
+
unsupportedFields.push(`${resourcePath}.scopeSpans`);
|
|
6747
|
+
warnings.push({
|
|
6748
|
+
code: "otlp_scope_spans_missing",
|
|
6749
|
+
message: "OTLP resourceSpans entry did not contain a scopeSpans array.",
|
|
6750
|
+
severity: "warning",
|
|
6751
|
+
field: `${resourcePath}.scopeSpans`
|
|
6752
|
+
});
|
|
6753
|
+
continue;
|
|
6754
|
+
}
|
|
6755
|
+
for (const [scopeIndex, scopeSpan] of resourceSpan.scopeSpans.entries()) {
|
|
6756
|
+
const scopePath = `${resourcePath}.scopeSpans[${scopeIndex}]`;
|
|
6757
|
+
if (!isRecord13(scopeSpan)) {
|
|
6758
|
+
unsupportedFields.push(scopePath);
|
|
6759
|
+
continue;
|
|
6760
|
+
}
|
|
6761
|
+
const scope = readRecordField(scopeSpan, "scope");
|
|
6762
|
+
const scopeParsed = parseOtlpAttributes(
|
|
6763
|
+
scope?.attributes,
|
|
6764
|
+
`${scopePath}.scope.attributes`
|
|
6765
|
+
);
|
|
6766
|
+
warnings.push(...scopeParsed.warnings);
|
|
6767
|
+
unsupportedFields.push(...scopeParsed.unsupportedFields);
|
|
6768
|
+
if (!Array.isArray(scopeSpan.spans)) {
|
|
6769
|
+
unsupportedFields.push(`${scopePath}.spans`);
|
|
6770
|
+
warnings.push({
|
|
6771
|
+
code: "otlp_spans_missing",
|
|
6772
|
+
message: "OTLP scopeSpans entry did not contain a spans array.",
|
|
6773
|
+
severity: "warning",
|
|
6774
|
+
field: `${scopePath}.spans`
|
|
6775
|
+
});
|
|
6776
|
+
continue;
|
|
6777
|
+
}
|
|
6778
|
+
for (const [spanIndex, span] of scopeSpan.spans.entries()) {
|
|
6779
|
+
const spanPath = `${scopePath}.spans[${spanIndex}]`;
|
|
6780
|
+
if (!looksLikeOtlpSpan(span)) {
|
|
6781
|
+
unsupportedFields.push(spanPath);
|
|
6782
|
+
warnings.push({
|
|
6783
|
+
code: "otlp_invalid_span",
|
|
6784
|
+
message: "Skipped OTLP span without required traceId, spanId, or name.",
|
|
6785
|
+
severity: "warning",
|
|
6786
|
+
field: spanPath
|
|
6787
|
+
});
|
|
6788
|
+
continue;
|
|
6789
|
+
}
|
|
6790
|
+
spans.push({
|
|
6791
|
+
span,
|
|
6792
|
+
resourceAttributes: resourceParsed.attributes,
|
|
6793
|
+
scopeAttributes: scopeParsed.attributes,
|
|
6794
|
+
scopeName: readStringField(scope ?? {}, ["name"]),
|
|
6795
|
+
scopeVersion: readStringField(scope ?? {}, ["version"]),
|
|
6796
|
+
pathPrefix: spanPath
|
|
6797
|
+
});
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6800
|
+
}
|
|
6801
|
+
if (spans.length === 0) {
|
|
6802
|
+
warnings.push({
|
|
6803
|
+
code: "otlp_no_valid_spans",
|
|
6804
|
+
message: "OTLP JSON payload did not contain any valid spans.",
|
|
6805
|
+
severity: "error"
|
|
6806
|
+
});
|
|
6807
|
+
return {
|
|
6808
|
+
spans,
|
|
6809
|
+
confidence: 0.7,
|
|
6810
|
+
description: "Malformed OTLP JSON trace payload",
|
|
6811
|
+
warnings,
|
|
6812
|
+
unsupportedFields
|
|
6813
|
+
};
|
|
6814
|
+
}
|
|
6815
|
+
return {
|
|
6816
|
+
spans,
|
|
6817
|
+
confidence: 0.93,
|
|
6818
|
+
description: "OTLP JSON trace payload",
|
|
6819
|
+
warnings,
|
|
6820
|
+
unsupportedFields
|
|
6821
|
+
};
|
|
6822
|
+
}
|
|
6823
|
+
function mapOtlpStatus(status) {
|
|
6824
|
+
if (!isRecord13(status)) return void 0;
|
|
6825
|
+
const rawCode = status.code;
|
|
6826
|
+
if (typeof rawCode !== "string") return void 0;
|
|
6827
|
+
switch (rawCode.toUpperCase()) {
|
|
6828
|
+
case "STATUS_CODE_OK":
|
|
6829
|
+
case "OK":
|
|
6830
|
+
return "ok";
|
|
6831
|
+
case "STATUS_CODE_ERROR":
|
|
6832
|
+
case "ERROR":
|
|
6833
|
+
return "error";
|
|
6834
|
+
case "STATUS_CODE_UNSET":
|
|
6835
|
+
case "UNSET":
|
|
6836
|
+
return "unknown";
|
|
6837
|
+
default:
|
|
6838
|
+
return "unknown";
|
|
6839
|
+
}
|
|
6840
|
+
}
|
|
6841
|
+
function readOtlpKind(attributes, pathPrefix) {
|
|
6842
|
+
const warnings = [];
|
|
6843
|
+
const agentInspectKind = attributes["agent_inspect.kind"];
|
|
6844
|
+
if (agentInspectKind === "RUN" || agentInspectKind === "AGENT" || agentInspectKind === "LLM" || agentInspectKind === "TOOL" || agentInspectKind === "CHAIN" || agentInspectKind === "RETRIEVER" || agentInspectKind === "DECISION" || agentInspectKind === "RESULT" || agentInspectKind === "ERROR" || agentInspectKind === "LOGIC" || agentInspectKind === "LOG") {
|
|
6845
|
+
return { kind: agentInspectKind, warnings };
|
|
6846
|
+
}
|
|
6847
|
+
const operation = attributes["gen_ai.operation.name"];
|
|
6848
|
+
if (typeof operation === "string") {
|
|
6849
|
+
switch (operation) {
|
|
6850
|
+
case "generate_content":
|
|
6851
|
+
case "chat":
|
|
6852
|
+
return { kind: "LLM", warnings };
|
|
6853
|
+
case "execute_tool":
|
|
6854
|
+
return { kind: "TOOL", warnings };
|
|
6855
|
+
case "invoke_agent":
|
|
6856
|
+
return { kind: "AGENT", warnings };
|
|
6857
|
+
default:
|
|
6858
|
+
warnings.push({
|
|
6859
|
+
code: "otlp_gen_ai_operation_semantic_loss",
|
|
6860
|
+
message: `OTLP GenAI operation "${operation}" mapped to AgentInspect LOGIC.`,
|
|
6861
|
+
severity: "warning",
|
|
6862
|
+
field: `${pathPrefix}.attributes.gen_ai.operation.name`
|
|
6863
|
+
});
|
|
6864
|
+
return { kind: "LOGIC", warnings };
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
warnings.push({
|
|
6868
|
+
code: "otlp_kind_unknown",
|
|
6869
|
+
message: "OTLP span had no AgentInspect kind or GenAI operation; mapped to LOGIC.",
|
|
6870
|
+
severity: "warning",
|
|
6871
|
+
field: `${pathPrefix}.attributes`
|
|
6872
|
+
});
|
|
6873
|
+
return { kind: "LOGIC", warnings };
|
|
6874
|
+
}
|
|
6875
|
+
function readOtlpTokenUsage(attributes) {
|
|
6876
|
+
const input = attributes["gen_ai.usage.input_tokens"];
|
|
6877
|
+
const output = attributes["gen_ai.usage.output_tokens"];
|
|
6878
|
+
const usage = {};
|
|
6879
|
+
if (typeof input === "number" && Number.isFinite(input) && input >= 0) {
|
|
6880
|
+
usage.input = input;
|
|
6881
|
+
}
|
|
6882
|
+
if (typeof output === "number" && Number.isFinite(output) && output >= 0) {
|
|
6883
|
+
usage.output = output;
|
|
6884
|
+
}
|
|
6885
|
+
if (usage.input !== void 0 && usage.output !== void 0) {
|
|
6886
|
+
usage.total = usage.input + usage.output;
|
|
6887
|
+
}
|
|
6888
|
+
return Object.keys(usage).length > 0 ? usage : void 0;
|
|
6889
|
+
}
|
|
6890
|
+
function readOtlpConfidence(attributes) {
|
|
6891
|
+
return readOpenInferenceConfidence(attributes);
|
|
6892
|
+
}
|
|
6893
|
+
function sanitizeOtlpAttributes(attributes, pathPrefix) {
|
|
6894
|
+
const ownerPath = pathPrefix.endsWith(".attributes") ? pathPrefix.slice(0, -".attributes".length) : pathPrefix;
|
|
6895
|
+
const sanitized = sanitizeOpenInferenceAttributes(attributes, ownerPath);
|
|
6896
|
+
return {
|
|
6897
|
+
...sanitized,
|
|
6898
|
+
warnings: sanitized.warnings.map(
|
|
6899
|
+
(warning) => warning.code === "openinference_sensitive_attribute_summarized" ? {
|
|
6900
|
+
...warning,
|
|
6901
|
+
code: "otlp_sensitive_attribute_summarized",
|
|
6902
|
+
message: "OTLP prompt/output/document attribute(s) were summarized instead of copied verbatim."
|
|
6903
|
+
} : warning
|
|
6904
|
+
)
|
|
6905
|
+
};
|
|
6906
|
+
}
|
|
6907
|
+
function mapOtlpEvents(value, pathPrefix) {
|
|
6908
|
+
const warnings = [];
|
|
6909
|
+
const unsupportedFields = [];
|
|
6910
|
+
if (value === void 0) return { warnings, unsupportedFields };
|
|
6911
|
+
if (!Array.isArray(value)) {
|
|
6912
|
+
unsupportedFields.push(pathPrefix);
|
|
6913
|
+
warnings.push({
|
|
6914
|
+
code: "otlp_events_invalid",
|
|
6915
|
+
message: "OTLP events field was not an array.",
|
|
6916
|
+
severity: "warning",
|
|
6917
|
+
field: pathPrefix
|
|
6918
|
+
});
|
|
6919
|
+
return { warnings, unsupportedFields };
|
|
6920
|
+
}
|
|
6921
|
+
const events = [];
|
|
6922
|
+
for (const [index, event] of value.entries()) {
|
|
6923
|
+
const eventPath = `${pathPrefix}[${index}]`;
|
|
6924
|
+
if (!isRecord13(event)) {
|
|
6925
|
+
unsupportedFields.push(eventPath);
|
|
6926
|
+
continue;
|
|
6927
|
+
}
|
|
6928
|
+
const parsedAttributes = parseOtlpAttributes(
|
|
6929
|
+
event.attributes,
|
|
6930
|
+
`${eventPath}.attributes`
|
|
6931
|
+
);
|
|
6932
|
+
warnings.push(...parsedAttributes.warnings);
|
|
6933
|
+
unsupportedFields.push(...parsedAttributes.unsupportedFields);
|
|
6934
|
+
const sanitized = sanitizeOtlpAttributes(
|
|
6935
|
+
parsedAttributes.attributes,
|
|
6936
|
+
`${eventPath}.attributes`
|
|
6937
|
+
);
|
|
6938
|
+
warnings.push(...sanitized.warnings);
|
|
6939
|
+
unsupportedFields.push(...sanitized.unsupportedFields);
|
|
6940
|
+
const out = {};
|
|
6941
|
+
const name = readStringField(event, ["name"]);
|
|
6942
|
+
if (name !== void 0) {
|
|
6943
|
+
out.name = name;
|
|
6944
|
+
}
|
|
6945
|
+
const timestamp = parseUnixNanoToIso(event.timeUnixNano);
|
|
6946
|
+
if (timestamp !== void 0) {
|
|
6947
|
+
out.timestamp = timestamp;
|
|
6948
|
+
} else if (event.timeUnixNano !== void 0) {
|
|
6949
|
+
unsupportedFields.push(`${eventPath}.timeUnixNano`);
|
|
6950
|
+
warnings.push({
|
|
6951
|
+
code: "otlp_event_timestamp_invalid",
|
|
6952
|
+
message: "OTLP event timeUnixNano could not be parsed.",
|
|
6953
|
+
severity: "warning",
|
|
6954
|
+
field: `${eventPath}.timeUnixNano`
|
|
6955
|
+
});
|
|
6956
|
+
}
|
|
6957
|
+
if (Object.keys(sanitized.attributes).length > 0) {
|
|
6958
|
+
out.attributes = sanitized.attributes;
|
|
6959
|
+
}
|
|
6960
|
+
events.push(out);
|
|
6961
|
+
}
|
|
6962
|
+
return {
|
|
6963
|
+
events: events.length > 0 ? events : void 0,
|
|
6964
|
+
warnings,
|
|
6965
|
+
unsupportedFields
|
|
6966
|
+
};
|
|
6967
|
+
}
|
|
6968
|
+
function mapOtlpSpan(context) {
|
|
6969
|
+
const { span, pathPrefix } = context;
|
|
6970
|
+
const warnings = [];
|
|
6971
|
+
const unsupportedFields = [];
|
|
6972
|
+
const parsedSpanAttributes = parseOtlpAttributes(
|
|
6973
|
+
span.attributes,
|
|
6974
|
+
`${pathPrefix}.attributes`
|
|
6975
|
+
);
|
|
6976
|
+
warnings.push(...parsedSpanAttributes.warnings);
|
|
6977
|
+
unsupportedFields.push(...parsedSpanAttributes.unsupportedFields);
|
|
6978
|
+
const sanitizedSpanAttributes = sanitizeOtlpAttributes(
|
|
6979
|
+
parsedSpanAttributes.attributes,
|
|
6980
|
+
`${pathPrefix}.attributes`
|
|
6981
|
+
);
|
|
6982
|
+
warnings.push(...sanitizedSpanAttributes.warnings);
|
|
6983
|
+
unsupportedFields.push(...sanitizedSpanAttributes.unsupportedFields);
|
|
6984
|
+
const attributes = {
|
|
6985
|
+
...sanitizedSpanAttributes.attributes
|
|
6986
|
+
};
|
|
6987
|
+
for (const [key, value] of Object.entries(context.resourceAttributes)) {
|
|
6988
|
+
attributes[`resource.${key}`] = value;
|
|
6989
|
+
}
|
|
6990
|
+
for (const [key, value] of Object.entries(context.scopeAttributes)) {
|
|
6991
|
+
attributes[`scope.${key}`] = value;
|
|
6992
|
+
}
|
|
6993
|
+
if (context.scopeName !== void 0) {
|
|
6994
|
+
attributes["scope.name"] = context.scopeName;
|
|
6995
|
+
}
|
|
6996
|
+
if (context.scopeVersion !== void 0) {
|
|
6997
|
+
attributes["scope.version"] = context.scopeVersion;
|
|
6998
|
+
}
|
|
6999
|
+
for (const [key, value] of Object.entries(span)) {
|
|
7000
|
+
if (OTLP_SPAN_KEYS.has(key)) continue;
|
|
7001
|
+
unsupportedFields.push(`${pathPrefix}.${key}`);
|
|
7002
|
+
if (value === null || typeof value !== "object") {
|
|
7003
|
+
attributes[`otlp.${key}`] = value;
|
|
7004
|
+
} else {
|
|
7005
|
+
attributes[`otlp.${key}.summary`] = summarizeAttributeValue(value);
|
|
7006
|
+
warnings.push({
|
|
7007
|
+
code: "otlp_unsupported_field_summarized",
|
|
7008
|
+
message: `Unsupported OTLP span field "${key}" was summarized.`,
|
|
7009
|
+
severity: "warning",
|
|
7010
|
+
field: `${pathPrefix}.${key}`
|
|
7011
|
+
});
|
|
7012
|
+
}
|
|
7013
|
+
}
|
|
7014
|
+
for (const key of [
|
|
7015
|
+
"droppedAttributesCount",
|
|
7016
|
+
"droppedEventsCount",
|
|
7017
|
+
"droppedLinksCount",
|
|
7018
|
+
"links"
|
|
7019
|
+
]) {
|
|
7020
|
+
if (span[key] !== void 0) {
|
|
7021
|
+
unsupportedFields.push(`${pathPrefix}.${key}`);
|
|
7022
|
+
warnings.push({
|
|
7023
|
+
code: "otlp_span_field_not_mapped",
|
|
7024
|
+
message: `OTLP span field "${key}" is not represented in AgentInspect events.`,
|
|
7025
|
+
severity: "warning",
|
|
7026
|
+
field: `${pathPrefix}.${key}`
|
|
7027
|
+
});
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
const events = mapOtlpEvents(span.events, `${pathPrefix}.events`);
|
|
7031
|
+
warnings.push(...events.warnings);
|
|
7032
|
+
unsupportedFields.push(...events.unsupportedFields);
|
|
7033
|
+
if (events.events !== void 0) {
|
|
7034
|
+
attributes["otlp.events"] = events.events;
|
|
7035
|
+
}
|
|
7036
|
+
const traceId = readStringField(span, ["traceId"]) ?? "trace-unknown";
|
|
7037
|
+
const spanId = readStringField(span, ["spanId"]) ?? "span-unknown";
|
|
7038
|
+
const parentSpanId = readStringField(span, ["parentSpanId"]);
|
|
7039
|
+
const startedAt = readOpenInferenceTimestamp(
|
|
7040
|
+
span,
|
|
7041
|
+
["startTimeUnixNano"],
|
|
7042
|
+
[]
|
|
7043
|
+
);
|
|
7044
|
+
const endedAt = readOpenInferenceTimestamp(span, ["endTimeUnixNano"], []);
|
|
7045
|
+
const timestamp = startedAt ?? "1970-01-01T00:00:00.000Z";
|
|
7046
|
+
if (startedAt === void 0) {
|
|
7047
|
+
unsupportedFields.push(`${pathPrefix}.startTimeUnixNano`);
|
|
7048
|
+
warnings.push({
|
|
7049
|
+
code: "otlp_missing_start_time",
|
|
7050
|
+
message: "OTLP span is missing a valid startTimeUnixNano; using Unix epoch.",
|
|
7051
|
+
severity: "warning",
|
|
7052
|
+
field: `${pathPrefix}.startTimeUnixNano`
|
|
7053
|
+
});
|
|
7054
|
+
}
|
|
7055
|
+
const { kind, warnings: kindWarnings } = readOtlpKind(
|
|
7056
|
+
parsedSpanAttributes.attributes,
|
|
7057
|
+
pathPrefix
|
|
7058
|
+
);
|
|
7059
|
+
warnings.push(...kindWarnings);
|
|
7060
|
+
const status = mapOtlpStatus(span.status);
|
|
7061
|
+
const tokenUsage = readOtlpTokenUsage(parsedSpanAttributes.attributes);
|
|
7062
|
+
const errorMessage = isRecord13(span.status) && typeof span.status.message === "string" ? span.status.message : void 0;
|
|
7063
|
+
const event = {
|
|
7064
|
+
schemaVersion: "0.2",
|
|
7065
|
+
eventId: typeof parsedSpanAttributes.attributes["agent_inspect.event_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.event_id"] : spanId,
|
|
7066
|
+
runId: typeof parsedSpanAttributes.attributes["agent_inspect.run_id"] === "string" ? parsedSpanAttributes.attributes["agent_inspect.run_id"] : traceId,
|
|
7067
|
+
kind,
|
|
7068
|
+
name: readStringField(span, ["name"]) ?? spanId,
|
|
7069
|
+
timestamp,
|
|
7070
|
+
confidence: readOtlpConfidence(parsedSpanAttributes.attributes),
|
|
7071
|
+
source: {
|
|
7072
|
+
type: "otel",
|
|
7073
|
+
name: context.scopeName ?? (typeof context.resourceAttributes["service.name"] === "string" ? context.resourceAttributes["service.name"] : "otlp-json"),
|
|
7074
|
+
...context.scopeVersion !== void 0 ? { version: context.scopeVersion } : {}
|
|
7075
|
+
},
|
|
7076
|
+
attributes,
|
|
7077
|
+
trace: {
|
|
7078
|
+
traceId,
|
|
7079
|
+
spanId,
|
|
7080
|
+
...parentSpanId !== void 0 ? { parentSpanId } : {}
|
|
7081
|
+
}
|
|
7082
|
+
};
|
|
7083
|
+
if (status !== void 0) {
|
|
7084
|
+
event.status = status;
|
|
7085
|
+
}
|
|
7086
|
+
if (startedAt !== void 0) {
|
|
7087
|
+
event.startedAt = startedAt;
|
|
7088
|
+
}
|
|
7089
|
+
if (endedAt !== void 0) {
|
|
7090
|
+
event.endedAt = endedAt;
|
|
7091
|
+
}
|
|
7092
|
+
const durationMs2 = durationBetweenIso(startedAt, endedAt);
|
|
7093
|
+
if (durationMs2 !== void 0) {
|
|
7094
|
+
event.durationMs = durationMs2;
|
|
7095
|
+
}
|
|
7096
|
+
if (tokenUsage !== void 0) {
|
|
7097
|
+
event.tokenUsage = tokenUsage;
|
|
7098
|
+
}
|
|
7099
|
+
if (status === "error") {
|
|
7100
|
+
event.error = {
|
|
7101
|
+
message: errorMessage !== void 0 && errorMessage.trim() !== "" ? errorMessage : "OTLP span error"
|
|
7102
|
+
};
|
|
7103
|
+
}
|
|
7104
|
+
return {
|
|
7105
|
+
event,
|
|
7106
|
+
warnings,
|
|
7107
|
+
unsupportedFields,
|
|
7108
|
+
spanId,
|
|
7109
|
+
...parentSpanId !== void 0 ? { parentSpanId } : {}
|
|
7110
|
+
};
|
|
7111
|
+
}
|
|
7112
|
+
function mapOtlpEventsToPersisted(document) {
|
|
7113
|
+
const mapped = document.spans.map((span) => mapOtlpSpan(span));
|
|
7114
|
+
const spanIdToEventId = new Map(
|
|
7115
|
+
mapped.map((span) => [span.spanId, span.event.eventId])
|
|
7116
|
+
);
|
|
7117
|
+
for (const span of mapped) {
|
|
7118
|
+
if (span.parentSpanId === void 0) continue;
|
|
7119
|
+
span.event.parentId = spanIdToEventId.get(span.parentSpanId) ?? span.parentSpanId;
|
|
7120
|
+
}
|
|
7121
|
+
return {
|
|
7122
|
+
events: mapped.map((span) => span.event),
|
|
7123
|
+
warnings: mapped.flatMap((span) => span.warnings),
|
|
7124
|
+
unsupportedFields: mapped.flatMap((span) => span.unsupportedFields)
|
|
7125
|
+
};
|
|
7126
|
+
}
|
|
7127
|
+
var otlpJsonReader = {
|
|
7128
|
+
format: OTLP_READER_FORMAT,
|
|
7129
|
+
name: "OTLP JSON",
|
|
7130
|
+
async detect(input) {
|
|
7131
|
+
const resolved = await resolveInput(input);
|
|
7132
|
+
if (!resolved) return void 0;
|
|
7133
|
+
let parsed;
|
|
7134
|
+
try {
|
|
7135
|
+
parsed = parseJsonDocument(resolved.content);
|
|
7136
|
+
} catch {
|
|
7137
|
+
return void 0;
|
|
7138
|
+
}
|
|
7139
|
+
const document = extractOtlpDocument(parsed);
|
|
7140
|
+
if (!document) return void 0;
|
|
7141
|
+
return {
|
|
7142
|
+
format: OTLP_READER_FORMAT,
|
|
7143
|
+
confidence: document.confidence,
|
|
7144
|
+
readerName: "OTLP JSON",
|
|
7145
|
+
description: document.description,
|
|
7146
|
+
warnings: attachSingleSourceFile(document.warnings, resolved)
|
|
7147
|
+
};
|
|
7148
|
+
},
|
|
7149
|
+
async read(input) {
|
|
7150
|
+
const resolved = await resolveInput(input);
|
|
7151
|
+
if (!resolved) {
|
|
7152
|
+
throw new TraceReadError(
|
|
7153
|
+
"unsupported_format",
|
|
7154
|
+
"OTLP JSON reader requires file, string, or buffer input."
|
|
7155
|
+
);
|
|
7156
|
+
}
|
|
7157
|
+
let parsed;
|
|
7158
|
+
try {
|
|
7159
|
+
parsed = parseJsonDocument(resolved.content);
|
|
7160
|
+
} catch {
|
|
7161
|
+
throw new TraceReadError("unsupported_format", "OTLP JSON input is not valid JSON.", [
|
|
7162
|
+
{
|
|
7163
|
+
code: "otlp_invalid_json",
|
|
7164
|
+
message: "OTLP JSON reader could not parse the input as JSON.",
|
|
7165
|
+
severity: "error"
|
|
7166
|
+
}
|
|
7167
|
+
]);
|
|
7168
|
+
}
|
|
7169
|
+
const document = extractOtlpDocument(parsed);
|
|
7170
|
+
if (!document || document.spans.length === 0) {
|
|
7171
|
+
throw new TraceReadError(
|
|
7172
|
+
"unsupported_format",
|
|
7173
|
+
"No valid OTLP spans found.",
|
|
7174
|
+
attachSingleSourceFile(
|
|
7175
|
+
document?.warnings ?? [
|
|
7176
|
+
{
|
|
7177
|
+
code: "otlp_no_valid_spans",
|
|
7178
|
+
message: "OTLP JSON input did not contain valid spans.",
|
|
7179
|
+
severity: "error"
|
|
7180
|
+
}
|
|
7181
|
+
],
|
|
7182
|
+
resolved
|
|
7183
|
+
)
|
|
7184
|
+
);
|
|
7185
|
+
}
|
|
7186
|
+
const mapped = mapOtlpEventsToPersisted(document);
|
|
7187
|
+
const warnings = attachSingleSourceFile(
|
|
7188
|
+
[...document.warnings, ...mapped.warnings],
|
|
7189
|
+
resolved
|
|
7190
|
+
);
|
|
7191
|
+
const unsupportedFields = [
|
|
7192
|
+
...document.unsupportedFields,
|
|
7193
|
+
...mapped.unsupportedFields
|
|
7194
|
+
].sort((a, b) => a.localeCompare(b));
|
|
7195
|
+
return {
|
|
7196
|
+
format: OTLP_READER_FORMAT,
|
|
7197
|
+
events: mapped.events,
|
|
7198
|
+
runs: persistedInspectEventsToRunTrees(mapped.events, { skipInvalid: true }),
|
|
7199
|
+
warnings,
|
|
7200
|
+
unsupportedFields,
|
|
7201
|
+
sourceFiles: resolved.sourceFiles
|
|
7202
|
+
};
|
|
7203
|
+
}
|
|
7204
|
+
};
|
|
7205
|
+
var agentInspectJsonlReader = {
|
|
7206
|
+
format: "agent-inspect-jsonl",
|
|
7207
|
+
name: "AgentInspect JSONL",
|
|
7208
|
+
async detect(input) {
|
|
7209
|
+
const resolved = await resolveInput(input);
|
|
7210
|
+
if (!resolved) return void 0;
|
|
7211
|
+
const detected = detectJsonlFormat(resolved.content);
|
|
7212
|
+
if (detected.validRows === 0 || detected.format === "empty") {
|
|
7213
|
+
return void 0;
|
|
7214
|
+
}
|
|
7215
|
+
return {
|
|
7216
|
+
format: "agent-inspect-jsonl",
|
|
7217
|
+
confidence: 0.95,
|
|
7218
|
+
readerName: "AgentInspect JSONL",
|
|
7219
|
+
description: agentInspectFormatLabel(detected.format),
|
|
7220
|
+
warnings: attachSingleSourceFile(detected.warnings, resolved)
|
|
7221
|
+
};
|
|
7222
|
+
},
|
|
7223
|
+
async read(input) {
|
|
7224
|
+
const resolved = await resolveInput(input);
|
|
7225
|
+
if (!resolved) {
|
|
7226
|
+
throw new Error("AgentInspect JSONL reader requires file, directory, string, or buffer input.");
|
|
7227
|
+
}
|
|
7228
|
+
const parsed = parseTraceJsonl(resolved.content, { warnings: false });
|
|
7229
|
+
if (parsed.sourceEventCount === 0) {
|
|
7230
|
+
throw new Error("No valid AgentInspect JSONL events found.");
|
|
7231
|
+
}
|
|
7232
|
+
const events = persistedEventsForParsedTrace(parsed);
|
|
7233
|
+
return {
|
|
7234
|
+
format: agentInspectFormatLabel(parsed.format),
|
|
7235
|
+
events,
|
|
7236
|
+
runs: persistedInspectEventsToRunTrees(events, { skipInvalid: true }),
|
|
7237
|
+
warnings: parsed.format === "mixed" ? attachSingleSourceFile(
|
|
7238
|
+
[
|
|
7239
|
+
{
|
|
7240
|
+
code: "mixed_agent_inspect_jsonl",
|
|
7241
|
+
message: "Trace input mixes schemaVersion 0.1 and 0.2 rows; events were normalized for reading.",
|
|
7242
|
+
severity: "warning"
|
|
7243
|
+
}
|
|
7244
|
+
],
|
|
7245
|
+
resolved
|
|
7246
|
+
) : [],
|
|
7247
|
+
unsupportedFields: [],
|
|
7248
|
+
sourceFiles: resolved.sourceFiles
|
|
7249
|
+
};
|
|
7250
|
+
}
|
|
7251
|
+
};
|
|
7252
|
+
var DEFAULT_TRACE_READERS = [
|
|
7253
|
+
agentInspectJsonlReader,
|
|
7254
|
+
openInferenceJsonReader,
|
|
7255
|
+
otlpJsonReader
|
|
7256
|
+
];
|
|
7257
|
+
async function detectTraceFormat(input, options = {}) {
|
|
7258
|
+
const readers = options.readers ?? DEFAULT_TRACE_READERS;
|
|
7259
|
+
if (options.format !== void 0) {
|
|
7260
|
+
const reader = findReaderByFormat(options.format, readers);
|
|
7261
|
+
if (!reader) {
|
|
7262
|
+
return {
|
|
7263
|
+
status: "unsupported",
|
|
7264
|
+
candidates: [],
|
|
7265
|
+
warnings: [
|
|
7266
|
+
{
|
|
7267
|
+
code: "unsupported_format",
|
|
7268
|
+
message: `No trace reader is registered for format "${options.format}".`,
|
|
7269
|
+
severity: "error"
|
|
7270
|
+
}
|
|
7271
|
+
]
|
|
7272
|
+
};
|
|
7273
|
+
}
|
|
7274
|
+
return {
|
|
7275
|
+
status: "detected",
|
|
7276
|
+
format: reader.format,
|
|
7277
|
+
candidates: [
|
|
7278
|
+
{
|
|
7279
|
+
format: reader.format,
|
|
7280
|
+
confidence: 1,
|
|
7281
|
+
readerName: reader.name,
|
|
7282
|
+
description: "Explicit format override"
|
|
7283
|
+
}
|
|
7284
|
+
],
|
|
7285
|
+
warnings: []
|
|
7286
|
+
};
|
|
7287
|
+
}
|
|
7288
|
+
const candidates = [];
|
|
7289
|
+
const warnings = [];
|
|
7290
|
+
for (const reader of readers) {
|
|
7291
|
+
try {
|
|
7292
|
+
const candidate = await reader.detect(input);
|
|
7293
|
+
if (candidate !== void 0) {
|
|
7294
|
+
candidates.push(normalizeCandidate(reader, candidate));
|
|
7295
|
+
}
|
|
7296
|
+
} catch (error) {
|
|
7297
|
+
if (error instanceof TraceReadError) {
|
|
7298
|
+
warnings.push(...error.warnings);
|
|
7299
|
+
continue;
|
|
7300
|
+
}
|
|
7301
|
+
warnings.push({
|
|
7302
|
+
code: "reader_detect_failed",
|
|
7303
|
+
message: error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed during detection.`,
|
|
7304
|
+
severity: "warning"
|
|
7305
|
+
});
|
|
7306
|
+
}
|
|
7307
|
+
}
|
|
7308
|
+
const sorted = sortCandidates(
|
|
7309
|
+
candidates.filter((candidate) => candidate.confidence >= MIN_DETECTION_CONFIDENCE)
|
|
7310
|
+
);
|
|
7311
|
+
const candidateWarnings = collectWarnings(sorted);
|
|
7312
|
+
const lowConfidenceWarnings = candidates.length > sorted.length ? [
|
|
7313
|
+
{
|
|
7314
|
+
code: "low_confidence_candidates",
|
|
7315
|
+
message: `Ignored ${candidates.length - sorted.length} low-confidence format candidate(s).`,
|
|
7316
|
+
severity: "info"
|
|
7317
|
+
}
|
|
7318
|
+
] : [];
|
|
7319
|
+
const allWarnings = dedupeWarnings([
|
|
7320
|
+
...warnings,
|
|
7321
|
+
...candidateWarnings,
|
|
7322
|
+
...lowConfidenceWarnings
|
|
7323
|
+
]);
|
|
7324
|
+
if (sorted.length === 0) {
|
|
7325
|
+
return {
|
|
7326
|
+
status: "unsupported",
|
|
7327
|
+
candidates: [],
|
|
7328
|
+
warnings: allWarnings
|
|
7329
|
+
};
|
|
7330
|
+
}
|
|
7331
|
+
const [best, second] = sorted;
|
|
7332
|
+
if (second !== void 0 && best.confidence - second.confidence <= AMBIGUOUS_CONFIDENCE_DELTA) {
|
|
7333
|
+
return {
|
|
7334
|
+
status: "ambiguous",
|
|
7335
|
+
candidates: sorted,
|
|
7336
|
+
warnings: [
|
|
7337
|
+
...allWarnings,
|
|
7338
|
+
{
|
|
7339
|
+
code: "ambiguous_format_candidates",
|
|
7340
|
+
message: `Top trace format candidates are within ${AMBIGUOUS_CONFIDENCE_DELTA} confidence.`,
|
|
7341
|
+
severity: "warning"
|
|
7342
|
+
}
|
|
7343
|
+
]
|
|
7344
|
+
};
|
|
7345
|
+
}
|
|
7346
|
+
return {
|
|
7347
|
+
status: "detected",
|
|
7348
|
+
format: best.format,
|
|
7349
|
+
candidates: sorted,
|
|
7350
|
+
warnings: allWarnings
|
|
7351
|
+
};
|
|
7352
|
+
}
|
|
7353
|
+
async function readTrace(input, options = {}) {
|
|
7354
|
+
const readers = options.readers ?? DEFAULT_TRACE_READERS;
|
|
7355
|
+
const detection = await detectTraceFormat(input, options);
|
|
7356
|
+
if (detection.status === "unsupported" || detection.format === void 0) {
|
|
7357
|
+
throw new TraceReadError(
|
|
7358
|
+
"unsupported_format",
|
|
7359
|
+
"No trace reader could detect the input format.",
|
|
7360
|
+
detection.warnings
|
|
7361
|
+
);
|
|
7362
|
+
}
|
|
7363
|
+
if (detection.status === "ambiguous") {
|
|
7364
|
+
throw new TraceReadError(
|
|
7365
|
+
"ambiguous_format",
|
|
7366
|
+
"Multiple trace readers matched the input with equal confidence.",
|
|
7367
|
+
detection.warnings
|
|
7368
|
+
);
|
|
7369
|
+
}
|
|
7370
|
+
const reader = findReaderByFormat(detection.format, readers);
|
|
7371
|
+
if (!reader) {
|
|
7372
|
+
throw new TraceReadError(
|
|
7373
|
+
"unsupported_format",
|
|
7374
|
+
`No trace reader is registered for format "${detection.format}".`,
|
|
7375
|
+
detection.warnings
|
|
7376
|
+
);
|
|
7377
|
+
}
|
|
7378
|
+
try {
|
|
7379
|
+
const result = await reader.read(input, { format: detection.format });
|
|
7380
|
+
return {
|
|
7381
|
+
...result,
|
|
7382
|
+
format: result.format || detection.format,
|
|
7383
|
+
warnings: [...detection.warnings, ...result.warnings]
|
|
7384
|
+
};
|
|
7385
|
+
} catch (error) {
|
|
7386
|
+
if (error instanceof TraceReadError) {
|
|
7387
|
+
throw new TraceReadError(
|
|
7388
|
+
error.code,
|
|
7389
|
+
error.message,
|
|
7390
|
+
dedupeWarnings([...detection.warnings, ...error.warnings])
|
|
7391
|
+
);
|
|
7392
|
+
}
|
|
7393
|
+
throw new TraceReadError(
|
|
7394
|
+
"reader_failed",
|
|
7395
|
+
error instanceof Error && error.message.trim() !== "" ? error.message : `Trace reader "${reader.format}" failed.`,
|
|
7396
|
+
detection.warnings
|
|
7397
|
+
);
|
|
7398
|
+
}
|
|
7399
|
+
}
|
|
7400
|
+
function openTrace(input, options = {}) {
|
|
7401
|
+
return readTrace(input, options);
|
|
7402
|
+
}
|
|
7403
|
+
|
|
7404
|
+
// packages/core/src/diff/comparable.ts
|
|
7405
|
+
function extractOutputPreview(meta) {
|
|
7406
|
+
if (meta === void 0) return void 0;
|
|
7407
|
+
if ("outputPreview" in meta) return meta.outputPreview;
|
|
7408
|
+
if ("resultPreview" in meta) return meta.resultPreview;
|
|
7409
|
+
return void 0;
|
|
7410
|
+
}
|
|
7411
|
+
function mapStepStatus2(s) {
|
|
7412
|
+
if (s === void 0) return "running";
|
|
7413
|
+
return s;
|
|
7414
|
+
}
|
|
7415
|
+
function manualTraceEventsToComparableRun(events) {
|
|
7416
|
+
const started = events.find((e) => e.event === "run_started");
|
|
7417
|
+
if (!started || started.event !== "run_started") {
|
|
7418
|
+
throw new Error("Invalid trace: missing run_started");
|
|
7419
|
+
}
|
|
7420
|
+
const rs = started;
|
|
7421
|
+
const runId = rs.runId;
|
|
7422
|
+
const completedAll = events.filter((e) => e.event === "run_completed");
|
|
7423
|
+
const lastCompleted = completedAll[completedAll.length - 1];
|
|
7424
|
+
let runStatus;
|
|
7425
|
+
if (lastCompleted === void 0) runStatus = "running";
|
|
7426
|
+
else runStatus = lastCompleted.status;
|
|
7427
|
+
const durationMs2 = lastCompleted !== void 0 && Number.isFinite(lastCompleted.durationMs) ? lastCompleted.durationMs : void 0;
|
|
7428
|
+
const steps = /* @__PURE__ */ new Map();
|
|
7429
|
+
let order = 0;
|
|
7430
|
+
for (const e of events) {
|
|
7431
|
+
if (e.event !== "step_started") continue;
|
|
7432
|
+
const s = e;
|
|
7433
|
+
const meta = s.metadata ? { ...s.metadata } : void 0;
|
|
7434
|
+
steps.set(s.stepId, {
|
|
7435
|
+
id: s.stepId,
|
|
7436
|
+
parentId: s.parentId,
|
|
7437
|
+
name: s.name,
|
|
7438
|
+
type: s.type,
|
|
7439
|
+
order: order++,
|
|
7440
|
+
timestamp: s.timestamp,
|
|
7441
|
+
metadata: meta
|
|
7442
|
+
});
|
|
7443
|
+
}
|
|
7444
|
+
for (const e of events) {
|
|
7445
|
+
if (e.event !== "step_completed") continue;
|
|
7446
|
+
const acc = steps.get(e.stepId);
|
|
7447
|
+
if (!acc) continue;
|
|
7448
|
+
acc.status = e.status;
|
|
7449
|
+
acc.durationMs = e.durationMs;
|
|
7450
|
+
if (e.error?.message) acc.errorMsg = e.error.message;
|
|
7451
|
+
const extra = e;
|
|
7452
|
+
if (extra.metadata !== void 0 && typeof extra.metadata === "object") {
|
|
7453
|
+
acc.metadata = { ...acc.metadata ?? {}, ...extra.metadata };
|
|
7454
|
+
}
|
|
7455
|
+
}
|
|
7456
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
7457
|
+
for (const acc of steps.values()) {
|
|
7458
|
+
let meta = acc.metadata ? { ...acc.metadata } : void 0;
|
|
7459
|
+
if (acc.parentId !== void 0 && !steps.has(acc.parentId)) {
|
|
7460
|
+
meta = { ...meta ?? {}, agent_inspect_diff_parent_missing: true };
|
|
4728
7461
|
}
|
|
4729
7462
|
const outputPreview = extractOutputPreview(meta);
|
|
4730
7463
|
const sc = {
|
|
@@ -4762,7 +7495,7 @@ function manualTraceEventsToComparableRun(events) {
|
|
|
4762
7495
|
runId,
|
|
4763
7496
|
name: rs.name,
|
|
4764
7497
|
status: runStatus,
|
|
4765
|
-
durationMs,
|
|
7498
|
+
durationMs: durationMs2,
|
|
4766
7499
|
steps: roots
|
|
4767
7500
|
};
|
|
4768
7501
|
}
|
|
@@ -4807,13 +7540,13 @@ function pairSteps(left, right) {
|
|
|
4807
7540
|
return pairs;
|
|
4808
7541
|
}
|
|
4809
7542
|
function compareLeafSteps(L, R, segments, opts, out) {
|
|
4810
|
-
const
|
|
7543
|
+
const path7 = buildPath(segments);
|
|
4811
7544
|
if (L.name !== R.name) {
|
|
4812
7545
|
out.push({
|
|
4813
7546
|
kind: "structure",
|
|
4814
7547
|
severity: "warning",
|
|
4815
7548
|
message: "Step name differs",
|
|
4816
|
-
path:
|
|
7549
|
+
path: path7,
|
|
4817
7550
|
left: L.name,
|
|
4818
7551
|
right: R.name
|
|
4819
7552
|
});
|
|
@@ -4823,7 +7556,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
4823
7556
|
kind: "step-type",
|
|
4824
7557
|
severity: "warning",
|
|
4825
7558
|
message: "Step type differs",
|
|
4826
|
-
path:
|
|
7559
|
+
path: path7,
|
|
4827
7560
|
left: L.type,
|
|
4828
7561
|
right: R.type
|
|
4829
7562
|
});
|
|
@@ -4833,7 +7566,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
4833
7566
|
kind: "step-status",
|
|
4834
7567
|
severity: "warning",
|
|
4835
7568
|
message: "Step status differs",
|
|
4836
|
-
path:
|
|
7569
|
+
path: path7,
|
|
4837
7570
|
left: L.status,
|
|
4838
7571
|
right: R.status
|
|
4839
7572
|
});
|
|
@@ -4845,7 +7578,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
4845
7578
|
kind: "error",
|
|
4846
7579
|
severity: "error",
|
|
4847
7580
|
message: "Step error message differs",
|
|
4848
|
-
path:
|
|
7581
|
+
path: path7,
|
|
4849
7582
|
left: le || void 0,
|
|
4850
7583
|
right: re || void 0
|
|
4851
7584
|
});
|
|
@@ -4863,7 +7596,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
4863
7596
|
kind: "duration",
|
|
4864
7597
|
severity: "info",
|
|
4865
7598
|
message: "Step duration differs",
|
|
4866
|
-
path:
|
|
7599
|
+
path: path7,
|
|
4867
7600
|
left: ld,
|
|
4868
7601
|
right: rd
|
|
4869
7602
|
});
|
|
@@ -4876,7 +7609,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
4876
7609
|
kind: "metadata",
|
|
4877
7610
|
severity: "info",
|
|
4878
7611
|
message: "Step metadata differs",
|
|
4879
|
-
path:
|
|
7612
|
+
path: path7,
|
|
4880
7613
|
left: L.metadata,
|
|
4881
7614
|
right: R.metadata
|
|
4882
7615
|
});
|
|
@@ -4888,7 +7621,7 @@ function compareLeafSteps(L, R, segments, opts, out) {
|
|
|
4888
7621
|
kind: "output",
|
|
4889
7622
|
severity: "info",
|
|
4890
7623
|
message: "Output preview differs",
|
|
4891
|
-
path:
|
|
7624
|
+
path: path7,
|
|
4892
7625
|
left: L.outputPreview,
|
|
4893
7626
|
right: R.outputPreview
|
|
4894
7627
|
});
|
|
@@ -5538,11 +8271,11 @@ createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
5538
8271
|
var source_default = chalk;
|
|
5539
8272
|
|
|
5540
8273
|
// packages/core/src/diff/renderer.ts
|
|
5541
|
-
function formatPath(
|
|
5542
|
-
if (
|
|
8274
|
+
function formatPath(path7) {
|
|
8275
|
+
if (path7 === void 0 || path7.path.length === 0) {
|
|
5543
8276
|
return "(run)";
|
|
5544
8277
|
}
|
|
5545
|
-
return
|
|
8278
|
+
return path7.path.map((s) => s.name).join(" > ");
|
|
5546
8279
|
}
|
|
5547
8280
|
function formatValue(v, verbose) {
|
|
5548
8281
|
if (v === void 0) return "(undefined)";
|
|
@@ -5657,15 +8390,15 @@ function getStatusIcon(status) {
|
|
|
5657
8390
|
if (status === "error") return source_default.red("\u2716");
|
|
5658
8391
|
return source_default.yellow("\u23F3");
|
|
5659
8392
|
}
|
|
5660
|
-
function renderStepLine(name,
|
|
8393
|
+
function renderStepLine(name, durationMs2, status, depth) {
|
|
5661
8394
|
try {
|
|
5662
8395
|
const nm = formatTerminalName(name);
|
|
5663
8396
|
const ind = getIndent(depth ?? 0);
|
|
5664
|
-
if (status === "running" &&
|
|
8397
|
+
if (status === "running" && durationMs2 === void 0) {
|
|
5665
8398
|
return `${ind}${source_default.yellow("\u23F3")} ${nm}`;
|
|
5666
8399
|
}
|
|
5667
|
-
const hasDur =
|
|
5668
|
-
const dur = hasDur ? formatDuration2(
|
|
8400
|
+
const hasDur = durationMs2 !== void 0 && Number.isFinite(durationMs2);
|
|
8401
|
+
const dur = hasDur ? formatDuration2(durationMs2) : void 0;
|
|
5669
8402
|
if (status === "running") {
|
|
5670
8403
|
return dur !== void 0 ? `${ind}${source_default.yellow("\u23F3")} ${nm} (${dur})` : `${ind}${source_default.yellow("\u23F3")} ${nm}`;
|
|
5671
8404
|
}
|
|
@@ -5689,9 +8422,9 @@ function renderErrorLine(error, depth) {
|
|
|
5689
8422
|
return "";
|
|
5690
8423
|
}
|
|
5691
8424
|
}
|
|
5692
|
-
function renderRunSummary(
|
|
8425
|
+
function renderRunSummary(durationMs2, status, traceFilePath) {
|
|
5693
8426
|
try {
|
|
5694
|
-
const dur = Number.isFinite(
|
|
8427
|
+
const dur = Number.isFinite(durationMs2) ? formatDuration2(durationMs2) : formatDuration2(0);
|
|
5695
8428
|
const head = status === "error" ? `Failed in ${dur}` : `Completed in ${dur}`;
|
|
5696
8429
|
const lines = [head];
|
|
5697
8430
|
if (traceFilePath !== void 0 && traceFilePath.trim() !== "") {
|
|
@@ -5718,10 +8451,10 @@ function printStepStart(name, depth = 0) {
|
|
|
5718
8451
|
} catch {
|
|
5719
8452
|
}
|
|
5720
8453
|
}
|
|
5721
|
-
function printStepComplete(name,
|
|
8454
|
+
function printStepComplete(name, durationMs2, status, depth = 0) {
|
|
5722
8455
|
if (isSilentContext()) return;
|
|
5723
8456
|
try {
|
|
5724
|
-
safePrint(renderStepLine(name,
|
|
8457
|
+
safePrint(renderStepLine(name, durationMs2, status, depth));
|
|
5725
8458
|
} catch {
|
|
5726
8459
|
}
|
|
5727
8460
|
}
|
|
@@ -5732,10 +8465,10 @@ function printError(error, depth = 0) {
|
|
|
5732
8465
|
} catch {
|
|
5733
8466
|
}
|
|
5734
8467
|
}
|
|
5735
|
-
function printRunComplete(_name, _runId,
|
|
8468
|
+
function printRunComplete(_name, _runId, durationMs2, status, traceFilePath) {
|
|
5736
8469
|
if (isSilentContext()) return;
|
|
5737
8470
|
try {
|
|
5738
|
-
const lines = renderRunSummary(
|
|
8471
|
+
const lines = renderRunSummary(durationMs2, status, traceFilePath);
|
|
5739
8472
|
for (let i = 0; i < lines.length; i++) {
|
|
5740
8473
|
const line = lines[i];
|
|
5741
8474
|
if (i === 0) {
|
|
@@ -5818,7 +8551,7 @@ async function inspectRun(name, fn, options) {
|
|
|
5818
8551
|
result = await Promise.resolve(fn());
|
|
5819
8552
|
} catch (userError) {
|
|
5820
8553
|
const endTime2 = Date.now();
|
|
5821
|
-
const
|
|
8554
|
+
const durationMs3 = endTime2 - startTime;
|
|
5822
8555
|
const formatted = formatError(userError);
|
|
5823
8556
|
const printPath2 = traceFilePath ?? getTraceFilePath(runId, traceDir);
|
|
5824
8557
|
await safeInstrumentation("writeTraceEvent(run_completed error)", async () => {
|
|
@@ -5829,7 +8562,7 @@ async function inspectRun(name, fn, options) {
|
|
|
5829
8562
|
runId,
|
|
5830
8563
|
status: "error",
|
|
5831
8564
|
endTime: endTime2,
|
|
5832
|
-
durationMs:
|
|
8565
|
+
durationMs: durationMs3,
|
|
5833
8566
|
error: formatted
|
|
5834
8567
|
};
|
|
5835
8568
|
await writeTraceEvent(
|
|
@@ -5838,12 +8571,12 @@ async function inspectRun(name, fn, options) {
|
|
|
5838
8571
|
);
|
|
5839
8572
|
});
|
|
5840
8573
|
await safeInstrumentation("printRunComplete(error)", () => {
|
|
5841
|
-
printRunComplete(runName, runId,
|
|
8574
|
+
printRunComplete(runName, runId, durationMs3, "error", printPath2);
|
|
5842
8575
|
});
|
|
5843
8576
|
throw userError;
|
|
5844
8577
|
}
|
|
5845
8578
|
const endTime = Date.now();
|
|
5846
|
-
const
|
|
8579
|
+
const durationMs2 = endTime - startTime;
|
|
5847
8580
|
const printPath = traceFilePath ?? getTraceFilePath(runId, traceDir);
|
|
5848
8581
|
await safeInstrumentation("writeTraceEvent(run_completed success)", async () => {
|
|
5849
8582
|
const completed = {
|
|
@@ -5853,7 +8586,7 @@ async function inspectRun(name, fn, options) {
|
|
|
5853
8586
|
runId,
|
|
5854
8587
|
status: "success",
|
|
5855
8588
|
endTime,
|
|
5856
|
-
durationMs
|
|
8589
|
+
durationMs: durationMs2
|
|
5857
8590
|
};
|
|
5858
8591
|
await writeTraceEvent(
|
|
5859
8592
|
prepareTraceEventForDisk(completed, traceSafety),
|
|
@@ -5861,7 +8594,7 @@ async function inspectRun(name, fn, options) {
|
|
|
5861
8594
|
);
|
|
5862
8595
|
});
|
|
5863
8596
|
await safeInstrumentation("printRunComplete(success)", () => {
|
|
5864
|
-
printRunComplete(runName, runId,
|
|
8597
|
+
printRunComplete(runName, runId, durationMs2, "success", printPath);
|
|
5865
8598
|
});
|
|
5866
8599
|
return result;
|
|
5867
8600
|
}, traceSafety);
|
|
@@ -5943,7 +8676,7 @@ async function stepImpl(name, fn, options) {
|
|
|
5943
8676
|
});
|
|
5944
8677
|
} catch (userError) {
|
|
5945
8678
|
const endTime2 = Date.now();
|
|
5946
|
-
const
|
|
8679
|
+
const durationMs3 = endTime2 - startTime;
|
|
5947
8680
|
const formatted = formatError(userError);
|
|
5948
8681
|
await safeInstrumentation2("writeTraceEvent(step_completed error)", async () => {
|
|
5949
8682
|
const completed = {
|
|
@@ -5954,14 +8687,14 @@ async function stepImpl(name, fn, options) {
|
|
|
5954
8687
|
stepId,
|
|
5955
8688
|
status: "error",
|
|
5956
8689
|
endTime: endTime2,
|
|
5957
|
-
durationMs:
|
|
8690
|
+
durationMs: durationMs3,
|
|
5958
8691
|
error: formatted
|
|
5959
8692
|
};
|
|
5960
8693
|
const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
|
|
5961
8694
|
await writeTraceEvent(safe, context.traceDir);
|
|
5962
8695
|
});
|
|
5963
8696
|
await safeInstrumentation2("printStepComplete(error)", () => {
|
|
5964
|
-
printStepComplete(stepName,
|
|
8697
|
+
printStepComplete(stepName, durationMs3, "error", renderDepth);
|
|
5965
8698
|
});
|
|
5966
8699
|
await safeInstrumentation2("printError", () => {
|
|
5967
8700
|
printError(formatted, renderDepth);
|
|
@@ -5972,7 +8705,7 @@ async function stepImpl(name, fn, options) {
|
|
|
5972
8705
|
throw userError;
|
|
5973
8706
|
}
|
|
5974
8707
|
const endTime = Date.now();
|
|
5975
|
-
const
|
|
8708
|
+
const durationMs2 = endTime - startTime;
|
|
5976
8709
|
await safeInstrumentation2("writeTraceEvent(step_completed success)", async () => {
|
|
5977
8710
|
const completed = {
|
|
5978
8711
|
schemaVersion: "0.1",
|
|
@@ -5982,13 +8715,13 @@ async function stepImpl(name, fn, options) {
|
|
|
5982
8715
|
stepId,
|
|
5983
8716
|
status: "success",
|
|
5984
8717
|
endTime,
|
|
5985
|
-
durationMs
|
|
8718
|
+
durationMs: durationMs2
|
|
5986
8719
|
};
|
|
5987
8720
|
const safe = traceSafety !== void 0 ? prepareTraceEventForDisk(completed, traceSafety) : completed;
|
|
5988
8721
|
await writeTraceEvent(safe, context.traceDir);
|
|
5989
8722
|
});
|
|
5990
8723
|
await safeInstrumentation2("printStepComplete(success)", () => {
|
|
5991
|
-
printStepComplete(stepName,
|
|
8724
|
+
printStepComplete(stepName, durationMs2, "success", renderDepth);
|
|
5992
8725
|
});
|
|
5993
8726
|
return result;
|
|
5994
8727
|
}
|
|
@@ -6463,6 +9196,7 @@ exports.DEFAULT_MAX_METADATA_VALUE_LENGTH = DEFAULT_MAX_METADATA_VALUE_LENGTH;
|
|
|
6463
9196
|
exports.DEFAULT_MAX_PREVIEW_LENGTH = DEFAULT_MAX_PREVIEW_LENGTH;
|
|
6464
9197
|
exports.DEFAULT_REDACT_KEYS = DEFAULT_REDACT_KEYS;
|
|
6465
9198
|
exports.DEFAULT_TRACE_DIR_NAME = DEFAULT_TRACE_DIR_NAME;
|
|
9199
|
+
exports.DEFAULT_TRACE_READERS = DEFAULT_TRACE_READERS;
|
|
6466
9200
|
exports.EXPORT_PAYLOAD_VERSION = EXPORT_PAYLOAD_VERSION;
|
|
6467
9201
|
exports.EventNormalizer = EventNormalizer;
|
|
6468
9202
|
exports.FALLBACK_TRACE_DIR = FALLBACK_TRACE_DIR;
|
|
@@ -6476,15 +9210,22 @@ exports.RUNS_DIR_NAME = RUNS_DIR_NAME;
|
|
|
6476
9210
|
exports.Redactor = Redactor;
|
|
6477
9211
|
exports.TERMINAL_INDENT = TERMINAL_INDENT;
|
|
6478
9212
|
exports.TraceDirectory = TraceDirectory;
|
|
9213
|
+
exports.TraceReadError = TraceReadError;
|
|
6479
9214
|
exports.TreeBuilder = TreeBuilder;
|
|
9215
|
+
exports.agentInspectJsonlReader = agentInspectJsonlReader;
|
|
9216
|
+
exports.bufferedFileWriter = bufferedFileWriter;
|
|
6480
9217
|
exports.buildRunReport = buildRunReport;
|
|
6481
9218
|
exports.buildRunSummary = buildRunSummary;
|
|
6482
9219
|
exports.buildRunTimeline = buildRunTimeline;
|
|
6483
9220
|
exports.buildRunWhatSummary = buildRunWhatSummary;
|
|
6484
9221
|
exports.buildTraceStats = buildTraceStats;
|
|
6485
9222
|
exports.compactAttributes = compactAttributes4;
|
|
9223
|
+
exports.compositeWriter = compositeWriter;
|
|
9224
|
+
exports.createInspector = createInspector;
|
|
9225
|
+
exports.createInspectorRuntime = createInspectorRuntime;
|
|
6486
9226
|
exports.createRunId = createRunId;
|
|
6487
9227
|
exports.createStepId = createStepId;
|
|
9228
|
+
exports.detectTraceFormat = detectTraceFormat;
|
|
6488
9229
|
exports.diffRuns = diffRuns;
|
|
6489
9230
|
exports.diffTraceEvents = diffTraceEvents;
|
|
6490
9231
|
exports.ensureTraceDir = ensureTraceDir;
|
|
@@ -6496,6 +9237,7 @@ exports.exportOpenInference = exportOpenInference;
|
|
|
6496
9237
|
exports.exportOtlpJson = exportOtlpJson;
|
|
6497
9238
|
exports.exportRunTree = exportRunTree;
|
|
6498
9239
|
exports.extractMetadata = extractMetadata;
|
|
9240
|
+
exports.fileWriter = fileWriter;
|
|
6499
9241
|
exports.filterTraces = filterTraces;
|
|
6500
9242
|
exports.flattenTree = flattenTree;
|
|
6501
9243
|
exports.formatDuration = formatDuration2;
|
|
@@ -6534,9 +9276,12 @@ exports.manualTraceEventsToComparableRun = manualTraceEventsToComparableRun;
|
|
|
6534
9276
|
exports.manualTraceEventsToRunTree = manualTraceEventsToRunTree;
|
|
6535
9277
|
exports.matchMapping = matchMapping;
|
|
6536
9278
|
exports.maybeInspectRun = maybeInspectRun;
|
|
9279
|
+
exports.memoryWriter = memoryWriter;
|
|
6537
9280
|
exports.mergeExportDefaults = mergeExportDefaults;
|
|
6538
9281
|
exports.mergeLogIngestConfig = mergeLogIngestConfig;
|
|
9282
|
+
exports.nullWriter = nullWriter;
|
|
6539
9283
|
exports.observe = observe;
|
|
9284
|
+
exports.openTrace = openTrace;
|
|
6540
9285
|
exports.parseDuration = parseDuration;
|
|
6541
9286
|
exports.parseDurationFilter = parseDurationFilter;
|
|
6542
9287
|
exports.parseLogLine = parseLogLine;
|
|
@@ -6555,6 +9300,7 @@ exports.printRunComplete = printRunComplete;
|
|
|
6555
9300
|
exports.printRunStart = printRunStart;
|
|
6556
9301
|
exports.printStepComplete = printStepComplete;
|
|
6557
9302
|
exports.printStepStart = printStepStart;
|
|
9303
|
+
exports.readTrace = readTrace;
|
|
6558
9304
|
exports.readTraceEvents = readTraceEvents;
|
|
6559
9305
|
exports.readTraceFile = readTraceFile;
|
|
6560
9306
|
exports.redactRunTreeForExport = redactRunTreeForExport;
|