agent-inspect 6.31.6 → 6.31.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/docs/AI-SDK-ADOPTION.md +62 -34
- package/package.json +1 -1
- package/packages/cli/dist/{chunk-YXDNWHNJ.mjs → chunk-6FE47XSF.mjs} +119 -34
- package/packages/cli/dist/chunk-6FE47XSF.mjs.map +1 -0
- package/packages/cli/dist/index.cjs +569 -102
- package/packages/cli/dist/index.cjs.map +1 -1
- package/packages/cli/dist/index.mjs +454 -74
- package/packages/cli/dist/index.mjs.map +1 -1
- package/packages/cli/dist/{src-H22KNWAZ.mjs → src-NXAYHG34.mjs} +3 -3
- package/packages/cli/dist/{src-H22KNWAZ.mjs.map → src-NXAYHG34.mjs.map} +1 -1
- package/packages/core/dist/advanced.cjs +116 -31
- package/packages/core/dist/advanced.cjs.map +1 -1
- package/packages/core/dist/advanced.mjs +7 -7
- package/packages/core/dist/checks.mjs +2 -2
- package/packages/core/dist/{chunk-LXYPM2ZO.mjs → chunk-2CCRUI42.mjs} +19 -318
- package/packages/core/dist/chunk-2CCRUI42.mjs.map +1 -0
- package/packages/core/dist/{chunk-Q5SLKV2Y.mjs → chunk-2IRRUNIN.mjs} +28 -5
- package/packages/core/dist/chunk-2IRRUNIN.mjs.map +1 -0
- package/packages/core/dist/{chunk-EXGQLMVB.mjs → chunk-7YYS742B.mjs} +49 -12
- package/packages/core/dist/chunk-7YYS742B.mjs.map +1 -0
- package/packages/core/dist/{chunk-OSGNGRHF.mjs → chunk-IJJSPJXV.mjs} +51 -25
- package/packages/core/dist/chunk-IJJSPJXV.mjs.map +1 -0
- package/packages/core/dist/chunk-L5WLVBW4.mjs +355 -0
- package/packages/core/dist/chunk-L5WLVBW4.mjs.map +1 -0
- package/packages/core/dist/exporters.cjs +327 -58
- package/packages/core/dist/exporters.cjs.map +1 -1
- package/packages/core/dist/exporters.mjs +281 -49
- package/packages/core/dist/exporters.mjs.map +1 -1
- package/packages/core/dist/persisted.cjs +361 -9
- package/packages/core/dist/persisted.cjs.map +1 -1
- package/packages/core/dist/persisted.d.cts +8 -1
- package/packages/core/dist/persisted.d.ts +8 -1
- package/packages/core/dist/persisted.mjs +3 -2
- package/packages/core/dist/persisted.mjs.map +1 -1
- package/packages/core/dist/readers.cjs +425 -100
- package/packages/core/dist/readers.cjs.map +1 -1
- package/packages/core/dist/readers.mjs +3 -3
- package/packages/cli/dist/chunk-YXDNWHNJ.mjs.map +0 -1
- package/packages/core/dist/chunk-EXGQLMVB.mjs.map +0 -1
- package/packages/core/dist/chunk-FWK3Q3OJ.mjs +0 -56
- package/packages/core/dist/chunk-FWK3Q3OJ.mjs.map +0 -1
- package/packages/core/dist/chunk-LXYPM2ZO.mjs.map +0 -1
- package/packages/core/dist/chunk-OSGNGRHF.mjs.map +0 -1
- package/packages/core/dist/chunk-Q5SLKV2Y.mjs.map +0 -1
|
@@ -1146,11 +1146,13 @@ function exportOpenInference(tree, options) {
|
|
|
1146
1146
|
endNs = startNs + unixNano(ev.durationMs);
|
|
1147
1147
|
}
|
|
1148
1148
|
const { openInferenceKind } = mapInspectKindToOI(ev.kind, warnings);
|
|
1149
|
+
const meta = ev.attributes;
|
|
1150
|
+
const originalSource = typeof meta?.originalSourceType === "string" && meta.originalSourceType.trim() !== "" ? meta.originalSourceType.trim() : ev.source.type;
|
|
1149
1151
|
const attrs = {
|
|
1150
1152
|
"openinference.span.kind": openInferenceKind,
|
|
1151
1153
|
"agent_inspect.kind": ev.kind,
|
|
1152
1154
|
"agent_inspect.confidence": ev.confidence,
|
|
1153
|
-
"agent_inspect.source.type":
|
|
1155
|
+
"agent_inspect.source.type": originalSource,
|
|
1154
1156
|
"agent_inspect.run_id": tree.runId,
|
|
1155
1157
|
"agent_inspect.event_id": ev.eventId,
|
|
1156
1158
|
"agent_inspect.status": ev.status ?? "unset"
|
|
@@ -1158,9 +1160,9 @@ function exportOpenInference(tree, options) {
|
|
|
1158
1160
|
if (ev.durationMs !== void 0) {
|
|
1159
1161
|
attrs["agent_inspect.duration_ms"] = ev.durationMs;
|
|
1160
1162
|
}
|
|
1161
|
-
const
|
|
1162
|
-
if (
|
|
1163
|
-
attrs["llm.model_name"] =
|
|
1163
|
+
const requestModel = (typeof meta?.model === "string" && meta.model.trim() !== "" ? meta.model : void 0) ?? (typeof meta?.modelId === "string" && meta.modelId.trim() !== "" ? meta.modelId : void 0);
|
|
1164
|
+
if (requestModel !== void 0) {
|
|
1165
|
+
attrs["llm.model_name"] = requestModel;
|
|
1164
1166
|
}
|
|
1165
1167
|
const tokens = meta?.tokens;
|
|
1166
1168
|
if (tokens && typeof tokens === "object" && tokens !== null) {
|
|
@@ -1170,8 +1172,9 @@ function exportOpenInference(tree, options) {
|
|
|
1170
1172
|
if (typeof outp === "number") attrs["llm.token_count.completion"] = outp;
|
|
1171
1173
|
}
|
|
1172
1174
|
if (includeAttributes && meta && typeof meta === "object") {
|
|
1175
|
+
const skipKeys = /* @__PURE__ */ new Set(["tokens", "model", "modelId", "originalSourceType"]);
|
|
1173
1176
|
for (const [k, v] of Object.entries(meta)) {
|
|
1174
|
-
if (k
|
|
1177
|
+
if (skipKeys.has(k)) continue;
|
|
1175
1178
|
if (v !== void 0 && v !== null && typeof v !== "object") {
|
|
1176
1179
|
attrs[`agent_inspect.preview.${k}`] = typeof v === "string" ? v.slice(0, maxLen) : v;
|
|
1177
1180
|
}
|
|
@@ -1214,6 +1217,10 @@ function exportOpenInference(tree, options) {
|
|
|
1214
1217
|
warnings
|
|
1215
1218
|
};
|
|
1216
1219
|
}
|
|
1220
|
+
var OTLP_STATUS_CODE_UNSET = 0;
|
|
1221
|
+
var OTLP_STATUS_CODE_OK = 1;
|
|
1222
|
+
var OTLP_STATUS_CODE_ERROR = 2;
|
|
1223
|
+
var OTLP_SPAN_KIND_INTERNAL = 1;
|
|
1217
1224
|
function hexFrom2(seed, byteLen) {
|
|
1218
1225
|
return crypto__default.default.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, byteLen * 2);
|
|
1219
1226
|
}
|
|
@@ -1226,7 +1233,19 @@ function stringAttr(key, value) {
|
|
|
1226
1233
|
return { key, value: { stringValue: value } };
|
|
1227
1234
|
}
|
|
1228
1235
|
function intAttr(key, value) {
|
|
1229
|
-
return { key, value: { intValue: String(value) } };
|
|
1236
|
+
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
1237
|
+
}
|
|
1238
|
+
function doubleAttr(key, value) {
|
|
1239
|
+
return { key, value: { doubleValue: value } };
|
|
1240
|
+
}
|
|
1241
|
+
function boolAttr(key, value) {
|
|
1242
|
+
return { key, value: { boolValue: value } };
|
|
1243
|
+
}
|
|
1244
|
+
function numberAttr(key, value) {
|
|
1245
|
+
if (Number.isFinite(value) && !Number.isInteger(value)) {
|
|
1246
|
+
return doubleAttr(key, value);
|
|
1247
|
+
}
|
|
1248
|
+
return intAttr(key, value);
|
|
1230
1249
|
}
|
|
1231
1250
|
function genAiOperationName(kind) {
|
|
1232
1251
|
switch (kind) {
|
|
@@ -1240,10 +1259,27 @@ function genAiOperationName(kind) {
|
|
|
1240
1259
|
return void 0;
|
|
1241
1260
|
}
|
|
1242
1261
|
}
|
|
1262
|
+
function resolveSpanTimes(ev) {
|
|
1263
|
+
const startedAtMs = typeof ev.attributes?.startedAtMs === "number" && Number.isFinite(ev.attributes.startedAtMs) ? ev.attributes.startedAtMs : void 0;
|
|
1264
|
+
const endedAtMs = typeof ev.attributes?.endedAtMs === "number" && Number.isFinite(ev.attributes.endedAtMs) ? ev.attributes.endedAtMs : void 0;
|
|
1265
|
+
const startMs = startedAtMs ?? ev.timestamp;
|
|
1266
|
+
const startNs = String(unixNano2(startMs));
|
|
1267
|
+
if (endedAtMs !== void 0) {
|
|
1268
|
+
return { startNs, endNs: String(unixNano2(endedAtMs)) };
|
|
1269
|
+
}
|
|
1270
|
+
if (ev.durationMs !== void 0 && Number.isFinite(ev.durationMs)) {
|
|
1271
|
+
return {
|
|
1272
|
+
startNs,
|
|
1273
|
+
endNs: String(unixNano2(startMs) + unixNano2(ev.durationMs))
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
return { startNs };
|
|
1277
|
+
}
|
|
1243
1278
|
function exportOtlpJson(tree, options) {
|
|
1244
1279
|
const warnings = [
|
|
1245
1280
|
"OTLP JSON export uses OTel GenAI-aligned attributes where applicable; experimental until verified against specific collectors.",
|
|
1246
|
-
"Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload."
|
|
1281
|
+
"Not OTLP gRPC/protobuf \u2014 JSON mapping only. Generated locally; no network upload.",
|
|
1282
|
+
"Status and span kind use OTLP numeric enums (StatusCode 0/1/2, SpanKind INTERNAL=1)."
|
|
1247
1283
|
];
|
|
1248
1284
|
const traceId = hexFrom2(`trace:${tree.runId}`, 16);
|
|
1249
1285
|
const includeAttributes = options?.includeAttributes ?? false;
|
|
@@ -1255,29 +1291,34 @@ function exportOtlpJson(tree, options) {
|
|
|
1255
1291
|
const ev = n.event;
|
|
1256
1292
|
const spanId = hexFrom2(`${tree.runId}:${ev.eventId}`, 8);
|
|
1257
1293
|
const parentSpanId = ev.parentId ? hexFrom2(`${tree.runId}:${ev.parentId}`, 8) : void 0;
|
|
1258
|
-
const startNs =
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
endNs = String(unixNano2(ev.timestamp) + unixNano2(ev.durationMs));
|
|
1262
|
-
}
|
|
1294
|
+
const { startNs, endNs } = resolveSpanTimes(ev);
|
|
1295
|
+
const meta = ev.attributes;
|
|
1296
|
+
const originalSource = typeof meta?.originalSourceType === "string" && meta.originalSourceType.trim() !== "" ? meta.originalSourceType.trim() : ev.source.type;
|
|
1263
1297
|
const attrs = [
|
|
1264
1298
|
stringAttr("agent_inspect.kind", ev.kind),
|
|
1265
1299
|
stringAttr("agent_inspect.confidence", ev.confidence),
|
|
1266
|
-
stringAttr("agent_inspect.source.type",
|
|
1300
|
+
stringAttr("agent_inspect.source.type", originalSource),
|
|
1267
1301
|
stringAttr("agent_inspect.run_id", tree.runId),
|
|
1268
1302
|
stringAttr("agent_inspect.event_id", ev.eventId),
|
|
1269
1303
|
stringAttr("agent_inspect.status", ev.status ?? "unset")
|
|
1270
1304
|
];
|
|
1271
1305
|
if (ev.durationMs !== void 0) {
|
|
1272
|
-
attrs.push(
|
|
1306
|
+
attrs.push(numberAttr("agent_inspect.duration_ms", ev.durationMs));
|
|
1273
1307
|
}
|
|
1274
1308
|
const op = genAiOperationName(ev.kind);
|
|
1275
1309
|
if (op !== void 0) {
|
|
1276
1310
|
attrs.push(stringAttr("gen_ai.operation.name", op));
|
|
1277
1311
|
}
|
|
1278
|
-
const
|
|
1279
|
-
if (
|
|
1280
|
-
attrs.push(stringAttr("gen_ai.request.model",
|
|
1312
|
+
const requestModel = (typeof meta?.model === "string" && meta.model.trim() !== "" ? meta.model : void 0) ?? (typeof meta?.modelId === "string" && meta.modelId.trim() !== "" ? meta.modelId : void 0);
|
|
1313
|
+
if (requestModel !== void 0) {
|
|
1314
|
+
attrs.push(stringAttr("gen_ai.request.model", requestModel.slice(0, maxLen)));
|
|
1315
|
+
}
|
|
1316
|
+
const responseModel = typeof meta?.responseModelId === "string" && meta.responseModelId.trim() !== "" ? meta.responseModelId : typeof meta?.responseModel === "string" && meta.responseModel.trim() !== "" ? meta.responseModel : void 0;
|
|
1317
|
+
if (responseModel !== void 0) {
|
|
1318
|
+
attrs.push(stringAttr("gen_ai.response.model", responseModel.slice(0, maxLen)));
|
|
1319
|
+
}
|
|
1320
|
+
if (typeof meta?.provider === "string" && meta.provider.trim() !== "") {
|
|
1321
|
+
attrs.push(stringAttr("gen_ai.provider.name", meta.provider.slice(0, maxLen)));
|
|
1281
1322
|
}
|
|
1282
1323
|
const tokens = meta?.tokens;
|
|
1283
1324
|
if (tokens && typeof tokens === "object" && tokens !== null) {
|
|
@@ -1287,31 +1328,39 @@ function exportOtlpJson(tree, options) {
|
|
|
1287
1328
|
if (typeof outp === "number") attrs.push(intAttr("gen_ai.usage.output_tokens", outp));
|
|
1288
1329
|
}
|
|
1289
1330
|
if (includeAttributes && meta && typeof meta === "object") {
|
|
1331
|
+
const skipKeys = /* @__PURE__ */ new Set([
|
|
1332
|
+
"tokens",
|
|
1333
|
+
"model",
|
|
1334
|
+
"modelId",
|
|
1335
|
+
"responseModel",
|
|
1336
|
+
"responseModelId",
|
|
1337
|
+
"provider",
|
|
1338
|
+
"originalSourceType"
|
|
1339
|
+
]);
|
|
1290
1340
|
for (const [k, v] of Object.entries(meta)) {
|
|
1291
|
-
if (k
|
|
1292
|
-
if (typeof v === "string"
|
|
1293
|
-
attrs.push(
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
);
|
|
1341
|
+
if (skipKeys.has(k)) continue;
|
|
1342
|
+
if (typeof v === "string") {
|
|
1343
|
+
attrs.push(stringAttr(`agent_inspect.preview.${k}`, v.slice(0, maxLen)));
|
|
1344
|
+
} else if (typeof v === "number" && Number.isFinite(v)) {
|
|
1345
|
+
attrs.push(numberAttr(`agent_inspect.preview.${k}`, v));
|
|
1346
|
+
} else if (typeof v === "boolean") {
|
|
1347
|
+
attrs.push(boolAttr(`agent_inspect.preview.${k}`, v));
|
|
1299
1348
|
}
|
|
1300
1349
|
}
|
|
1301
1350
|
}
|
|
1302
|
-
let statusCode =
|
|
1351
|
+
let statusCode = OTLP_STATUS_CODE_UNSET;
|
|
1303
1352
|
let statusMessage;
|
|
1304
1353
|
if (ev.status === "error") {
|
|
1305
|
-
statusCode =
|
|
1354
|
+
statusCode = OTLP_STATUS_CODE_ERROR;
|
|
1306
1355
|
statusMessage = meta && typeof meta.error === "object" && meta.error !== null ? String(meta.error.message ?? "error").slice(0, maxLen) : "error";
|
|
1307
1356
|
} else if (ev.status === "ok") {
|
|
1308
|
-
statusCode =
|
|
1357
|
+
statusCode = OTLP_STATUS_CODE_OK;
|
|
1309
1358
|
}
|
|
1310
1359
|
const spanJson = {
|
|
1311
1360
|
traceId,
|
|
1312
1361
|
spanId,
|
|
1313
1362
|
name: ev.name,
|
|
1314
|
-
kind:
|
|
1363
|
+
kind: OTLP_SPAN_KIND_INTERNAL,
|
|
1315
1364
|
startTimeUnixNano: startNs,
|
|
1316
1365
|
attributes: attrs,
|
|
1317
1366
|
status: {
|
|
@@ -1353,6 +1402,207 @@ function exportOtlpJson(tree, options) {
|
|
|
1353
1402
|
|
|
1354
1403
|
// packages/core/src/exporters/validation.ts
|
|
1355
1404
|
var EXPERIMENTAL = "Experimental compatibility export \u2014 verify against your target tooling before relying on it.";
|
|
1405
|
+
function pushPath(errors, path4, message) {
|
|
1406
|
+
errors.push(`${path4}: ${message}`);
|
|
1407
|
+
}
|
|
1408
|
+
function isRecord3(value) {
|
|
1409
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1410
|
+
}
|
|
1411
|
+
function isHexId(value, byteLen) {
|
|
1412
|
+
return typeof value === "string" && new RegExp(`^[0-9a-fA-F]{${byteLen * 2}}$`).test(value);
|
|
1413
|
+
}
|
|
1414
|
+
function validateAnyValue(errors, path4, value) {
|
|
1415
|
+
if (!isRecord3(value)) {
|
|
1416
|
+
pushPath(errors, path4, "must be an AnyValue object");
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
const variants = [
|
|
1420
|
+
"stringValue",
|
|
1421
|
+
"boolValue",
|
|
1422
|
+
"intValue",
|
|
1423
|
+
"doubleValue",
|
|
1424
|
+
"bytesValue",
|
|
1425
|
+
"arrayValue",
|
|
1426
|
+
"kvlistValue"
|
|
1427
|
+
].filter((key) => value[key] !== void 0);
|
|
1428
|
+
if (variants.length !== 1) {
|
|
1429
|
+
pushPath(
|
|
1430
|
+
errors,
|
|
1431
|
+
path4,
|
|
1432
|
+
`AnyValue must set exactly one variant (found ${variants.length}: ${variants.join(",")})`
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
if (value.intValue !== void 0) {
|
|
1436
|
+
if (typeof value.intValue !== "string" || !/^-?\d+$/.test(value.intValue)) {
|
|
1437
|
+
pushPath(errors, `${path4}.intValue`, "must be a decimal integer string");
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
function validateOtlpJson(content) {
|
|
1442
|
+
const errors = [];
|
|
1443
|
+
const warnings = [
|
|
1444
|
+
EXPERIMENTAL,
|
|
1445
|
+
"OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation.",
|
|
1446
|
+
"producer-profile checks IDs, timing, and AnyValue shape; historical string enums are reader-compat warnings only."
|
|
1447
|
+
];
|
|
1448
|
+
let parsed;
|
|
1449
|
+
try {
|
|
1450
|
+
parsed = JSON.parse(content);
|
|
1451
|
+
} catch {
|
|
1452
|
+
pushPath(errors, "$", "OTLP JSON export is not valid JSON");
|
|
1453
|
+
return { ok: false, format: "otlp-json", errors, warnings };
|
|
1454
|
+
}
|
|
1455
|
+
if (!isRecord3(parsed)) {
|
|
1456
|
+
pushPath(errors, "$", "OTLP JSON export must be an object");
|
|
1457
|
+
return { ok: false, format: "otlp-json", errors, warnings };
|
|
1458
|
+
}
|
|
1459
|
+
if (!Array.isArray(parsed.resourceSpans)) {
|
|
1460
|
+
pushPath(errors, "$.resourceSpans", "must be an array");
|
|
1461
|
+
return { ok: false, format: "otlp-json", errors, warnings };
|
|
1462
|
+
}
|
|
1463
|
+
parsed.resourceSpans.forEach((resourceSpan, rsi) => {
|
|
1464
|
+
const rsPath = `$.resourceSpans[${rsi}]`;
|
|
1465
|
+
if (!isRecord3(resourceSpan)) {
|
|
1466
|
+
pushPath(errors, rsPath, "must be an object");
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (!Array.isArray(resourceSpan.scopeSpans)) {
|
|
1470
|
+
pushPath(errors, `${rsPath}.scopeSpans`, "must be an array");
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
resourceSpan.scopeSpans.forEach((scopeSpan, ssi) => {
|
|
1474
|
+
const ssPath = `${rsPath}.scopeSpans[${ssi}]`;
|
|
1475
|
+
if (!isRecord3(scopeSpan)) {
|
|
1476
|
+
pushPath(errors, ssPath, "must be an object");
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
if (!Array.isArray(scopeSpan.spans)) {
|
|
1480
|
+
pushPath(errors, `${ssPath}.spans`, "must be an array");
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
scopeSpan.spans.forEach((span, spi) => {
|
|
1484
|
+
const spanPath = `${ssPath}.spans[${spi}]`;
|
|
1485
|
+
if (!isRecord3(span)) {
|
|
1486
|
+
pushPath(errors, spanPath, "must be an object");
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
if (!isHexId(span.traceId, 16)) {
|
|
1490
|
+
pushPath(
|
|
1491
|
+
errors,
|
|
1492
|
+
`${spanPath}.traceId`,
|
|
1493
|
+
"must be a 32-char hex trace id (16 bytes)"
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
if (!isHexId(span.spanId, 8)) {
|
|
1497
|
+
pushPath(
|
|
1498
|
+
errors,
|
|
1499
|
+
`${spanPath}.spanId`,
|
|
1500
|
+
"must be a 16-char hex span id (8 bytes)"
|
|
1501
|
+
);
|
|
1502
|
+
}
|
|
1503
|
+
if (span.parentSpanId !== void 0 && !isHexId(span.parentSpanId, 8)) {
|
|
1504
|
+
pushPath(
|
|
1505
|
+
errors,
|
|
1506
|
+
`${spanPath}.parentSpanId`,
|
|
1507
|
+
"must be a 16-char hex span id when present"
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
if (typeof span.name !== "string") {
|
|
1511
|
+
pushPath(errors, `${spanPath}.name`, "must be a string");
|
|
1512
|
+
}
|
|
1513
|
+
if (typeof span.startTimeUnixNano !== "string" || !/^\d+$/.test(span.startTimeUnixNano)) {
|
|
1514
|
+
pushPath(
|
|
1515
|
+
errors,
|
|
1516
|
+
`${spanPath}.startTimeUnixNano`,
|
|
1517
|
+
"must be a decimal-string 64-bit integer"
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
if (span.endTimeUnixNano !== void 0 && (typeof span.endTimeUnixNano !== "string" || !/^\d+$/.test(span.endTimeUnixNano))) {
|
|
1521
|
+
pushPath(
|
|
1522
|
+
errors,
|
|
1523
|
+
`${spanPath}.endTimeUnixNano`,
|
|
1524
|
+
"must be a decimal-string 64-bit integer when present"
|
|
1525
|
+
);
|
|
1526
|
+
}
|
|
1527
|
+
if (typeof span.startTimeUnixNano === "string" && /^\d+$/.test(span.startTimeUnixNano) && typeof span.endTimeUnixNano === "string" && /^\d+$/.test(span.endTimeUnixNano)) {
|
|
1528
|
+
try {
|
|
1529
|
+
if (BigInt(span.endTimeUnixNano) < BigInt(span.startTimeUnixNano)) {
|
|
1530
|
+
pushPath(
|
|
1531
|
+
errors,
|
|
1532
|
+
`${spanPath}.endTimeUnixNano`,
|
|
1533
|
+
"must be >= startTimeUnixNano"
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
} catch {
|
|
1537
|
+
pushPath(errors, `${spanPath}.endTimeUnixNano`, "out of integer range");
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
if (Array.isArray(span.attributes)) {
|
|
1541
|
+
span.attributes.forEach((attr, ai) => {
|
|
1542
|
+
const attrPath = `${spanPath}.attributes[${ai}]`;
|
|
1543
|
+
if (!isRecord3(attr)) {
|
|
1544
|
+
pushPath(errors, attrPath, "must be an object");
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
if (typeof attr.key !== "string") {
|
|
1548
|
+
pushPath(errors, `${attrPath}.key`, "must be a string");
|
|
1549
|
+
}
|
|
1550
|
+
validateAnyValue(errors, `${attrPath}.value`, attr.value);
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
if (typeof span.kind === "number") {
|
|
1554
|
+
if (!Number.isInteger(span.kind)) {
|
|
1555
|
+
pushPath(errors, `${spanPath}.kind`, "must be an integer SpanKind enum");
|
|
1556
|
+
}
|
|
1557
|
+
} else if (typeof span.kind === "string") {
|
|
1558
|
+
warnings.push(
|
|
1559
|
+
`${spanPath}.kind: string SpanKind is historical reader-compat only; producer wire format uses numeric enums`
|
|
1560
|
+
);
|
|
1561
|
+
} else if (span.kind !== void 0) {
|
|
1562
|
+
pushPath(
|
|
1563
|
+
errors,
|
|
1564
|
+
`${spanPath}.kind`,
|
|
1565
|
+
"must be numeric SpanKind or historical string enum"
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
if (!isRecord3(span.status)) {
|
|
1569
|
+
pushPath(errors, `${spanPath}.status`, "must be an object");
|
|
1570
|
+
} else {
|
|
1571
|
+
const code = span.status.code;
|
|
1572
|
+
if (typeof code === "number") {
|
|
1573
|
+
if (![0, 1, 2].includes(code)) {
|
|
1574
|
+
pushPath(
|
|
1575
|
+
errors,
|
|
1576
|
+
`${spanPath}.status.code`,
|
|
1577
|
+
"must be numeric StatusCode 0 (UNSET), 1 (OK), or 2 (ERROR)"
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
} else if (typeof code === "string") {
|
|
1581
|
+
const upper = code.toUpperCase();
|
|
1582
|
+
if (upper !== "STATUS_CODE_UNSET" && upper !== "STATUS_CODE_OK" && upper !== "STATUS_CODE_ERROR" && upper !== "UNSET" && upper !== "OK" && upper !== "ERROR" && !/^[012]$/.test(code.trim())) {
|
|
1583
|
+
pushPath(
|
|
1584
|
+
errors,
|
|
1585
|
+
`${spanPath}.status.code`,
|
|
1586
|
+
"unrecognized StatusCode string"
|
|
1587
|
+
);
|
|
1588
|
+
} else {
|
|
1589
|
+
warnings.push(
|
|
1590
|
+
`${spanPath}.status.code: string StatusCode is historical reader-compat only; producer wire format uses numeric 0/1/2`
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
} else {
|
|
1594
|
+
pushPath(
|
|
1595
|
+
errors,
|
|
1596
|
+
`${spanPath}.status.code`,
|
|
1597
|
+
"must be numeric StatusCode 0/1/2 or historical string enum"
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
});
|
|
1602
|
+
});
|
|
1603
|
+
});
|
|
1604
|
+
return { ok: errors.length === 0, format: "otlp-json", errors, warnings };
|
|
1605
|
+
}
|
|
1356
1606
|
function validateExportContent(format, content) {
|
|
1357
1607
|
const errors = [];
|
|
1358
1608
|
const warnings = [EXPERIMENTAL];
|
|
@@ -1398,25 +1648,7 @@ function validateExportContent(format, content) {
|
|
|
1398
1648
|
return { ok: errors.length === 0, format, errors, warnings };
|
|
1399
1649
|
}
|
|
1400
1650
|
if (format === "otlp-json") {
|
|
1401
|
-
|
|
1402
|
-
try {
|
|
1403
|
-
parsed = JSON.parse(content);
|
|
1404
|
-
} catch {
|
|
1405
|
-
errors.push("OTLP JSON export is not valid JSON");
|
|
1406
|
-
return { ok: false, format, errors, warnings };
|
|
1407
|
-
}
|
|
1408
|
-
if (!parsed || typeof parsed !== "object") {
|
|
1409
|
-
errors.push("OTLP JSON export must be an object");
|
|
1410
|
-
return { ok: false, format, errors, warnings };
|
|
1411
|
-
}
|
|
1412
|
-
const o = parsed;
|
|
1413
|
-
if (!Array.isArray(o.resourceSpans)) {
|
|
1414
|
-
errors.push("OTLP JSON export must include resourceSpans array");
|
|
1415
|
-
}
|
|
1416
|
-
warnings.push(
|
|
1417
|
-
"OTLP JSON mapping uses OTel GenAI-aligned attributes where applicable; collectors may require transformation."
|
|
1418
|
-
);
|
|
1419
|
-
return { ok: errors.length === 0, format, errors, warnings };
|
|
1651
|
+
return validateOtlpJson(content);
|
|
1420
1652
|
}
|
|
1421
1653
|
errors.push(`Unsupported export format`);
|
|
1422
1654
|
return { ok: false, format, errors, warnings };
|
|
@@ -1917,6 +2149,8 @@ function formatStepLabel(stepType, stepName) {
|
|
|
1917
2149
|
}
|
|
1918
2150
|
|
|
1919
2151
|
// packages/core/src/timeline.ts
|
|
2152
|
+
var ROOT_TIMELINE_DEPTH = 0;
|
|
2153
|
+
var MAX_TIMELINE_DEPTH = 1e3;
|
|
1920
2154
|
function finite(n) {
|
|
1921
2155
|
return typeof n === "number" && Number.isFinite(n);
|
|
1922
2156
|
}
|
|
@@ -1987,16 +2221,51 @@ function buildRunTimeline(events, options = {}) {
|
|
|
1987
2221
|
const computeDepth = (stepId) => {
|
|
1988
2222
|
const cached = depthCache.get(stepId);
|
|
1989
2223
|
if (cached !== void 0) return cached;
|
|
1990
|
-
const
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2224
|
+
const ancestry = [];
|
|
2225
|
+
const ancestryIndexes = /* @__PURE__ */ new Map();
|
|
2226
|
+
let currentStepId = stepId;
|
|
2227
|
+
let resolvedDepth;
|
|
2228
|
+
while (resolvedDepth === void 0) {
|
|
2229
|
+
const cachedDepth = depthCache.get(currentStepId);
|
|
2230
|
+
if (cachedDepth !== void 0) {
|
|
2231
|
+
resolvedDepth = cachedDepth;
|
|
2232
|
+
continue;
|
|
2233
|
+
}
|
|
2234
|
+
const cycleStart = ancestryIndexes.get(currentStepId);
|
|
2235
|
+
if (cycleStart !== void 0) {
|
|
2236
|
+
const cycleStepIds = ancestry.splice(cycleStart);
|
|
2237
|
+
for (const cycleStepId of cycleStepIds) {
|
|
2238
|
+
depthCache.set(cycleStepId, ROOT_TIMELINE_DEPTH);
|
|
2239
|
+
}
|
|
2240
|
+
resolvedDepth = ROOT_TIMELINE_DEPTH;
|
|
2241
|
+
continue;
|
|
2242
|
+
}
|
|
2243
|
+
const currentStep = steps.get(currentStepId);
|
|
2244
|
+
if (!currentStep) {
|
|
2245
|
+
resolvedDepth = ROOT_TIMELINE_DEPTH;
|
|
2246
|
+
continue;
|
|
2247
|
+
}
|
|
2248
|
+
ancestryIndexes.set(currentStepId, ancestry.length);
|
|
2249
|
+
ancestry.push(currentStepId);
|
|
2250
|
+
const parentId = currentStep.parentId;
|
|
2251
|
+
if (typeof parentId !== "string" || parentId.trim() === "" || !steps.has(parentId)) {
|
|
2252
|
+
ancestry.pop();
|
|
2253
|
+
depthCache.set(currentStepId, ROOT_TIMELINE_DEPTH);
|
|
2254
|
+
resolvedDepth = ROOT_TIMELINE_DEPTH;
|
|
2255
|
+
continue;
|
|
2256
|
+
}
|
|
2257
|
+
currentStepId = parentId;
|
|
2258
|
+
}
|
|
2259
|
+
ancestry.reverse();
|
|
2260
|
+
for (const ancestorStepId of ancestry) {
|
|
2261
|
+
resolvedDepth = Math.min(MAX_TIMELINE_DEPTH, resolvedDepth + 1);
|
|
2262
|
+
depthCache.set(ancestorStepId, resolvedDepth);
|
|
2263
|
+
}
|
|
2264
|
+
const resolvedStepDepth = depthCache.get(stepId);
|
|
2265
|
+
if (resolvedStepDepth === void 0) {
|
|
2266
|
+
throw new Error(`Failed to resolve timeline depth for step "${stepId}"`);
|
|
2267
|
+
}
|
|
2268
|
+
return resolvedStepDepth;
|
|
2000
2269
|
};
|
|
2001
2270
|
const entries = [];
|
|
2002
2271
|
for (const [stepId, s] of steps.entries()) {
|