agent-inspect 6.31.5 → 6.31.7
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 +13 -0
- package/README.md +1 -1
- package/docs/AI-SDK-ADOPTION.md +62 -34
- package/docs/SAFE-TRACE-SHARING.md +1 -1
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-LKEPABND.mjs → chunk-QV73NM25.mjs} +100 -31
- package/packages/cli/dist/chunk-QV73NM25.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +474 -92
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +379 -67
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-4WYF5RFI.mjs → src-KFOBXFPN.mjs} +3 -3
- package/packages/cli/dist/{src-4WYF5RFI.mjs.map → src-KFOBXFPN.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +95 -23
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.mjs +11 -11
- package/packages/core/dist/checks.cjs +2 -5
- package/packages/core/dist/checks.cjs.map +1 -1
- package/packages/core/dist/checks.mjs +3 -3
- package/packages/core/dist/{chunk-OSGNGRHF.mjs → chunk-3RV3JILQ.mjs} +34 -16
- package/packages/core/dist/chunk-3RV3JILQ.mjs.map +1 -0
- package/packages/core/dist/{chunk-NY4ILMXK.mjs → chunk-7YYS742B.mjs} +50 -13
- package/packages/core/dist/chunk-7YYS742B.mjs.map +1 -0
- package/packages/core/dist/{chunk-2KJR6X4V.mjs → chunk-DK3OW6UI.mjs} +3 -3
- package/packages/core/dist/chunk-DK3OW6UI.mjs.map +1 -0
- package/packages/core/dist/{chunk-PKDBFBJ7.mjs → chunk-LXYPM2ZO.mjs} +5 -8
- package/packages/core/dist/{chunk-PKDBFBJ7.mjs.map → chunk-LXYPM2ZO.mjs.map} +1 -1
- package/packages/core/dist/{chunk-INE5IWLN.mjs → chunk-N5PZAI6Q.mjs} +3 -3
- package/packages/core/dist/{chunk-INE5IWLN.mjs.map → chunk-N5PZAI6Q.mjs.map} +1 -1
- package/packages/core/dist/{chunk-Q5SLKV2Y.mjs → chunk-QLYUWKK7.mjs} +19 -2
- package/packages/core/dist/chunk-QLYUWKK7.mjs.map +1 -0
- package/packages/core/dist/{chunk-MTMTXTJL.mjs → chunk-VQUB3WRI.mjs} +4 -4
- package/packages/core/dist/{chunk-MTMTXTJL.mjs.map → chunk-VQUB3WRI.mjs.map} +1 -1
- package/packages/core/dist/exporters.cjs +253 -50
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +208 -42
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/index.cjs +1 -1
- package/packages/core/dist/index.cjs.map +1 -1
- package/packages/core/dist/index.mjs +4 -4
- package/packages/core/dist/persisted.cjs +17 -0
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.mjs +2 -2
- package/packages/core/dist/readers.cjs +48 -13
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.mjs +2 -2
- package/packages/core/dist/writers.cjs +1 -1
- package/packages/core/dist/writers.cjs.map +1 -1
- package/packages/core/dist/writers.mjs +1 -1
- package/packages/cli/dist/chunk-LKEPABND.mjs.map +0 -1
- package/packages/core/dist/chunk-2KJR6X4V.mjs.map +0 -1
- package/packages/core/dist/chunk-NY4ILMXK.mjs.map +0 -1
- package/packages/core/dist/chunk-OSGNGRHF.mjs.map +0 -1
- package/packages/core/dist/chunk-Q5SLKV2Y.mjs.map +0 -1
|
@@ -185,7 +185,7 @@ var Redactor = class {
|
|
|
185
185
|
};
|
|
186
186
|
|
|
187
187
|
// packages/core/src/safety/credential-value-patterns.ts
|
|
188
|
-
var KEY_VALUE_SECRET_PATTERN = /\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=(?!\[(?:REDACTED(?::[^\]]*)?|HASH:[0-9a-f]{8})\](?![^\s"'
|
|
188
|
+
var KEY_VALUE_SECRET_PATTERN = /\b(?:api[_-]?key|internal[_-]?token|access[_-]?token|auth[_-]?token|password|secret|token)=(?!\[(?:REDACTED(?::[^\]]*)?|HASH:[0-9a-f]{8})\](?![^\s"'\\&#?]))([^\s"'\\]{8,})/i;
|
|
189
189
|
var HIGH_CONFIDENCE_CREDENTIAL_PATTERNS = [
|
|
190
190
|
/^(?:basic|bearer|digest|apikey)\s+[a-z0-9._~+/=-]+$/i,
|
|
191
191
|
/\bbearer\s+[a-z0-9._~+/=-]{12,}\b/i,
|
|
@@ -223,6 +223,8 @@ var CONNECTION_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
|
223
223
|
"amqps:"
|
|
224
224
|
]);
|
|
225
225
|
var CONNECTION_URI = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^\s]+$/i;
|
|
226
|
+
var CONNECTION_USERINFO = /^(postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/([^@/?#]+)@(.+)$/i;
|
|
227
|
+
var CONNECTION_HAS_USERINFO = /^(?:postgres|postgresql|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?):\/\/[^@/?#]+@/i;
|
|
226
228
|
var UUID_SEGMENT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
227
229
|
var HEX_SEGMENT = /^[0-9a-f]{12,}$/i;
|
|
228
230
|
var NUMERIC_SEGMENT = /^\d{5,}$/;
|
|
@@ -246,6 +248,28 @@ function parseRedactableUrl(value) {
|
|
|
246
248
|
return void 0;
|
|
247
249
|
}
|
|
248
250
|
}
|
|
251
|
+
function redactConnectionUserinfoFallback(value, replacement) {
|
|
252
|
+
const trimmed = value.trim();
|
|
253
|
+
const match = CONNECTION_USERINFO.exec(trimmed);
|
|
254
|
+
if (match) {
|
|
255
|
+
const [, scheme, , rest] = match;
|
|
256
|
+
if (scheme && rest && rest.length > 0) {
|
|
257
|
+
return {
|
|
258
|
+
value: `${scheme}://${rest}`,
|
|
259
|
+
credentialRedacted: true,
|
|
260
|
+
identifiersMasked: false
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (looksLikeConnectionUri(trimmed) && CONNECTION_HAS_USERINFO.test(trimmed)) {
|
|
265
|
+
return {
|
|
266
|
+
value: replacement,
|
|
267
|
+
credentialRedacted: true,
|
|
268
|
+
identifiersMasked: false
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return void 0;
|
|
272
|
+
}
|
|
249
273
|
function isHttpProtocol(protocol) {
|
|
250
274
|
return protocol === "http:" || protocol === "https:";
|
|
251
275
|
}
|
|
@@ -287,9 +311,11 @@ function redactUrlString(value, options) {
|
|
|
287
311
|
identifiersMasked: false
|
|
288
312
|
};
|
|
289
313
|
if (!looksLikeUrlForRedaction(value)) return unchanged;
|
|
290
|
-
const url = parseRedactableUrl(value);
|
|
291
|
-
if (!url) return unchanged;
|
|
292
314
|
const replacement = options.replacement ?? "[REDACTED]";
|
|
315
|
+
const url = parseRedactableUrl(value);
|
|
316
|
+
if (!url) {
|
|
317
|
+
return redactConnectionUserinfoFallback(value, replacement) ?? unchanged;
|
|
318
|
+
}
|
|
293
319
|
const idPlaceholder = options.idPlaceholder ?? "[id]";
|
|
294
320
|
const http = isHttpProtocol(url.protocol);
|
|
295
321
|
let credentialRedacted = url.username.length > 0 || url.password.length > 0;
|
|
@@ -1188,6 +1214,10 @@ function exportOpenInference(tree, options) {
|
|
|
1188
1214
|
warnings
|
|
1189
1215
|
};
|
|
1190
1216
|
}
|
|
1217
|
+
var OTLP_STATUS_CODE_UNSET = 0;
|
|
1218
|
+
var OTLP_STATUS_CODE_OK = 1;
|
|
1219
|
+
var OTLP_STATUS_CODE_ERROR = 2;
|
|
1220
|
+
var OTLP_SPAN_KIND_INTERNAL = 1;
|
|
1191
1221
|
function hexFrom2(seed, byteLen) {
|
|
1192
1222
|
return crypto__default.default.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
|
|
1193
1223
|
}
|
|
@@ -1200,7 +1230,19 @@ function stringAttr(key, value) {
|
|
|
1200
1230
|
return { key, value: { stringValue: value } };
|
|
1201
1231
|
}
|
|
1202
1232
|
function intAttr(key, value) {
|
|
1203
|
-
return { key, value: { intValue: String(value) } };
|
|
1233
|
+
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
1234
|
+
}
|
|
1235
|
+
function doubleAttr(key, value) {
|
|
1236
|
+
return { key, value: { doubleValue: value } };
|
|
1237
|
+
}
|
|
1238
|
+
function boolAttr(key, value) {
|
|
1239
|
+
return { key, value: { boolValue: value } };
|
|
1240
|
+
}
|
|
1241
|
+
function numberAttr(key, value) {
|
|
1242
|
+
if (Number.isFinite(value) && !Number.isInteger(value)) {
|
|
1243
|
+
return doubleAttr(key, value);
|
|
1244
|
+
}
|
|
1245
|
+
return intAttr(key, value);
|
|
1204
1246
|
}
|
|
1205
1247
|
function genAiOperationName(kind) {
|
|
1206
1248
|
switch (kind) {
|
|
@@ -1214,10 +1256,27 @@ function genAiOperationName(kind) {
|
|
|
1214
1256
|
return void 0;
|
|
1215
1257
|
}
|
|
1216
1258
|
}
|
|
1259
|
+
function resolveSpanTimes(ev) {
|
|
1260
|
+
const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
|
|
1261
|
+
const endedAtMs = typeof ev.attributes?.endedAtMs === "number" && Number.isFinite(ev.attributes.endedAtMs) ? ev.attributes.endedAtMs : void 0;
|
|
1262
|
+
const startMs = startedAtMs ?? ev.timestamp;
|
|
1263
|
+
const startNs = String(unixNano2(startMs));
|
|
1264
|
+
if (endedAtMs !== void 0) {
|
|
1265
|
+
return { startNs, endNs: String(unixNano2(endedAtMs)) };
|
|
1266
|
+
}
|
|
1267
|
+
if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
|
|
1268
|
+
return {
|
|
1269
|
+
startNs,
|
|
1270
|
+
endNs: String(unixNano2(startMs) + unixNano2(ev.durationMs))
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
return { startNs };
|
|
1274
|
+
}
|
|
1217
1275
|
function exportOtlpJson(tree, options) {
|
|
1218
1276
|
const warnings = [
|
|
1219
1277
|
"OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
|
|
1220
|
-
"Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload."
|
|
1278
|
+
"Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
|
|
1279
|
+
"Status and span kind use OTLP numeric enums (StatusCode 0/1/2, SpanKind INTERNAL=1)."
|
|
1221
1280
|
];
|
|
1222
1281
|
const traceId = hexFrom2(`trace:${tree.runId}`, 16);
|
|
1223
1282
|
const includeAttributes = options?.includeAttributes ?? false;
|
|
@@ -1229,11 +1288,7 @@ function exportOtlpJson(tree, options) {
|
|
|
1229
1288
|
const ev = n.event;
|
|
1230
1289
|
const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
|
|
1231
1290
|
const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
|
|
1232
|
-
const startNs =
|
|
1233
|
-
let endNs;
|
|
1234
|
-
if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
|
|
1235
|
-
endNs = String(unixNano2(ev.timestamp) + unixNano2(ev.durationMs));
|
|
1236
|
-
}
|
|
1291
|
+
const { startNs, endNs } = resolveSpanTimes(ev);
|
|
1237
1292
|
const attrs = [
|
|
1238
1293
|
stringAttr("agent_inspect.kind", ev.kind),
|
|
1239
1294
|
stringAttr("agent_inspect.confidence", ev.confidence),
|
|
@@ -1263,29 +1318,28 @@ function exportOtlpJson(tree, options) {
|
|
|
1263
1318
|
if (includeAttributes && meta && typeof meta === "object") {
|
|
1264
1319
|
for (const [k, v] of Object.entries(meta)) {
|
|
1265
1320
|
if (k === "tokens" || k === "model") continue;
|
|
1266
|
-
if (typeof v === "string"
|
|
1267
|
-
attrs.push(
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
);
|
|
1321
|
+
if (typeof v === "string") {
|
|
1322
|
+
attrs.push(stringAttr(`agent_inspect.preview.${k}`, v.slice(0, maxLen)));
|
|
1323
|
+
} else if (typeof v === "number" && Number.isFinite(v)) {
|
|
1324
|
+
attrs.push(numberAttr(`agent_inspect.preview.${k}`, v));
|
|
1325
|
+
} else if (typeof v === "boolean") {
|
|
1326
|
+
attrs.push(boolAttr(`agent_inspect.preview.${k}`, v));
|
|
1273
1327
|
}
|
|
1274
1328
|
}
|
|
1275
1329
|
}
|
|
1276
|
-
let statusCode =
|
|
1330
|
+
let statusCode = OTLP_STATUS_CODE_UNSET;
|
|
1277
1331
|
let statusMessage;
|
|
1278
1332
|
if (ev.status === "error") {
|
|
1279
|
-
statusCode =
|
|
1333
|
+
statusCode = OTLP_STATUS_CODE_ERROR;
|
|
1280
1334
|
statusMessage = meta && typeof meta.error === "object" && meta.error !== null ? String(meta.error.message ?? "error").slice(0, maxLen) : "error";
|
|
1281
1335
|
} else if (ev.status === "ok") {
|
|
1282
|
-
statusCode =
|
|
1336
|
+
statusCode = OTLP_STATUS_CODE_OK;
|
|
1283
1337
|
}
|
|
1284
1338
|
const spanJson = {
|
|
1285
1339
|
traceId,
|
|
1286
1340
|
spanId,
|
|
1287
1341
|
name: ev.name,
|
|
1288
|
-
kind:
|
|
1342
|
+
kind: OTLP_SPAN_KIND_INTERNAL,
|
|
1289
1343
|
startTimeUnixNano: startNs,
|
|
1290
1344
|
attributes: attrs,
|
|
1291
1345
|
status: {
|
|
@@ -1327,6 +1381,136 @@ function exportOtlpJson(tree, options) {
|
|
|
1327
1381
|
|
|
1328
1382
|
// packages/core/src/exporters/validation.ts
|
|
1329
1383
|
var EXPERIMENTAL = "Experimental compatibility export \u2014 verify against your target tooling before relying on it.";
|
|
1384
|
+
function pushPath(errors, path4, message) {
|
|
1385
|
+
errors.push(`${path4}: ${message}`);
|
|
1386
|
+
}
|
|
1387
|
+
function isRecord3(value) {
|
|
1388
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1389
|
+
}
|
|
1390
|
+
function validateOtlpJson(content) {
|
|
1391
|
+
const errors = [];
|
|
1392
|
+
const warnings = [
|
|
1393
|
+
EXPERIMENTAL,
|
|
1394
|
+
"OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation.",
|
|
1395
|
+
"protocol-valid \u2260 profile-complete \u2260 fixture-complete \u2014 nested path diagnostics report protocol shape only."
|
|
1396
|
+
];
|
|
1397
|
+
let parsed;
|
|
1398
|
+
try {
|
|
1399
|
+
parsed = JSON.parse(content);
|
|
1400
|
+
} catch {
|
|
1401
|
+
pushPath(errors, "$", "OTLP JSON export is not valid JSON");
|
|
1402
|
+
return { ok: false, format: "otlp-json", errors, warnings };
|
|
1403
|
+
}
|
|
1404
|
+
if (!isRecord3(parsed)) {
|
|
1405
|
+
pushPath(errors, "$", "OTLP JSON export must be an object");
|
|
1406
|
+
return { ok: false, format: "otlp-json", errors, warnings };
|
|
1407
|
+
}
|
|
1408
|
+
if (!Array.isArray(parsed.resourceSpans)) {
|
|
1409
|
+
pushPath(errors, "$.resourceSpans", "must be an array");
|
|
1410
|
+
return { ok: false, format: "otlp-json", errors, warnings };
|
|
1411
|
+
}
|
|
1412
|
+
parsed.resourceSpans.forEach((resourceSpan, rsi) => {
|
|
1413
|
+
const rsPath = `$.resourceSpans[${rsi}]`;
|
|
1414
|
+
if (!isRecord3(resourceSpan)) {
|
|
1415
|
+
pushPath(errors, rsPath, "must be an object");
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
if (!Array.isArray(resourceSpan.scopeSpans)) {
|
|
1419
|
+
pushPath(errors, `${rsPath}.scopeSpans`, "must be an array");
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
resourceSpan.scopeSpans.forEach((scopeSpan, ssi) => {
|
|
1423
|
+
const ssPath = `${rsPath}.scopeSpans[${ssi}]`;
|
|
1424
|
+
if (!isRecord3(scopeSpan)) {
|
|
1425
|
+
pushPath(errors, ssPath, "must be an object");
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
if (!Array.isArray(scopeSpan.spans)) {
|
|
1429
|
+
pushPath(errors, `${ssPath}.spans`, "must be an array");
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
scopeSpan.spans.forEach((span, spi) => {
|
|
1433
|
+
const spanPath = `${ssPath}.spans[${spi}]`;
|
|
1434
|
+
if (!isRecord3(span)) {
|
|
1435
|
+
pushPath(errors, spanPath, "must be an object");
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
if (typeof span.traceId !== "string" || span.traceId.length === 0) {
|
|
1439
|
+
pushPath(errors, `${spanPath}.traceId`, "must be a non-empty string");
|
|
1440
|
+
}
|
|
1441
|
+
if (typeof span.spanId !== "string" || span.spanId.length === 0) {
|
|
1442
|
+
pushPath(errors, `${spanPath}.spanId`, "must be a non-empty string");
|
|
1443
|
+
}
|
|
1444
|
+
if (typeof span.name !== "string") {
|
|
1445
|
+
pushPath(errors, `${spanPath}.name`, "must be a string");
|
|
1446
|
+
}
|
|
1447
|
+
if (typeof span.startTimeUnixNano !== "string" || !/^\d+$/.test(span.startTimeUnixNano)) {
|
|
1448
|
+
pushPath(
|
|
1449
|
+
errors,
|
|
1450
|
+
`${spanPath}.startTimeUnixNano`,
|
|
1451
|
+
"must be a decimal-string 64-bit integer"
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
if (span.endTimeUnixNano !== void 0 && (typeof span.endTimeUnixNano !== "string" || !/^\d+$/.test(span.endTimeUnixNano))) {
|
|
1455
|
+
pushPath(
|
|
1456
|
+
errors,
|
|
1457
|
+
`${spanPath}.endTimeUnixNano`,
|
|
1458
|
+
"must be a decimal-string 64-bit integer when present"
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
if (typeof span.kind === "number") {
|
|
1462
|
+
if (!Number.isInteger(span.kind)) {
|
|
1463
|
+
pushPath(errors, `${spanPath}.kind`, "must be an integer SpanKind enum");
|
|
1464
|
+
}
|
|
1465
|
+
} else if (typeof span.kind === "string") {
|
|
1466
|
+
warnings.push(
|
|
1467
|
+
`${spanPath}.kind: string SpanKind enum is legacy; prefer numeric (INTERNAL=1)`
|
|
1468
|
+
);
|
|
1469
|
+
} else if (span.kind !== void 0) {
|
|
1470
|
+
pushPath(
|
|
1471
|
+
errors,
|
|
1472
|
+
`${spanPath}.kind`,
|
|
1473
|
+
"must be numeric SpanKind or historical string enum"
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
if (!isRecord3(span.status)) {
|
|
1477
|
+
pushPath(errors, `${spanPath}.status`, "must be an object");
|
|
1478
|
+
} else {
|
|
1479
|
+
const code = span.status.code;
|
|
1480
|
+
if (typeof code === "number") {
|
|
1481
|
+
if (![0, 1, 2].includes(code)) {
|
|
1482
|
+
pushPath(
|
|
1483
|
+
errors,
|
|
1484
|
+
`${spanPath}.status.code`,
|
|
1485
|
+
"must be numeric StatusCode 0 (UNSET), 1 (OK), or 2 (ERROR)"
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
} else if (typeof code === "string") {
|
|
1489
|
+
const upper = code.toUpperCase();
|
|
1490
|
+
if (upper !== "STATUS_CODE_UNSET" && upper !== "STATUS_CODE_OK" && upper !== "STATUS_CODE_ERROR" && upper !== "UNSET" && upper !== "OK" && upper !== "ERROR" && !/^[012]$/.test(code.trim())) {
|
|
1491
|
+
pushPath(
|
|
1492
|
+
errors,
|
|
1493
|
+
`${spanPath}.status.code`,
|
|
1494
|
+
"unrecognized StatusCode string"
|
|
1495
|
+
);
|
|
1496
|
+
} else {
|
|
1497
|
+
warnings.push(
|
|
1498
|
+
`${spanPath}.status.code: string StatusCode is legacy; prefer numeric 0/1/2`
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
} else {
|
|
1502
|
+
pushPath(
|
|
1503
|
+
errors,
|
|
1504
|
+
`${spanPath}.status.code`,
|
|
1505
|
+
"must be numeric StatusCode 0/1/2 or historical string enum"
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
});
|
|
1510
|
+
});
|
|
1511
|
+
});
|
|
1512
|
+
return { ok: errors.length === 0, format: "otlp-json", errors, warnings };
|
|
1513
|
+
}
|
|
1330
1514
|
function validateExportContent(format, content) {
|
|
1331
1515
|
const errors = [];
|
|
1332
1516
|
const warnings = [EXPERIMENTAL];
|
|
@@ -1372,25 +1556,7 @@ function validateExportContent(format, content) {
|
|
|
1372
1556
|
return { ok: errors.length === 0, format, errors, warnings };
|
|
1373
1557
|
}
|
|
1374
1558
|
if (format === "otlp-json") {
|
|
1375
|
-
|
|
1376
|
-
try {
|
|
1377
|
-
parsed = JSON.parse(content);
|
|
1378
|
-
} catch {
|
|
1379
|
-
errors.push("OTLP JSON export is not valid JSON");
|
|
1380
|
-
return { ok: false, format, errors, warnings };
|
|
1381
|
-
}
|
|
1382
|
-
if (!parsed || typeof parsed !== "object") {
|
|
1383
|
-
errors.push("OTLP JSON export must be an object");
|
|
1384
|
-
return { ok: false, format, errors, warnings };
|
|
1385
|
-
}
|
|
1386
|
-
const o = parsed;
|
|
1387
|
-
if (!Array.isArray(o.resourceSpans)) {
|
|
1388
|
-
errors.push("OTLP JSON export must include resourceSpans array");
|
|
1389
|
-
}
|
|
1390
|
-
warnings.push(
|
|
1391
|
-
"OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation."
|
|
1392
|
-
);
|
|
1393
|
-
return { ok: errors.length === 0, format, errors, warnings };
|
|
1559
|
+
return validateOtlpJson(content);
|
|
1394
1560
|
}
|
|
1395
1561
|
errors.push(`Unsupported export format`);
|
|
1396
1562
|
return { ok: false, format, errors, warnings };
|
|
@@ -1891,6 +2057,8 @@ function formatStepLabel(stepType, stepName) {
|
|
|
1891
2057
|
}
|
|
1892
2058
|
|
|
1893
2059
|
// packages/core/src/timeline.ts
|
|
2060
|
+
var ROOT_TIMELINE_DEPTH = 0;
|
|
2061
|
+
var MAX_TIMELINE_DEPTH = 1e3;
|
|
1894
2062
|
function finite(n) {
|
|
1895
2063
|
return typeof n === "number" && Number.isFinite(n);
|
|
1896
2064
|
}
|
|
@@ -1961,16 +2129,51 @@ function buildRunTimeline(events, options = {}) {
|
|
|
1961
2129
|
const computeDepth = (stepId) => {
|
|
1962
2130
|
const cached = depthCache.get(stepId);
|
|
1963
2131
|
if (cached !== void 0) return cached;
|
|
1964
|
-
const
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2132
|
+
const ancestry = [];
|
|
2133
|
+
const ancestryIndexes = /* @__PURE__ */ new Map();
|
|
2134
|
+
let currentStepId = stepId;
|
|
2135
|
+
let resolvedDepth;
|
|
2136
|
+
while (resolvedDepth === void 0) {
|
|
2137
|
+
const cachedDepth = depthCache.get(currentStepId);
|
|
2138
|
+
if (cachedDepth !== void 0) {
|
|
2139
|
+
resolvedDepth = cachedDepth;
|
|
2140
|
+
continue;
|
|
2141
|
+
}
|
|
2142
|
+
const cycleStart = ancestryIndexes.get(currentStepId);
|
|
2143
|
+
if (cycleStart !== void 0) {
|
|
2144
|
+
const cycleStepIds = ancestry.splice(cycleStart);
|
|
2145
|
+
for (const cycleStepId of cycleStepIds) {
|
|
2146
|
+
depthCache.set(cycleStepId, ROOT_TIMELINE_DEPTH);
|
|
2147
|
+
}
|
|
2148
|
+
resolvedDepth = ROOT_TIMELINE_DEPTH;
|
|
2149
|
+
continue;
|
|
2150
|
+
}
|
|
2151
|
+
const currentStep = steps.get(currentStepId);
|
|
2152
|
+
if (!currentStep) {
|
|
2153
|
+
resolvedDepth = ROOT_TIMELINE_DEPTH;
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
ancestryIndexes.set(currentStepId, ancestry.length);
|
|
2157
|
+
ancestry.push(currentStepId);
|
|
2158
|
+
const parentId = currentStep.parentId;
|
|
2159
|
+
if (typeof parentId !== "string" || parentId.trim() === "" || !steps.has(parentId)) {
|
|
2160
|
+
ancestry.pop();
|
|
2161
|
+
depthCache.set(currentStepId, ROOT_TIMELINE_DEPTH);
|
|
2162
|
+
resolvedDepth = ROOT_TIMELINE_DEPTH;
|
|
2163
|
+
continue;
|
|
2164
|
+
}
|
|
2165
|
+
currentStepId = parentId;
|
|
2166
|
+
}
|
|
2167
|
+
ancestry.reverse();
|
|
2168
|
+
for (const ancestorStepId of ancestry) {
|
|
2169
|
+
resolvedDepth = Math.min(MAX_TIMELINE_DEPTH, resolvedDepth + 1);
|
|
2170
|
+
depthCache.set(ancestorStepId, resolvedDepth);
|
|
2171
|
+
}
|
|
2172
|
+
const resolvedStepDepth = depthCache.get(stepId);
|
|
2173
|
+
if (resolvedStepDepth === void 0) {
|
|
2174
|
+
throw new Error(`Failed to resolve timeline depth for step "${stepId}"`);
|
|
2175
|
+
}
|
|
2176
|
+
return resolvedStepDepth;
|
|
1974
2177
|
};
|
|
1975
2178
|
const entries = [];
|
|
1976
2179
|
for (const [stepId, s] of steps.entries()) {
|