@cognipeer/agent-sdk 0.16.0 → 0.18.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/README.md +1 -1
- package/dist/index.cjs +2160 -379
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +596 -38
- package/dist/index.d.ts +596 -38
- package/dist/index.mjs +2154 -380
- package/dist/index.mjs.map +1 -1
- package/dist/{model-rules-Bg9nSqyN.d.cts → model-rules--welxWDw.d.cts} +2 -0
- package/dist/{model-rules-Bg9nSqyN.d.ts → model-rules--welxWDw.d.ts} +2 -0
- package/dist/model-rules.d.cts +1 -1
- package/dist/model-rules.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -8,6 +8,8 @@ var path = require('path');
|
|
|
8
8
|
var buffer = require('buffer');
|
|
9
9
|
var nanoid = require('nanoid');
|
|
10
10
|
var crypto = require('crypto');
|
|
11
|
+
var zlib = require('zlib');
|
|
12
|
+
var util = require('util');
|
|
11
13
|
var AjvModule = require('ajv');
|
|
12
14
|
|
|
13
15
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -1231,9 +1233,1398 @@ function splitUsage(usage) {
|
|
|
1231
1233
|
}
|
|
1232
1234
|
return { own, subagent, ownCalls: ownEntries.length, subagentCalls: subagentEntries.length, ownEntries, subagentEntries };
|
|
1233
1235
|
}
|
|
1236
|
+
function cacheWriteTokensOf(raw) {
|
|
1237
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
1238
|
+
const details = raw.prompt_tokens_details || raw.promptTokensDetails || raw.input_token_details || raw.inputTokenDetails || {};
|
|
1239
|
+
const candidates = [
|
|
1240
|
+
details.cache_write_tokens,
|
|
1241
|
+
details.cacheWriteTokens,
|
|
1242
|
+
details.cache_creation,
|
|
1243
|
+
raw.cache_write_tokens,
|
|
1244
|
+
raw.cacheWriteTokens,
|
|
1245
|
+
raw.cache_creation_input_tokens,
|
|
1246
|
+
raw.cacheCreationInputTokens,
|
|
1247
|
+
raw.cacheWriteInputTokens,
|
|
1248
|
+
raw.cacheWriteInputTokenCount
|
|
1249
|
+
];
|
|
1250
|
+
for (const value of candidates) {
|
|
1251
|
+
const n = Number(value);
|
|
1252
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
1253
|
+
}
|
|
1254
|
+
return void 0;
|
|
1255
|
+
}
|
|
1234
1256
|
|
|
1235
1257
|
// src/utils/tracing.ts
|
|
1236
1258
|
init_content();
|
|
1259
|
+
|
|
1260
|
+
// src/version.ts
|
|
1261
|
+
var SDK_VERSION = "0.18.0";
|
|
1262
|
+
|
|
1263
|
+
// src/utils/otlp/content.ts
|
|
1264
|
+
init_content();
|
|
1265
|
+
|
|
1266
|
+
// src/utils/otlp/semconv.ts
|
|
1267
|
+
var GENAI_SEMCONV_COMMIT = "547934a";
|
|
1268
|
+
var ATTR = {
|
|
1269
|
+
operationName: "gen_ai.operation.name",
|
|
1270
|
+
providerName: "gen_ai.provider.name",
|
|
1271
|
+
requestModel: "gen_ai.request.model",
|
|
1272
|
+
responseModel: "gen_ai.response.model",
|
|
1273
|
+
responseId: "gen_ai.response.id",
|
|
1274
|
+
finishReasons: "gen_ai.response.finish_reasons",
|
|
1275
|
+
requestStream: "gen_ai.request.stream",
|
|
1276
|
+
outputType: "gen_ai.output.type",
|
|
1277
|
+
conversationId: "gen_ai.conversation.id",
|
|
1278
|
+
agentName: "gen_ai.agent.name",
|
|
1279
|
+
agentVersion: "gen_ai.agent.version",
|
|
1280
|
+
toolName: "gen_ai.tool.name",
|
|
1281
|
+
toolCallId: "gen_ai.tool.call.id",
|
|
1282
|
+
toolType: "gen_ai.tool.type",
|
|
1283
|
+
usageInput: "gen_ai.usage.input_tokens",
|
|
1284
|
+
usageOutput: "gen_ai.usage.output_tokens",
|
|
1285
|
+
usageCacheRead: "gen_ai.usage.cache_read.input_tokens",
|
|
1286
|
+
usageCacheWrite: "gen_ai.usage.cache_write.input_tokens",
|
|
1287
|
+
usageReasoning: "gen_ai.usage.reasoning.output_tokens",
|
|
1288
|
+
errorType: "error.type",
|
|
1289
|
+
// Content (opt-in).
|
|
1290
|
+
systemInstructions: "gen_ai.system_instructions",
|
|
1291
|
+
inputMessages: "gen_ai.input.messages",
|
|
1292
|
+
outputMessages: "gen_ai.output.messages",
|
|
1293
|
+
toolDefinitions: "gen_ai.tool.definitions",
|
|
1294
|
+
toolCallArguments: "gen_ai.tool.call.arguments",
|
|
1295
|
+
toolCallResult: "gen_ai.tool.call.result"
|
|
1296
|
+
};
|
|
1297
|
+
var OPERATION = {
|
|
1298
|
+
chat: "chat",
|
|
1299
|
+
executeTool: "execute_tool",
|
|
1300
|
+
invokeAgent: "invoke_agent"
|
|
1301
|
+
};
|
|
1302
|
+
var PROVIDERS = {
|
|
1303
|
+
openai: "openai",
|
|
1304
|
+
chatopenai: "openai",
|
|
1305
|
+
azure: "azure.ai.openai",
|
|
1306
|
+
azureopenai: "azure.ai.openai",
|
|
1307
|
+
azurechatopenai: "azure.ai.openai",
|
|
1308
|
+
azureaiopenai: "azure.ai.openai",
|
|
1309
|
+
azureaiinference: "azure.ai.inference",
|
|
1310
|
+
anthropic: "anthropic",
|
|
1311
|
+
chatanthropic: "anthropic",
|
|
1312
|
+
bedrock: "aws.bedrock",
|
|
1313
|
+
awsbedrock: "aws.bedrock",
|
|
1314
|
+
chatbedrock: "aws.bedrock",
|
|
1315
|
+
chatbedrockconverse: "aws.bedrock",
|
|
1316
|
+
vertex: "gcp.vertex_ai",
|
|
1317
|
+
vertexai: "gcp.vertex_ai",
|
|
1318
|
+
gcpvertexai: "gcp.vertex_ai",
|
|
1319
|
+
chatvertexai: "gcp.vertex_ai",
|
|
1320
|
+
gemini: "gcp.gemini",
|
|
1321
|
+
gcpgemini: "gcp.gemini",
|
|
1322
|
+
chatgooglegenerativeai: "gcp.gemini",
|
|
1323
|
+
// Gemini API or Vertex: the name alone does not say which.
|
|
1324
|
+
google: "gcp.gen_ai",
|
|
1325
|
+
gcpgenai: "gcp.gen_ai",
|
|
1326
|
+
mistral: "mistral",
|
|
1327
|
+
mistralai: "mistral",
|
|
1328
|
+
chatmistralai: "mistral",
|
|
1329
|
+
groq: "groq",
|
|
1330
|
+
chatgroq: "groq",
|
|
1331
|
+
deepseek: "deepseek",
|
|
1332
|
+
chatdeepseek: "deepseek",
|
|
1333
|
+
cohere: "cohere",
|
|
1334
|
+
chatcohere: "cohere",
|
|
1335
|
+
xai: "x_ai",
|
|
1336
|
+
chatxai: "x_ai",
|
|
1337
|
+
perplexity: "perplexity",
|
|
1338
|
+
chatperplexity: "perplexity",
|
|
1339
|
+
watsonx: "ibm.watsonx.ai",
|
|
1340
|
+
ibmwatsonxai: "ibm.watsonx.ai"
|
|
1341
|
+
};
|
|
1342
|
+
function genAiProviderName(hint) {
|
|
1343
|
+
if (!hint) return void 0;
|
|
1344
|
+
const key = hint.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1345
|
+
return key ? PROVIDERS[key] : void 0;
|
|
1346
|
+
}
|
|
1347
|
+
function errorTypeOf(error) {
|
|
1348
|
+
if (!error) return "_OTHER";
|
|
1349
|
+
if (typeof error.type === "string" && error.type.length > 0) return error.type;
|
|
1350
|
+
if (typeof error.stack === "string") {
|
|
1351
|
+
const match = /^\s*([A-Za-z_$][\w$.]*)\s*(?::|$)/m.exec(error.stack.split("\n", 1)[0] ?? "");
|
|
1352
|
+
if (match) return match[1];
|
|
1353
|
+
}
|
|
1354
|
+
return "_OTHER";
|
|
1355
|
+
}
|
|
1356
|
+
function genAiUsageOf(event) {
|
|
1357
|
+
const num2 = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
1358
|
+
const input = num2(event.inputTokens);
|
|
1359
|
+
const output = num2(event.outputTokens);
|
|
1360
|
+
const cacheRead = num2(event.cachedInputTokens);
|
|
1361
|
+
const cacheWrite = num2(event.cacheWriteTokens);
|
|
1362
|
+
const reasoning = num2(event.reasoningTokens);
|
|
1363
|
+
if (input + output + cacheRead + cacheWrite + reasoning + num2(event.totalTokens) === 0) return void 0;
|
|
1364
|
+
const basis = event.usageBasis ?? {};
|
|
1365
|
+
return {
|
|
1366
|
+
input: basis.inputExcludesCache ? input + cacheRead + cacheWrite : input,
|
|
1367
|
+
output: basis.outputExcludesReasoning ? output + reasoning : output,
|
|
1368
|
+
...cacheRead > 0 ? { cacheRead } : {},
|
|
1369
|
+
...cacheWrite > 0 ? { cacheWrite } : {},
|
|
1370
|
+
...reasoning > 0 ? { reasoning } : {}
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// src/utils/otlp/content.ts
|
|
1375
|
+
var CAPTURE = Symbol.for("cognipeer.agent-sdk.traceCapture");
|
|
1376
|
+
var DEFAULTS = {
|
|
1377
|
+
maxStringChars: 4096,
|
|
1378
|
+
maxMessages: 32,
|
|
1379
|
+
maxAttributeBytes: 32768
|
|
1380
|
+
};
|
|
1381
|
+
var FIELDS = ["system", "input", "output", "tools", "toolArgs", "toolResults", "sections"];
|
|
1382
|
+
function resolveContentOptions(content) {
|
|
1383
|
+
const given = typeof content === "object" && content !== null ? content : {};
|
|
1384
|
+
const enabled = typeof content === "boolean" ? content : given.enabled === true;
|
|
1385
|
+
const positive = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : fallback;
|
|
1386
|
+
return {
|
|
1387
|
+
enabled,
|
|
1388
|
+
include: Array.isArray(given.include) ? given.include.filter((field) => FIELDS.includes(field)) : [...FIELDS],
|
|
1389
|
+
maxStringChars: positive(given.maxStringChars, DEFAULTS.maxStringChars),
|
|
1390
|
+
maxMessages: positive(given.maxMessages, DEFAULTS.maxMessages),
|
|
1391
|
+
maxAttributeBytes: positive(given.maxAttributeBytes, DEFAULTS.maxAttributeBytes),
|
|
1392
|
+
redact: typeof given.redact === "function" ? given.redact : void 0,
|
|
1393
|
+
encoding: given.encoding === "structured" ? "structured" : "json"
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1397
|
+
function plain(value) {
|
|
1398
|
+
if (value === void 0) return void 0;
|
|
1399
|
+
try {
|
|
1400
|
+
const text = JSON.stringify(value);
|
|
1401
|
+
return text === void 0 ? void 0 : JSON.parse(text);
|
|
1402
|
+
} catch {
|
|
1403
|
+
return void 0;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
var TRUNCATED_MARKER = /\.\.\.\[truncated (\d+) chars\]$/;
|
|
1407
|
+
function truncateText(text, max) {
|
|
1408
|
+
const earlier = TRUNCATED_MARKER.exec(text);
|
|
1409
|
+
const body = earlier ? text.slice(0, earlier.index) : text;
|
|
1410
|
+
if (body.length <= max) return text;
|
|
1411
|
+
const lost = body.length - max + (earlier ? Number(earlier[1]) : 0);
|
|
1412
|
+
return `${body.slice(0, max)}...[truncated ${lost} chars]`;
|
|
1413
|
+
}
|
|
1414
|
+
function capStrings(value, max) {
|
|
1415
|
+
if (typeof value === "string") return truncateText(value, max);
|
|
1416
|
+
if (Array.isArray(value)) return value.map((item) => capStrings(item, max));
|
|
1417
|
+
if (isRecord2(value)) {
|
|
1418
|
+
const out = {};
|
|
1419
|
+
for (const [key, item] of Object.entries(value)) out[key] = capStrings(item, max);
|
|
1420
|
+
return out;
|
|
1421
|
+
}
|
|
1422
|
+
return value;
|
|
1423
|
+
}
|
|
1424
|
+
function asObject(value) {
|
|
1425
|
+
let parsed = value;
|
|
1426
|
+
if (typeof value === "string") {
|
|
1427
|
+
try {
|
|
1428
|
+
parsed = JSON.parse(value);
|
|
1429
|
+
} catch {
|
|
1430
|
+
parsed = value;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
const copy = plain(parsed);
|
|
1434
|
+
if (copy === void 0) return void 0;
|
|
1435
|
+
return isRecord2(copy) ? copy : { value: copy };
|
|
1436
|
+
}
|
|
1437
|
+
var REASONING_PART_TYPES = /* @__PURE__ */ new Set(["thinking", "redacted_thinking", "reasoning", "reasoning_content"]);
|
|
1438
|
+
function textOf(content) {
|
|
1439
|
+
if (content == null) return "";
|
|
1440
|
+
if (typeof content === "string") return content;
|
|
1441
|
+
if (!Array.isArray(content)) return contentPartToText(content, () => "");
|
|
1442
|
+
return content.filter((part) => !(isRecord2(part) && REASONING_PART_TYPES.has(String(part.type)))).map((part) => contentPartToText(part, () => "")).filter((text) => text.length > 0).join("\n");
|
|
1443
|
+
}
|
|
1444
|
+
function toolCallPartsOf(message) {
|
|
1445
|
+
const calls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
|
|
1446
|
+
const parts = [];
|
|
1447
|
+
for (const call of calls) {
|
|
1448
|
+
if (!isRecord2(call)) continue;
|
|
1449
|
+
const name = call.name ?? call.function?.name;
|
|
1450
|
+
if (typeof name !== "string" || !name) continue;
|
|
1451
|
+
const args = call.args ?? call.arguments ?? call.function?.arguments;
|
|
1452
|
+
const coerced = asObject(args ?? {});
|
|
1453
|
+
const id = typeof call.id === "string" && call.id && !call.idSynthesized ? call.id : void 0;
|
|
1454
|
+
parts.push({ type: "tool_call", ...id ? { id } : {}, name, arguments: coerced ?? {} });
|
|
1455
|
+
}
|
|
1456
|
+
return parts;
|
|
1457
|
+
}
|
|
1458
|
+
function messageOf(raw) {
|
|
1459
|
+
if (!isRecord2(raw)) return void 0;
|
|
1460
|
+
const role = typeof raw.role === "string" ? raw.role : "user";
|
|
1461
|
+
const parts = [];
|
|
1462
|
+
if (role === "tool") {
|
|
1463
|
+
const text2 = textOf(raw.content);
|
|
1464
|
+
const parsed = (() => {
|
|
1465
|
+
try {
|
|
1466
|
+
return JSON.parse(text2);
|
|
1467
|
+
} catch {
|
|
1468
|
+
return text2;
|
|
1469
|
+
}
|
|
1470
|
+
})();
|
|
1471
|
+
parts.push({
|
|
1472
|
+
type: "tool_call_response",
|
|
1473
|
+
...typeof raw.tool_call_id === "string" && raw.tool_call_id ? { id: raw.tool_call_id } : {},
|
|
1474
|
+
response: plain(parsed) ?? text2
|
|
1475
|
+
});
|
|
1476
|
+
return { role, parts, ...typeof raw.name === "string" && raw.name ? { name: raw.name } : {} };
|
|
1477
|
+
}
|
|
1478
|
+
const text = textOf(raw.content);
|
|
1479
|
+
if (text) parts.push({ type: "text", content: text });
|
|
1480
|
+
if (role === "assistant") parts.push(...toolCallPartsOf(raw));
|
|
1481
|
+
if (parts.length === 0 && role !== "assistant") parts.push({ type: "text", content: "" });
|
|
1482
|
+
return { role, parts };
|
|
1483
|
+
}
|
|
1484
|
+
function buildCapturedContent(source, limits) {
|
|
1485
|
+
const out = {};
|
|
1486
|
+
if (Array.isArray(source.input)) {
|
|
1487
|
+
const system = [];
|
|
1488
|
+
const messages = [];
|
|
1489
|
+
for (const raw of source.input) {
|
|
1490
|
+
const message = messageOf(raw);
|
|
1491
|
+
if (!message) continue;
|
|
1492
|
+
if (message.role === "system") {
|
|
1493
|
+
const content = message.parts.map((part) => part.type === "text" ? part.content : "").join("\n");
|
|
1494
|
+
if (content) system.push({ type: "text", content });
|
|
1495
|
+
} else {
|
|
1496
|
+
messages.push(message);
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
if (system.length > 0) out.system = capStrings(system, limits.maxStringChars);
|
|
1500
|
+
const recent = messages.slice(-limits.maxMessages);
|
|
1501
|
+
out.input = capStrings(recent, limits.maxStringChars);
|
|
1502
|
+
}
|
|
1503
|
+
if (source.output !== void 0 && source.output !== null) {
|
|
1504
|
+
const message = messageOf({ ...isRecord2(source.output) ? source.output : { content: String(source.output) }, role: "assistant" });
|
|
1505
|
+
if (message) out.output = capStrings(message, limits.maxStringChars);
|
|
1506
|
+
}
|
|
1507
|
+
if (Array.isArray(source.toolDefinitions) && source.toolDefinitions.length > 0) {
|
|
1508
|
+
out.tools = capStrings(
|
|
1509
|
+
source.toolDefinitions.filter((tool) => tool && typeof tool.name === "string").map((tool) => ({
|
|
1510
|
+
type: "function",
|
|
1511
|
+
name: tool.name,
|
|
1512
|
+
...tool.description ? { description: tool.description } : {},
|
|
1513
|
+
...tool.parameters !== void 0 ? { parameters: plain(tool.parameters) } : {}
|
|
1514
|
+
})),
|
|
1515
|
+
limits.maxStringChars
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
if (source.toolArguments !== void 0) {
|
|
1519
|
+
const args = asObject(source.toolArguments);
|
|
1520
|
+
if (args !== void 0) out.toolArgs = capStrings(args, limits.maxStringChars);
|
|
1521
|
+
}
|
|
1522
|
+
if (source.hasToolResult || source.toolResult !== void 0) {
|
|
1523
|
+
const result = asObject(source.toolResult);
|
|
1524
|
+
if (result !== void 0) out.toolResults = capStrings(result, limits.maxStringChars);
|
|
1525
|
+
}
|
|
1526
|
+
return out;
|
|
1527
|
+
}
|
|
1528
|
+
function capturedContentOf(event) {
|
|
1529
|
+
return event?.[CAPTURE];
|
|
1530
|
+
}
|
|
1531
|
+
function attachCapturedContent(record, content) {
|
|
1532
|
+
Object.defineProperty(record, CAPTURE, { value: content, enumerable: false, configurable: true, writable: true });
|
|
1533
|
+
}
|
|
1534
|
+
var SEPARATE_SYSTEM = /* @__PURE__ */ new Set(["anthropic", "aws.bedrock", "gcp.vertex_ai", "gcp.gemini"]);
|
|
1535
|
+
function toAnyValue(value) {
|
|
1536
|
+
if (value === null || value === void 0) return void 0;
|
|
1537
|
+
if (typeof value === "string") return { stringValue: value };
|
|
1538
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
1539
|
+
if (typeof value === "number") {
|
|
1540
|
+
if (!Number.isFinite(value)) return void 0;
|
|
1541
|
+
return Number.isInteger(value) && Number.isSafeInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
1542
|
+
}
|
|
1543
|
+
if (Array.isArray(value)) {
|
|
1544
|
+
return { arrayValue: { values: value.map((item) => toAnyValue(item) ?? { stringValue: "" }) } };
|
|
1545
|
+
}
|
|
1546
|
+
if (isRecord2(value)) {
|
|
1547
|
+
const values = [];
|
|
1548
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1549
|
+
const any = toAnyValue(item);
|
|
1550
|
+
if (any) values.push({ key, value: any });
|
|
1551
|
+
}
|
|
1552
|
+
return { kvlistValue: { values } };
|
|
1553
|
+
}
|
|
1554
|
+
return void 0;
|
|
1555
|
+
}
|
|
1556
|
+
var byteLength = (text) => buffer.Buffer.byteLength(text, "utf8");
|
|
1557
|
+
function render(value, field, options, info) {
|
|
1558
|
+
let working = plain(value);
|
|
1559
|
+
if (working === void 0) return void 0;
|
|
1560
|
+
if (options.redact) {
|
|
1561
|
+
try {
|
|
1562
|
+
working = options.redact(plain(working), { field, ...info });
|
|
1563
|
+
} catch {
|
|
1564
|
+
return void 0;
|
|
1565
|
+
}
|
|
1566
|
+
working = plain(working);
|
|
1567
|
+
if (working === void 0 || working === null) return void 0;
|
|
1568
|
+
}
|
|
1569
|
+
working = capStrings(working, options.maxStringChars);
|
|
1570
|
+
if ((field === "input" || field === "system" || field === "sections") && Array.isArray(working) && working.length > options.maxMessages) {
|
|
1571
|
+
working = working.slice(-options.maxMessages);
|
|
1572
|
+
}
|
|
1573
|
+
let text = JSON.stringify(working);
|
|
1574
|
+
if (text === void 0) return void 0;
|
|
1575
|
+
if (byteLength(text) > options.maxAttributeBytes) {
|
|
1576
|
+
if (field === "input" && Array.isArray(working)) {
|
|
1577
|
+
const messages = [...working];
|
|
1578
|
+
while (messages.length > 1 && byteLength(JSON.stringify(messages)) > options.maxAttributeBytes) messages.shift();
|
|
1579
|
+
working = messages;
|
|
1580
|
+
text = JSON.stringify(working);
|
|
1581
|
+
}
|
|
1582
|
+
if (byteLength(text) > options.maxAttributeBytes) {
|
|
1583
|
+
working = { truncated: true };
|
|
1584
|
+
text = JSON.stringify(working);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
return options.encoding === "structured" ? toAnyValue(working) : { stringValue: text };
|
|
1588
|
+
}
|
|
1589
|
+
function contentAttributes(kind, event, provider, options) {
|
|
1590
|
+
if (!options?.enabled) return [];
|
|
1591
|
+
const captured = capturedContentOf(event);
|
|
1592
|
+
if (!captured) return [];
|
|
1593
|
+
const include = new Set(options.include);
|
|
1594
|
+
const info = {
|
|
1595
|
+
eventType: event.type,
|
|
1596
|
+
...event.spanId ? { spanId: event.spanId } : {},
|
|
1597
|
+
...kind === "execute_tool" && event.actor?.name ? { toolName: event.actor.name } : {},
|
|
1598
|
+
...event.model ? { model: event.model } : {}
|
|
1599
|
+
};
|
|
1600
|
+
const attrs = [];
|
|
1601
|
+
const add = (key, value) => {
|
|
1602
|
+
if (value) attrs.push({ key, value });
|
|
1603
|
+
};
|
|
1604
|
+
if (kind === "chat") {
|
|
1605
|
+
const separate = provider !== void 0 && SEPARATE_SYSTEM.has(provider);
|
|
1606
|
+
const system = captured.system ?? [];
|
|
1607
|
+
if (separate) {
|
|
1608
|
+
if (include.has("system") && system.length > 0) add(ATTR.systemInstructions, render(system, "system", options, info));
|
|
1609
|
+
if (include.has("input") && captured.input) add(ATTR.inputMessages, render(captured.input, "input", options, info));
|
|
1610
|
+
} else if (include.has("input") && (captured.input || system.length > 0)) {
|
|
1611
|
+
const messages = captured.input ?? [];
|
|
1612
|
+
const capped = messages.slice(-options.maxMessages);
|
|
1613
|
+
const withSystem = system.length > 0 ? [{ role: "system", parts: system }, ...capped] : capped;
|
|
1614
|
+
add(ATTR.inputMessages, render(withSystem, "input", { ...options, maxMessages: options.maxMessages + 1 }, info));
|
|
1615
|
+
}
|
|
1616
|
+
if (include.has("output") && captured.output) {
|
|
1617
|
+
const reason = event.rawFinishReason ?? event.finishReason;
|
|
1618
|
+
const finish = reason === "tool_calls" ? "tool_call" : reason;
|
|
1619
|
+
add(ATTR.outputMessages, render([{ ...captured.output, ...finish ? { finish_reason: finish } : {} }], "output", options, info));
|
|
1620
|
+
}
|
|
1621
|
+
if (include.has("tools") && captured.tools) add(ATTR.toolDefinitions, render(captured.tools, "tools", options, info));
|
|
1622
|
+
} else {
|
|
1623
|
+
if (include.has("toolArgs") && captured.toolArgs !== void 0) add(ATTR.toolCallArguments, render(captured.toolArgs, "toolArgs", options, info));
|
|
1624
|
+
if (include.has("toolResults") && captured.toolResults !== void 0) add(ATTR.toolCallResult, render(captured.toolResults, "toolResults", options, info));
|
|
1625
|
+
}
|
|
1626
|
+
return attrs;
|
|
1627
|
+
}
|
|
1628
|
+
function sectionsAttribute(sections, event, options) {
|
|
1629
|
+
if (!sections || sections.length === 0) return void 0;
|
|
1630
|
+
const identity2 = sections.filter((section) => section.identity === true);
|
|
1631
|
+
const payload = sections.filter((section) => section.identity !== true);
|
|
1632
|
+
let kept = [];
|
|
1633
|
+
if (options?.enabled && options.include.includes("sections") && payload.length > 0) {
|
|
1634
|
+
kept = redactedSections(payload, options, event);
|
|
1635
|
+
}
|
|
1636
|
+
const max = options?.maxAttributeBytes ?? DEFAULTS.maxAttributeBytes;
|
|
1637
|
+
const encode = (list) => {
|
|
1638
|
+
try {
|
|
1639
|
+
return JSON.stringify(list);
|
|
1640
|
+
} catch {
|
|
1641
|
+
return void 0;
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
let text = encode([...identity2, ...kept]);
|
|
1645
|
+
while (text !== void 0 && kept.length > 0 && byteLength(text) > max) {
|
|
1646
|
+
kept.shift();
|
|
1647
|
+
text = encode([...identity2, ...kept]);
|
|
1648
|
+
}
|
|
1649
|
+
if (text === void 0) {
|
|
1650
|
+
text = encode(identity2);
|
|
1651
|
+
}
|
|
1652
|
+
if (text === void 0 || text === "[]") return void 0;
|
|
1653
|
+
return { key: "cognipeer.sections", value: { stringValue: text } };
|
|
1654
|
+
}
|
|
1655
|
+
function redactedSections(payload, options, event) {
|
|
1656
|
+
let working = plain(payload);
|
|
1657
|
+
if (working === void 0) return [];
|
|
1658
|
+
if (options.redact) {
|
|
1659
|
+
try {
|
|
1660
|
+
working = plain(options.redact(plain(working), {
|
|
1661
|
+
field: "sections",
|
|
1662
|
+
eventType: event.type,
|
|
1663
|
+
...event.spanId ? { spanId: event.spanId } : {},
|
|
1664
|
+
...event.model ? { model: event.model } : {}
|
|
1665
|
+
}));
|
|
1666
|
+
} catch {
|
|
1667
|
+
return [];
|
|
1668
|
+
}
|
|
1669
|
+
if (!Array.isArray(working)) return [];
|
|
1670
|
+
}
|
|
1671
|
+
const capped = capStrings(working, options.maxStringChars);
|
|
1672
|
+
return Array.isArray(capped) ? capped.slice(-options.maxMessages) : [];
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// src/utils/otlp/convert.ts
|
|
1676
|
+
var SCOPE_NAME = "cognipeer-agent-sdk";
|
|
1677
|
+
var SPAN_KIND_INTERNAL = 1;
|
|
1678
|
+
var SPAN_KIND_CLIENT = 3;
|
|
1679
|
+
var FLAG_HAS_PARENT = 256;
|
|
1680
|
+
var FLAG_REMOTE_PARENT = 512;
|
|
1681
|
+
var MAX_STATUS_MESSAGE = 1024;
|
|
1682
|
+
var str = (key, value) => value != null && value !== "" ? { key, value: { stringValue: value } } : null;
|
|
1683
|
+
var strAllowEmpty = (key, value) => value != null ? { key, value: { stringValue: value } } : null;
|
|
1684
|
+
var int = (key, value) => typeof value === "number" && Number.isFinite(value) ? { key, value: { intValue: String(Math.trunc(value)) } } : null;
|
|
1685
|
+
var dbl = (key, value) => typeof value === "number" && Number.isFinite(value) ? { key, value: { doubleValue: value } } : null;
|
|
1686
|
+
var bool = (key, value) => typeof value === "boolean" ? { key, value: { boolValue: value } } : null;
|
|
1687
|
+
var strArray = (key, values) => ({
|
|
1688
|
+
key,
|
|
1689
|
+
value: { arrayValue: { values: values.map((value) => ({ stringValue: value })) } }
|
|
1690
|
+
});
|
|
1691
|
+
var compact = (list) => list.filter((entry) => Boolean(entry));
|
|
1692
|
+
function msToNs(ms) {
|
|
1693
|
+
const whole = Math.floor(ms);
|
|
1694
|
+
return BigInt(whole) * 1000000n + BigInt(Math.round((ms - whole) * 1e6));
|
|
1695
|
+
}
|
|
1696
|
+
function parseMs(iso) {
|
|
1697
|
+
if (!iso) return void 0;
|
|
1698
|
+
const value = Date.parse(iso);
|
|
1699
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
1700
|
+
}
|
|
1701
|
+
function durationNs(durationMs) {
|
|
1702
|
+
return typeof durationMs === "number" && Number.isFinite(durationMs) && durationMs > 0 ? msToNs(durationMs) : 0n;
|
|
1703
|
+
}
|
|
1704
|
+
function classify(event) {
|
|
1705
|
+
if (event.type === "ai_call" || event.type === "summarization") {
|
|
1706
|
+
if (event.skipReason === "cancelled") return "chat";
|
|
1707
|
+
if (event.skipReason || event.status === "skipped") return "plain";
|
|
1708
|
+
return "chat";
|
|
1709
|
+
}
|
|
1710
|
+
if (event.type === "tool_call") {
|
|
1711
|
+
const source = event.debug?.shortCircuitSource;
|
|
1712
|
+
if (event.skipReason || event.status === "skipped" || source === "cache" || source === "plugin") return "plain";
|
|
1713
|
+
if (event.status === "pending") return "plain";
|
|
1714
|
+
return "execute_tool";
|
|
1715
|
+
}
|
|
1716
|
+
if (event.type === "span" && event.actor?.role === "subagent") return "invoke_agent";
|
|
1717
|
+
return "plain";
|
|
1718
|
+
}
|
|
1719
|
+
var knownModel = (model) => model && model !== "unknown-model" && model !== "unknown_model" ? model : void 0;
|
|
1720
|
+
function toolNameOf(event) {
|
|
1721
|
+
if (event.actor?.name) return event.actor.name;
|
|
1722
|
+
const label = event.label.replace(/\s#\d+$/, "");
|
|
1723
|
+
const dash = label.indexOf(" - ");
|
|
1724
|
+
return dash >= 0 ? label.slice(dash + 3) : void 0;
|
|
1725
|
+
}
|
|
1726
|
+
var stripSequence = (label) => label.replace(/\s#\d+$/, "");
|
|
1727
|
+
function cappedMessage(message) {
|
|
1728
|
+
const text = message && message.length > 0 ? message : "Unknown error";
|
|
1729
|
+
return text.length > MAX_STATUS_MESSAGE ? text.slice(0, MAX_STATUS_MESSAGE) : text;
|
|
1730
|
+
}
|
|
1731
|
+
function exceptionEvent(timeNs, error) {
|
|
1732
|
+
return {
|
|
1733
|
+
timeUnixNano: timeNs.toString(),
|
|
1734
|
+
name: "exception",
|
|
1735
|
+
attributes: compact([
|
|
1736
|
+
str("exception.type", errorTypeOf(error)),
|
|
1737
|
+
strAllowEmpty("exception.message", error.message ?? "Unknown error"),
|
|
1738
|
+
str("exception.stacktrace", error.stack)
|
|
1739
|
+
])
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
function sessionToOtlp(file, options) {
|
|
1743
|
+
const useCognipeer = options.semconv !== "gen_ai";
|
|
1744
|
+
const useGenAi = options.semconv !== "cognipeer";
|
|
1745
|
+
const traceId = file.traceId || generateTraceId();
|
|
1746
|
+
const rootSpanId = file.rootSpanId || generateSpanId();
|
|
1747
|
+
const parent = options.parent;
|
|
1748
|
+
const traceState = parent?.traceState || void 0;
|
|
1749
|
+
const traceFlags = (typeof parent?.flags === "number" ? parent.flags : 1) & 255;
|
|
1750
|
+
const flags = traceFlags | FLAG_HAS_PARENT;
|
|
1751
|
+
const rootFlags = parent?.remote ? flags | FLAG_REMOTE_PARENT : flags;
|
|
1752
|
+
const agentName = file.agent?.name;
|
|
1753
|
+
const everyEvent = file.events;
|
|
1754
|
+
const exportedEvents = foldSupersededSpans(everyEvent).filter(
|
|
1755
|
+
(event) => options.terminal || !(event.type === "span" && event.status === "pending")
|
|
1756
|
+
);
|
|
1757
|
+
const startMs = parseMs(file.startedAt);
|
|
1758
|
+
const nodes = exportedEvents.map((event) => {
|
|
1759
|
+
const endMs = parseMs(event.timestamp) ?? startMs ?? Date.now();
|
|
1760
|
+
const endNs = msToNs(endMs);
|
|
1761
|
+
let startNs = endNs - durationNs(event.durationMs);
|
|
1762
|
+
if (startNs < 0n) startNs = 0n;
|
|
1763
|
+
return {
|
|
1764
|
+
event,
|
|
1765
|
+
spanId: event.spanId || generateSpanId(),
|
|
1766
|
+
parentId: event.parentSpanId || rootSpanId,
|
|
1767
|
+
startNs,
|
|
1768
|
+
endNs
|
|
1769
|
+
};
|
|
1770
|
+
});
|
|
1771
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
1772
|
+
for (const node of nodes) {
|
|
1773
|
+
const list = childrenOf.get(node.parentId);
|
|
1774
|
+
if (list) list.push(node);
|
|
1775
|
+
else childrenOf.set(node.parentId, [node]);
|
|
1776
|
+
}
|
|
1777
|
+
const settled = /* @__PURE__ */ new Set();
|
|
1778
|
+
const inProgress = /* @__PURE__ */ new Set();
|
|
1779
|
+
const widen = (node) => {
|
|
1780
|
+
if (settled.has(node) || inProgress.has(node)) return;
|
|
1781
|
+
inProgress.add(node);
|
|
1782
|
+
for (const child of childrenOf.get(node.spanId) ?? []) {
|
|
1783
|
+
if (child === node) continue;
|
|
1784
|
+
widen(child);
|
|
1785
|
+
if (child.startNs < node.startNs) node.startNs = child.startNs;
|
|
1786
|
+
if (child.endNs > node.endNs) node.endNs = child.endNs;
|
|
1787
|
+
}
|
|
1788
|
+
inProgress.delete(node);
|
|
1789
|
+
settled.add(node);
|
|
1790
|
+
};
|
|
1791
|
+
for (const node of nodes) widen(node);
|
|
1792
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1793
|
+
for (const event of everyEvent) if (event.spanId) byId.set(event.spanId, event);
|
|
1794
|
+
const agentOf = (event) => {
|
|
1795
|
+
let cursor = event;
|
|
1796
|
+
for (let hops = 0; cursor && hops < 64; hops++) {
|
|
1797
|
+
if (cursor !== event && cursor.type === "span" && cursor.actor?.role === "subagent") return cursor.actor.name;
|
|
1798
|
+
cursor = cursor.parentSpanId ? byId.get(cursor.parentSpanId) : void 0;
|
|
1799
|
+
}
|
|
1800
|
+
return agentName;
|
|
1801
|
+
};
|
|
1802
|
+
const spans = [];
|
|
1803
|
+
const sessionErrors = (file.errors ?? []).filter((error) => error.eventId === "session");
|
|
1804
|
+
if (options.terminal) {
|
|
1805
|
+
const earliestChild = nodes.reduce(
|
|
1806
|
+
(earliest, node) => earliest === void 0 || node.startNs < earliest ? node.startNs : earliest,
|
|
1807
|
+
void 0
|
|
1808
|
+
);
|
|
1809
|
+
let rootStart = startMs !== void 0 ? msToNs(startMs) : earliestChild ?? msToNs(Date.now());
|
|
1810
|
+
let rootEnd = msToNs(parseMs(file.endedAt) ?? (startMs !== void 0 ? startMs + (file.durationMs ?? 0) : Date.now()));
|
|
1811
|
+
for (const node of childrenOf.get(rootSpanId) ?? []) {
|
|
1812
|
+
if (node.startNs < rootStart) rootStart = node.startNs;
|
|
1813
|
+
if (node.endNs > rootEnd) rootEnd = node.endNs;
|
|
1814
|
+
}
|
|
1815
|
+
if (rootEnd < rootStart) rootEnd = rootStart;
|
|
1816
|
+
const rootName = useGenAi ? agentName ? `${OPERATION.invokeAgent} ${agentName}` : OPERATION.invokeAgent : `agent_session: ${agentName || "agent"}`;
|
|
1817
|
+
const summary = file.summary;
|
|
1818
|
+
const cumulativeEvents = summary?.eventCounts ? Object.values(summary.eventCounts).reduce((total, count) => total + (Number(count) || 0), 0) : file.events.length;
|
|
1819
|
+
const attributes = [];
|
|
1820
|
+
if (useCognipeer) {
|
|
1821
|
+
attributes.push(
|
|
1822
|
+
...compact([
|
|
1823
|
+
strAllowEmpty("cognipeer.session.status", options.cancelled ? "partial" : file.status),
|
|
1824
|
+
dbl("cognipeer.session.duration_ms", file.durationMs),
|
|
1825
|
+
int("cognipeer.session.total_input_tokens", summary?.totalInputTokens),
|
|
1826
|
+
int("cognipeer.session.total_output_tokens", summary?.totalOutputTokens),
|
|
1827
|
+
int("cognipeer.session.total_cached_input_tokens", summary?.totalCachedInputTokens),
|
|
1828
|
+
int("cognipeer.session.total_bytes_in", summary?.totalBytesIn),
|
|
1829
|
+
int("cognipeer.session.total_bytes_out", summary?.totalBytesOut),
|
|
1830
|
+
int("cognipeer.session.event_count", cumulativeEvents)
|
|
1831
|
+
])
|
|
1832
|
+
);
|
|
1833
|
+
for (const [key, count] of Object.entries(summary?.eventCounts ?? {})) {
|
|
1834
|
+
attributes.push({ key: `cognipeer.session.event_count.${key}`, value: { intValue: String(count) } });
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
if (useGenAi) {
|
|
1838
|
+
attributes.push(
|
|
1839
|
+
...compact([
|
|
1840
|
+
str(ATTR.operationName, OPERATION.invokeAgent),
|
|
1841
|
+
str(ATTR.agentName, agentName),
|
|
1842
|
+
str(ATTR.agentVersion, file.agent?.version),
|
|
1843
|
+
str(ATTR.requestModel, knownModel(file.agent?.model)),
|
|
1844
|
+
str(ATTR.conversationId, file.threadId)
|
|
1845
|
+
])
|
|
1846
|
+
);
|
|
1847
|
+
}
|
|
1848
|
+
const root = {
|
|
1849
|
+
traceId,
|
|
1850
|
+
spanId: rootSpanId,
|
|
1851
|
+
parentSpanId: parent?.spanId ?? "",
|
|
1852
|
+
...traceState ? { traceState } : {},
|
|
1853
|
+
flags: rootFlags,
|
|
1854
|
+
name: rootName,
|
|
1855
|
+
kind: SPAN_KIND_INTERNAL,
|
|
1856
|
+
startTimeUnixNano: rootStart.toString(),
|
|
1857
|
+
endTimeUnixNano: rootEnd.toString(),
|
|
1858
|
+
attributes,
|
|
1859
|
+
status: { code: 0 }
|
|
1860
|
+
};
|
|
1861
|
+
if (sessionErrors.length > 0) {
|
|
1862
|
+
root.status = {
|
|
1863
|
+
code: 2,
|
|
1864
|
+
message: cappedMessage(sessionErrors.map((error) => error.message).join("; "))
|
|
1865
|
+
};
|
|
1866
|
+
if (useGenAi) root.attributes.push({ key: ATTR.errorType, value: { stringValue: errorTypeOf({ type: sessionErrors[0].errorName, stack: sessionErrors[0].stack }) } });
|
|
1867
|
+
root.events = sessionErrors.map((error) => {
|
|
1868
|
+
const at = parseMs(error.timestamp);
|
|
1869
|
+
return exceptionEvent(at !== void 0 ? msToNs(at) : rootEnd, {
|
|
1870
|
+
message: error.message,
|
|
1871
|
+
stack: error.stack,
|
|
1872
|
+
type: error.errorName
|
|
1873
|
+
});
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
spans.push(root);
|
|
1877
|
+
}
|
|
1878
|
+
for (const node of nodes) {
|
|
1879
|
+
const event = node.event;
|
|
1880
|
+
const kind = classify(event);
|
|
1881
|
+
const failed = event.status === "error";
|
|
1882
|
+
const cancelledChat = kind === "chat" && event.skipReason === "cancelled";
|
|
1883
|
+
const attributes = [];
|
|
1884
|
+
if (useCognipeer) {
|
|
1885
|
+
attributes.push(
|
|
1886
|
+
...compact([
|
|
1887
|
+
strAllowEmpty("cognipeer.event.type", event.type),
|
|
1888
|
+
strAllowEmpty("cognipeer.event.label", event.label),
|
|
1889
|
+
int("cognipeer.event.sequence", event.sequence),
|
|
1890
|
+
strAllowEmpty("cognipeer.actor.scope", event.actor?.scope),
|
|
1891
|
+
strAllowEmpty("cognipeer.actor.name", event.actor?.name),
|
|
1892
|
+
strAllowEmpty("cognipeer.actor.role", event.actor?.role),
|
|
1893
|
+
strAllowEmpty("cognipeer.model", event.model),
|
|
1894
|
+
int("cognipeer.tokens.reasoning", event.reasoningTokens),
|
|
1895
|
+
strAllowEmpty("cognipeer.finish_reason", event.finishReason),
|
|
1896
|
+
strAllowEmpty("cognipeer.provider", event.provider),
|
|
1897
|
+
strAllowEmpty("cognipeer.tool.details", event.toolDetails ? JSON.stringify(event.toolDetails) : void 0),
|
|
1898
|
+
int("cognipeer.tokens.input", event.inputTokens),
|
|
1899
|
+
int("cognipeer.tokens.output", event.outputTokens),
|
|
1900
|
+
int("cognipeer.tokens.total", event.totalTokens),
|
|
1901
|
+
int("cognipeer.tokens.cached_input", event.cachedInputTokens),
|
|
1902
|
+
int("cognipeer.bytes.request", event.requestBytes),
|
|
1903
|
+
int("cognipeer.bytes.response", event.responseBytes),
|
|
1904
|
+
strAllowEmpty("cognipeer.tool.execution_id", event.toolExecutionId),
|
|
1905
|
+
strAllowEmpty("cognipeer.retry_of", event.retryOf),
|
|
1906
|
+
strAllowEmpty("cognipeer.event.id", event.id)
|
|
1907
|
+
])
|
|
1908
|
+
);
|
|
1909
|
+
const sectionsAttr = sectionsAttribute(event.data?.sections, event, options.content);
|
|
1910
|
+
if (sectionsAttr) attributes.push(sectionsAttr);
|
|
1911
|
+
attributes.push({ key: "cognipeer.event.status", value: { stringValue: event.status } });
|
|
1912
|
+
}
|
|
1913
|
+
let name = event.label || event.type;
|
|
1914
|
+
let spanKind = SPAN_KIND_INTERNAL;
|
|
1915
|
+
if (kind === "chat") spanKind = SPAN_KIND_CLIENT;
|
|
1916
|
+
if (useGenAi) {
|
|
1917
|
+
const conversation = str(ATTR.conversationId, file.threadId);
|
|
1918
|
+
if (kind === "chat") {
|
|
1919
|
+
const model = knownModel(event.model);
|
|
1920
|
+
name = model ? `${OPERATION.chat} ${model}` : OPERATION.chat;
|
|
1921
|
+
attributes.push(
|
|
1922
|
+
...compact([
|
|
1923
|
+
str(ATTR.operationName, OPERATION.chat),
|
|
1924
|
+
str(ATTR.providerName, genAiProviderName(event.provider)),
|
|
1925
|
+
str(ATTR.requestModel, model),
|
|
1926
|
+
str(ATTR.responseModel, event.responseModel),
|
|
1927
|
+
str(ATTR.responseId, event.responseId),
|
|
1928
|
+
bool(ATTR.requestStream, event.streaming),
|
|
1929
|
+
str(ATTR.outputType, event.outputType)
|
|
1930
|
+
])
|
|
1931
|
+
);
|
|
1932
|
+
if (failed || cancelledChat) {
|
|
1933
|
+
attributes.push(strArray(ATTR.finishReasons, ["error"]));
|
|
1934
|
+
} else {
|
|
1935
|
+
const reason = event.rawFinishReason ?? event.finishReason;
|
|
1936
|
+
if (reason) attributes.push(strArray(ATTR.finishReasons, [reason]));
|
|
1937
|
+
}
|
|
1938
|
+
const usageAllowed = !failed && !cancelledChat && (event.type !== "summarization" || event.debug?.usageFromModel === true);
|
|
1939
|
+
const usage = usageAllowed ? genAiUsageOf(event) : void 0;
|
|
1940
|
+
if (usage) {
|
|
1941
|
+
attributes.push(
|
|
1942
|
+
...compact([
|
|
1943
|
+
int(ATTR.usageInput, usage.input),
|
|
1944
|
+
int(ATTR.usageOutput, usage.output),
|
|
1945
|
+
int(ATTR.usageCacheRead, usage.cacheRead),
|
|
1946
|
+
int(ATTR.usageCacheWrite, usage.cacheWrite),
|
|
1947
|
+
int(ATTR.usageReasoning, usage.reasoning)
|
|
1948
|
+
])
|
|
1949
|
+
);
|
|
1950
|
+
}
|
|
1951
|
+
if (conversation) attributes.push(conversation);
|
|
1952
|
+
attributes.push(...contentAttributes("chat", event, genAiProviderName(event.provider), options.content));
|
|
1953
|
+
} else if (kind === "execute_tool") {
|
|
1954
|
+
const tool = toolNameOf(event);
|
|
1955
|
+
name = tool ? `${OPERATION.executeTool} ${tool}` : OPERATION.executeTool;
|
|
1956
|
+
attributes.push(
|
|
1957
|
+
...compact([
|
|
1958
|
+
str(ATTR.operationName, OPERATION.executeTool),
|
|
1959
|
+
str(ATTR.toolName, tool),
|
|
1960
|
+
str(ATTR.toolCallId, event.toolCallId),
|
|
1961
|
+
str(ATTR.toolType, "function"),
|
|
1962
|
+
str(ATTR.agentName, agentOf(event)),
|
|
1963
|
+
conversation
|
|
1964
|
+
])
|
|
1965
|
+
);
|
|
1966
|
+
attributes.push(...contentAttributes("execute_tool", event, void 0, options.content));
|
|
1967
|
+
} else if (kind === "invoke_agent") {
|
|
1968
|
+
const child = event.actor?.name;
|
|
1969
|
+
name = child ? `${OPERATION.invokeAgent} ${child}` : OPERATION.invokeAgent;
|
|
1970
|
+
attributes.push(...compact([str(ATTR.operationName, OPERATION.invokeAgent), str(ATTR.agentName, child), conversation]));
|
|
1971
|
+
} else {
|
|
1972
|
+
name = stripSequence(name);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
const span = {
|
|
1976
|
+
traceId: event.traceId || traceId,
|
|
1977
|
+
spanId: node.spanId,
|
|
1978
|
+
parentSpanId: node.parentId,
|
|
1979
|
+
...traceState ? { traceState } : {},
|
|
1980
|
+
flags,
|
|
1981
|
+
name,
|
|
1982
|
+
kind: spanKind,
|
|
1983
|
+
startTimeUnixNano: node.startNs.toString(),
|
|
1984
|
+
endTimeUnixNano: node.endNs.toString(),
|
|
1985
|
+
attributes,
|
|
1986
|
+
status: { code: 0 }
|
|
1987
|
+
};
|
|
1988
|
+
if (failed) {
|
|
1989
|
+
const error = event.error ?? { message: "Unknown error" };
|
|
1990
|
+
span.status = { code: 2, message: cappedMessage(error.message) };
|
|
1991
|
+
if (useGenAi) attributes.push({ key: ATTR.errorType, value: { stringValue: errorTypeOf(error) } });
|
|
1992
|
+
span.events = [exceptionEvent(node.endNs, error)];
|
|
1993
|
+
}
|
|
1994
|
+
spans.push(span);
|
|
1995
|
+
}
|
|
1996
|
+
return {
|
|
1997
|
+
resourceSpans: [
|
|
1998
|
+
{
|
|
1999
|
+
resource: { attributes: resourceAttributesOf(file, options, useCognipeer) },
|
|
2000
|
+
scopeSpans: [{ scope: { name: SCOPE_NAME, version: SDK_VERSION }, spans }]
|
|
2001
|
+
}
|
|
2002
|
+
]
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
function resourceAttributesOf(file, options, useCognipeer) {
|
|
2006
|
+
const custom = options.resourceAttributes ?? {};
|
|
2007
|
+
const serviceName = options.serviceName || custom["service.name"] || file.agent?.name || "cognipeer-agent";
|
|
2008
|
+
const attributes = compact([
|
|
2009
|
+
str("service.name", serviceName),
|
|
2010
|
+
str("service.version", file.agent?.version)
|
|
2011
|
+
]);
|
|
2012
|
+
if (useCognipeer) {
|
|
2013
|
+
attributes.push(
|
|
2014
|
+
...compact([
|
|
2015
|
+
str("cognipeer.session.id", file.sessionId),
|
|
2016
|
+
str("cognipeer.thread.id", file.threadId),
|
|
2017
|
+
str("cognipeer.agent.model", file.agent?.model),
|
|
2018
|
+
str("cognipeer.agent.provider", file.agent?.provider),
|
|
2019
|
+
...Object.entries(file.metadata ?? {}).map(([key, value]) => str(`cognipeer.metadata.${key}`, value))
|
|
2020
|
+
])
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
attributes.push(
|
|
2024
|
+
...compact([
|
|
2025
|
+
str("telemetry.sdk.name", SCOPE_NAME),
|
|
2026
|
+
str("telemetry.sdk.language", "nodejs"),
|
|
2027
|
+
str("telemetry.sdk.version", SDK_VERSION)
|
|
2028
|
+
])
|
|
2029
|
+
);
|
|
2030
|
+
for (const [key, value] of Object.entries(custom)) {
|
|
2031
|
+
if (key === "service.name") continue;
|
|
2032
|
+
const index = attributes.findIndex((attr) => attr.key === key);
|
|
2033
|
+
const entry = str(key, value);
|
|
2034
|
+
if (!entry) continue;
|
|
2035
|
+
if (index >= 0) attributes[index] = entry;
|
|
2036
|
+
else attributes.push(entry);
|
|
2037
|
+
}
|
|
2038
|
+
return attributes;
|
|
2039
|
+
}
|
|
2040
|
+
function countSpans(request) {
|
|
2041
|
+
let total = 0;
|
|
2042
|
+
for (const rs of request.resourceSpans) for (const ss of rs.scopeSpans) total += ss.spans.length;
|
|
2043
|
+
return total;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
// src/utils/otlp/env.ts
|
|
2047
|
+
var warned = /* @__PURE__ */ new Set();
|
|
2048
|
+
function warnOnce(message) {
|
|
2049
|
+
if (warned.has(message)) return;
|
|
2050
|
+
warned.add(message);
|
|
2051
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") console.warn(message);
|
|
2052
|
+
}
|
|
2053
|
+
function pick(env, ...names) {
|
|
2054
|
+
for (const name of names) {
|
|
2055
|
+
const value = env[name];
|
|
2056
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
2057
|
+
}
|
|
2058
|
+
return void 0;
|
|
2059
|
+
}
|
|
2060
|
+
function decode(value) {
|
|
2061
|
+
try {
|
|
2062
|
+
return decodeURIComponent(value);
|
|
2063
|
+
} catch {
|
|
2064
|
+
return value;
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
function parseKeyValueList(raw) {
|
|
2068
|
+
const out = {};
|
|
2069
|
+
if (!raw) return out;
|
|
2070
|
+
for (const part of raw.split(",")) {
|
|
2071
|
+
const index = part.indexOf("=");
|
|
2072
|
+
if (index <= 0) continue;
|
|
2073
|
+
const key = part.slice(0, index).trim();
|
|
2074
|
+
if (!key) continue;
|
|
2075
|
+
out[key] = decode(part.slice(index + 1).trim());
|
|
2076
|
+
}
|
|
2077
|
+
return out;
|
|
2078
|
+
}
|
|
2079
|
+
function tracesEndpointFrom(base) {
|
|
2080
|
+
return `${base.replace(/\/+$/, "")}/v1/traces`;
|
|
2081
|
+
}
|
|
2082
|
+
function protocolFrom(raw, fallback) {
|
|
2083
|
+
if (!raw) return fallback;
|
|
2084
|
+
const value = raw.toLowerCase();
|
|
2085
|
+
if (value === "http/protobuf" || value === "http/json") return value;
|
|
2086
|
+
warnOnce(
|
|
2087
|
+
value === "grpc" ? `[agent-sdk] OTLP/gRPC is not supported; exporting over ${fallback} instead.` : `[agent-sdk] OTLP protocol "${raw}" is not supported (use http/json or http/protobuf); falling back to ${fallback}.`
|
|
2088
|
+
);
|
|
2089
|
+
return fallback;
|
|
2090
|
+
}
|
|
2091
|
+
function resolveOtlpEnv(env, explicit) {
|
|
2092
|
+
const explicitEndpoint = typeof explicit.endpoint === "string" ? explicit.endpoint.trim() : "";
|
|
2093
|
+
const envDriven = explicitEndpoint.length === 0;
|
|
2094
|
+
const resourceAttributes = parseKeyValueList(pick(env, "OTEL_RESOURCE_ATTRIBUTES"));
|
|
2095
|
+
const serviceName = pick(env, "OTEL_SERVICE_NAME");
|
|
2096
|
+
if (!envDriven) {
|
|
2097
|
+
return {
|
|
2098
|
+
envDriven,
|
|
2099
|
+
endpoint: explicitEndpoint,
|
|
2100
|
+
headers: { ...explicit.headers ?? {} },
|
|
2101
|
+
protocol: explicit.protocol ?? "http/json",
|
|
2102
|
+
compression: explicit.compression ?? "none",
|
|
2103
|
+
timeoutMs: explicit.timeoutMs,
|
|
2104
|
+
serviceName,
|
|
2105
|
+
resourceAttributes,
|
|
2106
|
+
disabled: false
|
|
2107
|
+
};
|
|
2108
|
+
}
|
|
2109
|
+
const tracesEndpoint = pick(env, "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT");
|
|
2110
|
+
const baseEndpoint = pick(env, "OTEL_EXPORTER_OTLP_ENDPOINT");
|
|
2111
|
+
const endpoint = tracesEndpoint ?? (baseEndpoint ? tracesEndpointFrom(baseEndpoint) : void 0);
|
|
2112
|
+
const envHeaders = {
|
|
2113
|
+
...parseKeyValueList(pick(env, "OTEL_EXPORTER_OTLP_HEADERS")),
|
|
2114
|
+
...parseKeyValueList(pick(env, "OTEL_EXPORTER_OTLP_TRACES_HEADERS"))
|
|
2115
|
+
};
|
|
2116
|
+
const timeoutRaw = pick(env, "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT", "OTEL_EXPORTER_OTLP_TIMEOUT");
|
|
2117
|
+
const timeout = timeoutRaw !== void 0 ? Number(timeoutRaw) : void 0;
|
|
2118
|
+
const compressionRaw = pick(env, "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION", "OTEL_EXPORTER_OTLP_COMPRESSION")?.toLowerCase();
|
|
2119
|
+
return {
|
|
2120
|
+
envDriven,
|
|
2121
|
+
endpoint,
|
|
2122
|
+
headers: { ...envHeaders, ...explicit.headers ?? {} },
|
|
2123
|
+
protocol: explicit.protocol ?? protocolFrom(pick(env, "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", "OTEL_EXPORTER_OTLP_PROTOCOL"), "http/protobuf"),
|
|
2124
|
+
compression: explicit.compression ?? (compressionRaw === "gzip" ? "gzip" : "none"),
|
|
2125
|
+
timeoutMs: explicit.timeoutMs ?? (timeout !== void 0 && Number.isFinite(timeout) && timeout > 0 ? timeout : void 0),
|
|
2126
|
+
serviceName,
|
|
2127
|
+
resourceAttributes,
|
|
2128
|
+
disabled: pick(env, "OTEL_SDK_DISABLED")?.toLowerCase() === "true" || pick(env, "OTEL_TRACES_EXPORTER")?.toLowerCase() === "none"
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
function currentEnv() {
|
|
2132
|
+
return typeof process !== "undefined" && process.env ? process.env : {};
|
|
2133
|
+
}
|
|
2134
|
+
var WIRE_VARINT = 0;
|
|
2135
|
+
var WIRE_FIXED64 = 1;
|
|
2136
|
+
var WIRE_LEN = 2;
|
|
2137
|
+
var WIRE_FIXED32 = 5;
|
|
2138
|
+
var textEncoder = new TextEncoder();
|
|
2139
|
+
var Writer = class {
|
|
2140
|
+
constructor() {
|
|
2141
|
+
this.buf = new Uint8Array(128);
|
|
2142
|
+
this.len = 0;
|
|
2143
|
+
this.view = new DataView(this.buf.buffer);
|
|
2144
|
+
}
|
|
2145
|
+
ensure(extra) {
|
|
2146
|
+
if (this.len + extra <= this.buf.length) return;
|
|
2147
|
+
let size = this.buf.length * 2;
|
|
2148
|
+
while (size < this.len + extra) size *= 2;
|
|
2149
|
+
const next = new Uint8Array(size);
|
|
2150
|
+
next.set(this.buf.subarray(0, this.len));
|
|
2151
|
+
this.buf = next;
|
|
2152
|
+
this.view = new DataView(next.buffer);
|
|
2153
|
+
}
|
|
2154
|
+
byte(value) {
|
|
2155
|
+
this.ensure(1);
|
|
2156
|
+
this.buf[this.len++] = value;
|
|
2157
|
+
}
|
|
2158
|
+
varint(value) {
|
|
2159
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
|
|
2160
|
+
let n2 = value;
|
|
2161
|
+
while (n2 >= 128) {
|
|
2162
|
+
this.byte(n2 % 128 | 128);
|
|
2163
|
+
n2 = Math.floor(n2 / 128);
|
|
2164
|
+
}
|
|
2165
|
+
this.byte(n2);
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
let n = BigInt.asUintN(64, BigInt(value));
|
|
2169
|
+
while (n >= 128n) {
|
|
2170
|
+
this.byte(Number(n & 127n) | 128);
|
|
2171
|
+
n >>= 7n;
|
|
2172
|
+
}
|
|
2173
|
+
this.byte(Number(n));
|
|
2174
|
+
}
|
|
2175
|
+
tag(field, wire) {
|
|
2176
|
+
this.varint(field * 8 + wire);
|
|
2177
|
+
}
|
|
2178
|
+
raw(bytes) {
|
|
2179
|
+
this.ensure(bytes.length);
|
|
2180
|
+
this.buf.set(bytes, this.len);
|
|
2181
|
+
this.len += bytes.length;
|
|
2182
|
+
}
|
|
2183
|
+
fixed64(value) {
|
|
2184
|
+
this.ensure(8);
|
|
2185
|
+
this.view.setBigUint64(this.len, BigInt.asUintN(64, value), true);
|
|
2186
|
+
this.len += 8;
|
|
2187
|
+
}
|
|
2188
|
+
fixed32(value) {
|
|
2189
|
+
this.ensure(4);
|
|
2190
|
+
this.view.setUint32(this.len, value >>> 0, true);
|
|
2191
|
+
this.len += 4;
|
|
2192
|
+
}
|
|
2193
|
+
double(value) {
|
|
2194
|
+
this.ensure(8);
|
|
2195
|
+
this.view.setFloat64(this.len, value, true);
|
|
2196
|
+
this.len += 8;
|
|
2197
|
+
}
|
|
2198
|
+
finish() {
|
|
2199
|
+
return this.buf.slice(0, this.len);
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
function lenField(w, field, bytes) {
|
|
2203
|
+
w.tag(field, WIRE_LEN);
|
|
2204
|
+
w.varint(bytes.length);
|
|
2205
|
+
w.raw(bytes);
|
|
2206
|
+
}
|
|
2207
|
+
function stringField(w, field, value) {
|
|
2208
|
+
if (!value) return;
|
|
2209
|
+
lenField(w, field, textEncoder.encode(value));
|
|
2210
|
+
}
|
|
2211
|
+
function hexBytes(hex, bytes) {
|
|
2212
|
+
if (!hex) return void 0;
|
|
2213
|
+
const out = new Uint8Array(bytes);
|
|
2214
|
+
for (let i = 0; i < bytes; i++) {
|
|
2215
|
+
const pair = hex.slice(i * 2, i * 2 + 2);
|
|
2216
|
+
const value = /^[0-9a-fA-F]{2}$/.test(pair) ? parseInt(pair, 16) : 0;
|
|
2217
|
+
out[i] = value;
|
|
2218
|
+
}
|
|
2219
|
+
return out;
|
|
2220
|
+
}
|
|
2221
|
+
function base64Bytes(value) {
|
|
2222
|
+
return new Uint8Array(buffer.Buffer.from(value, "base64"));
|
|
2223
|
+
}
|
|
2224
|
+
function encodeAnyValue(value) {
|
|
2225
|
+
const w = new Writer();
|
|
2226
|
+
if (value.stringValue !== void 0) {
|
|
2227
|
+
lenField(w, 1, textEncoder.encode(value.stringValue));
|
|
2228
|
+
} else if (value.boolValue !== void 0) {
|
|
2229
|
+
w.tag(2, WIRE_VARINT);
|
|
2230
|
+
w.varint(value.boolValue ? 1 : 0);
|
|
2231
|
+
} else if (value.intValue !== void 0) {
|
|
2232
|
+
w.tag(3, WIRE_VARINT);
|
|
2233
|
+
w.varint(BigInt(value.intValue));
|
|
2234
|
+
} else if (value.doubleValue !== void 0) {
|
|
2235
|
+
w.tag(4, WIRE_FIXED64);
|
|
2236
|
+
w.double(value.doubleValue);
|
|
2237
|
+
} else if (value.arrayValue !== void 0) {
|
|
2238
|
+
const inner = new Writer();
|
|
2239
|
+
for (const item of value.arrayValue.values) lenField(inner, 1, encodeAnyValue(item));
|
|
2240
|
+
lenField(w, 5, inner.finish());
|
|
2241
|
+
} else if (value.kvlistValue !== void 0) {
|
|
2242
|
+
const inner = new Writer();
|
|
2243
|
+
for (const kv of value.kvlistValue.values) lenField(inner, 1, encodeKeyValue(kv));
|
|
2244
|
+
lenField(w, 6, inner.finish());
|
|
2245
|
+
} else if (value.bytesValue !== void 0) {
|
|
2246
|
+
lenField(w, 7, base64Bytes(value.bytesValue));
|
|
2247
|
+
}
|
|
2248
|
+
return w.finish();
|
|
2249
|
+
}
|
|
2250
|
+
function encodeKeyValue(kv) {
|
|
2251
|
+
const w = new Writer();
|
|
2252
|
+
stringField(w, 1, kv.key);
|
|
2253
|
+
lenField(w, 2, encodeAnyValue(kv.value));
|
|
2254
|
+
return w.finish();
|
|
2255
|
+
}
|
|
2256
|
+
function encodeSpanEvent(event) {
|
|
2257
|
+
const w = new Writer();
|
|
2258
|
+
w.tag(1, WIRE_FIXED64);
|
|
2259
|
+
w.fixed64(BigInt(event.timeUnixNano));
|
|
2260
|
+
stringField(w, 2, event.name);
|
|
2261
|
+
for (const attr of event.attributes) lenField(w, 3, encodeKeyValue(attr));
|
|
2262
|
+
return w.finish();
|
|
2263
|
+
}
|
|
2264
|
+
function encodeSpan(span) {
|
|
2265
|
+
const w = new Writer();
|
|
2266
|
+
const traceId = hexBytes(span.traceId, 16);
|
|
2267
|
+
if (traceId) lenField(w, 1, traceId);
|
|
2268
|
+
const spanId = hexBytes(span.spanId, 8);
|
|
2269
|
+
if (spanId) lenField(w, 2, spanId);
|
|
2270
|
+
stringField(w, 3, span.traceState);
|
|
2271
|
+
const parent = hexBytes(span.parentSpanId, 8);
|
|
2272
|
+
if (parent) lenField(w, 4, parent);
|
|
2273
|
+
stringField(w, 5, span.name);
|
|
2274
|
+
if (span.kind) {
|
|
2275
|
+
w.tag(6, WIRE_VARINT);
|
|
2276
|
+
w.varint(span.kind);
|
|
2277
|
+
}
|
|
2278
|
+
w.tag(7, WIRE_FIXED64);
|
|
2279
|
+
w.fixed64(BigInt(span.startTimeUnixNano));
|
|
2280
|
+
w.tag(8, WIRE_FIXED64);
|
|
2281
|
+
w.fixed64(BigInt(span.endTimeUnixNano));
|
|
2282
|
+
for (const attr of span.attributes) lenField(w, 9, encodeKeyValue(attr));
|
|
2283
|
+
for (const event of span.events ?? []) lenField(w, 11, encodeSpanEvent(event));
|
|
2284
|
+
const status = new Writer();
|
|
2285
|
+
stringField(status, 2, span.status.message);
|
|
2286
|
+
if (span.status.code) {
|
|
2287
|
+
status.tag(3, WIRE_VARINT);
|
|
2288
|
+
status.varint(span.status.code);
|
|
2289
|
+
}
|
|
2290
|
+
lenField(w, 15, status.finish());
|
|
2291
|
+
if (span.flags) {
|
|
2292
|
+
w.tag(16, WIRE_FIXED32);
|
|
2293
|
+
w.fixed32(span.flags);
|
|
2294
|
+
}
|
|
2295
|
+
return w.finish();
|
|
2296
|
+
}
|
|
2297
|
+
function encodeExportTraceServiceRequest(request) {
|
|
2298
|
+
const w = new Writer();
|
|
2299
|
+
for (const rs of request.resourceSpans) {
|
|
2300
|
+
const resourceSpans = new Writer();
|
|
2301
|
+
const resource = new Writer();
|
|
2302
|
+
for (const attr of rs.resource.attributes) lenField(resource, 1, encodeKeyValue(attr));
|
|
2303
|
+
lenField(resourceSpans, 1, resource.finish());
|
|
2304
|
+
for (const ss of rs.scopeSpans) {
|
|
2305
|
+
const scopeSpans = new Writer();
|
|
2306
|
+
const scope = new Writer();
|
|
2307
|
+
stringField(scope, 1, ss.scope.name);
|
|
2308
|
+
stringField(scope, 2, ss.scope.version);
|
|
2309
|
+
lenField(scopeSpans, 1, scope.finish());
|
|
2310
|
+
for (const span of ss.spans) lenField(scopeSpans, 2, encodeSpan(span));
|
|
2311
|
+
lenField(resourceSpans, 2, scopeSpans.finish());
|
|
2312
|
+
}
|
|
2313
|
+
stringField(resourceSpans, 3, rs.schemaUrl);
|
|
2314
|
+
lenField(w, 1, resourceSpans.finish());
|
|
2315
|
+
}
|
|
2316
|
+
return w.finish();
|
|
2317
|
+
}
|
|
2318
|
+
var Reader = class {
|
|
2319
|
+
constructor(bytes) {
|
|
2320
|
+
this.bytes = bytes;
|
|
2321
|
+
this.pos = 0;
|
|
2322
|
+
}
|
|
2323
|
+
get done() {
|
|
2324
|
+
return this.pos >= this.bytes.length;
|
|
2325
|
+
}
|
|
2326
|
+
varint() {
|
|
2327
|
+
let result = 0n;
|
|
2328
|
+
let shift = 0n;
|
|
2329
|
+
for (; ; ) {
|
|
2330
|
+
if (this.pos >= this.bytes.length) throw new Error("truncated varint");
|
|
2331
|
+
const byte = this.bytes[this.pos++];
|
|
2332
|
+
result |= BigInt(byte & 127) << shift;
|
|
2333
|
+
if ((byte & 128) === 0) return result;
|
|
2334
|
+
shift += 7n;
|
|
2335
|
+
if (shift > 70n) throw new Error("varint too long");
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
slice(length) {
|
|
2339
|
+
if (this.pos + length > this.bytes.length) throw new Error("truncated field");
|
|
2340
|
+
const out = this.bytes.subarray(this.pos, this.pos + length);
|
|
2341
|
+
this.pos += length;
|
|
2342
|
+
return out;
|
|
2343
|
+
}
|
|
2344
|
+
skip(wire) {
|
|
2345
|
+
if (wire === WIRE_VARINT) this.varint();
|
|
2346
|
+
else if (wire === WIRE_FIXED64) this.slice(8);
|
|
2347
|
+
else if (wire === WIRE_FIXED32) this.slice(4);
|
|
2348
|
+
else if (wire === WIRE_LEN) this.slice(Number(this.varint()));
|
|
2349
|
+
else throw new Error(`unsupported wire type ${wire}`);
|
|
2350
|
+
}
|
|
2351
|
+
};
|
|
2352
|
+
function decodeExportTraceServiceResponse(bytes) {
|
|
2353
|
+
const top = new Reader(bytes);
|
|
2354
|
+
let result;
|
|
2355
|
+
while (!top.done) {
|
|
2356
|
+
const key = Number(top.varint());
|
|
2357
|
+
const field = key >>> 3;
|
|
2358
|
+
const wire = key & 7;
|
|
2359
|
+
if (field === 1 && wire === WIRE_LEN) {
|
|
2360
|
+
const inner = new Reader(top.slice(Number(top.varint())));
|
|
2361
|
+
let rejected = 0n;
|
|
2362
|
+
let message;
|
|
2363
|
+
while (!inner.done) {
|
|
2364
|
+
const innerKey = Number(inner.varint());
|
|
2365
|
+
const innerField = innerKey >>> 3;
|
|
2366
|
+
const innerWire = innerKey & 7;
|
|
2367
|
+
if (innerField === 1 && innerWire === WIRE_VARINT) rejected = BigInt.asIntN(64, inner.varint());
|
|
2368
|
+
else if (innerField === 2 && innerWire === WIRE_LEN) message = new TextDecoder().decode(inner.slice(Number(inner.varint())));
|
|
2369
|
+
else inner.skip(innerWire);
|
|
2370
|
+
}
|
|
2371
|
+
result = { rejectedSpans: Number(rejected), ...message ? { message } : {} };
|
|
2372
|
+
} else {
|
|
2373
|
+
top.skip(wire);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
return result;
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
// src/utils/otlp/exporter.ts
|
|
2380
|
+
var gzipAsync = util.promisify(zlib.gzip);
|
|
2381
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
2382
|
+
var RETRY_DEFAULTS = {
|
|
2383
|
+
maxAttempts: 3,
|
|
2384
|
+
initialDelayMs: 250,
|
|
2385
|
+
maxDelayMs: 4e3,
|
|
2386
|
+
maxElapsedMs: 25e3
|
|
2387
|
+
};
|
|
2388
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
2389
|
+
function retryPolicy(retry) {
|
|
2390
|
+
if (retry === false) return { ...RETRY_DEFAULTS, maxAttempts: 1 };
|
|
2391
|
+
const merged = { ...RETRY_DEFAULTS, ...retry ?? {} };
|
|
2392
|
+
return { ...merged, maxAttempts: Math.max(1, Math.floor(merged.maxAttempts)) };
|
|
2393
|
+
}
|
|
2394
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2395
|
+
function retryAfterMs(response) {
|
|
2396
|
+
let raw;
|
|
2397
|
+
try {
|
|
2398
|
+
raw = response?.headers?.get?.("retry-after");
|
|
2399
|
+
} catch {
|
|
2400
|
+
return void 0;
|
|
2401
|
+
}
|
|
2402
|
+
if (typeof raw !== "string" || raw.trim() === "") return void 0;
|
|
2403
|
+
const seconds = Number(raw);
|
|
2404
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
2405
|
+
const date = Date.parse(raw);
|
|
2406
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
2407
|
+
}
|
|
2408
|
+
async function attemptOnce(fetchFn, url, init, timeoutMs, protocol) {
|
|
2409
|
+
const controller = new AbortController();
|
|
2410
|
+
let timer;
|
|
2411
|
+
const timeout = new Promise((_, reject) => {
|
|
2412
|
+
timer = setTimeout(() => {
|
|
2413
|
+
controller.abort();
|
|
2414
|
+
reject(new Error(`timed out after ${timeoutMs} ms`));
|
|
2415
|
+
}, timeoutMs);
|
|
2416
|
+
});
|
|
2417
|
+
try {
|
|
2418
|
+
const pending = fetchFn(url, { ...init, signal: controller.signal });
|
|
2419
|
+
Promise.resolve(pending).catch(() => void 0);
|
|
2420
|
+
const response = await Promise.race([pending, timeout]);
|
|
2421
|
+
const status = typeof response?.status === "number" ? response.status : response?.ok ? 200 : 0;
|
|
2422
|
+
const ok = typeof response?.ok === "boolean" ? response.ok : status >= 200 && status < 300;
|
|
2423
|
+
if (ok) {
|
|
2424
|
+
const lateBody = timeout.catch(() => void 0);
|
|
2425
|
+
const partialSuccess = await Promise.race([readPartialSuccess(response, protocol), lateBody]);
|
|
2426
|
+
return { kind: "ok", status, ...partialSuccess ? { partialSuccess } : {} };
|
|
2427
|
+
}
|
|
2428
|
+
let body = "";
|
|
2429
|
+
try {
|
|
2430
|
+
if (typeof response?.text === "function") body = String(await response.text());
|
|
2431
|
+
} catch {
|
|
2432
|
+
}
|
|
2433
|
+
const statusText = typeof response?.statusText === "string" && response.statusText ? ` ${response.statusText}` : "";
|
|
2434
|
+
return {
|
|
2435
|
+
kind: "http",
|
|
2436
|
+
status,
|
|
2437
|
+
message: `HTTP ${status}${statusText}${body ? ` - ${body.slice(0, 200)}` : ""}`,
|
|
2438
|
+
retryable: RETRYABLE_STATUS.has(status),
|
|
2439
|
+
retryAfter: retryAfterMs(response)
|
|
2440
|
+
};
|
|
2441
|
+
} catch (err) {
|
|
2442
|
+
return { kind: "network", message: err instanceof Error ? err.message : String(err) };
|
|
2443
|
+
} finally {
|
|
2444
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
async function readPartialSuccess(response, protocol) {
|
|
2448
|
+
try {
|
|
2449
|
+
if (protocol === "http/protobuf") {
|
|
2450
|
+
if (typeof response?.arrayBuffer !== "function") return void 0;
|
|
2451
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
2452
|
+
if (bytes.length === 0) return void 0;
|
|
2453
|
+
const decoded = decodeExportTraceServiceResponse(bytes);
|
|
2454
|
+
return decoded && (decoded.rejectedSpans > 0 || decoded.message) ? decoded : void 0;
|
|
2455
|
+
}
|
|
2456
|
+
if (typeof response?.text !== "function") return void 0;
|
|
2457
|
+
const text = String(await response.text());
|
|
2458
|
+
if (!text.trim()) return void 0;
|
|
2459
|
+
const partial = JSON.parse(text)?.partialSuccess;
|
|
2460
|
+
if (!partial || typeof partial !== "object") return void 0;
|
|
2461
|
+
const rejectedSpans = Number(partial.rejectedSpans ?? 0);
|
|
2462
|
+
const message = typeof partial.errorMessage === "string" && partial.errorMessage ? partial.errorMessage : void 0;
|
|
2463
|
+
if (!(rejectedSpans > 0) && !message) return void 0;
|
|
2464
|
+
return { rejectedSpans: Number.isFinite(rejectedSpans) ? rejectedSpans : 0, ...message ? { message } : {} };
|
|
2465
|
+
} catch {
|
|
2466
|
+
return void 0;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
function createOtlpExporter(options = {}) {
|
|
2470
|
+
const env = resolveOtlpEnv(currentEnv(), options);
|
|
2471
|
+
if (!env.endpoint && !env.disabled) {
|
|
2472
|
+
throw new Error(
|
|
2473
|
+
"[agent-sdk] OTLP export needs an `endpoint` (or OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT in the environment)."
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2476
|
+
const semconv = options.semconv ?? "both";
|
|
2477
|
+
const protocol = env.protocol;
|
|
2478
|
+
const compression = env.compression;
|
|
2479
|
+
const timeoutMs = env.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2480
|
+
const policy = retryPolicy(options.retry);
|
|
2481
|
+
const serviceName = options.serviceName ?? env.serviceName;
|
|
2482
|
+
const resourceAttributes = { ...env.resourceAttributes, ...options.resourceAttributes ?? {} };
|
|
2483
|
+
const endpoint = env.endpoint ?? "";
|
|
2484
|
+
const content = resolveContentOptions(options.content);
|
|
2485
|
+
return {
|
|
2486
|
+
name: options.name ?? "otlp",
|
|
2487
|
+
endpoint,
|
|
2488
|
+
semconv,
|
|
2489
|
+
protocol,
|
|
2490
|
+
wantsContent: content.enabled,
|
|
2491
|
+
contentOptions: content,
|
|
2492
|
+
async exportSession(file, run) {
|
|
2493
|
+
try {
|
|
2494
|
+
if (env.disabled) {
|
|
2495
|
+
return { ok: true, skipped: true, reason: "disabled by the environment (OTEL_SDK_DISABLED / OTEL_TRACES_EXPORTER)", attempts: 0, spans: 0, bytes: 0 };
|
|
2496
|
+
}
|
|
2497
|
+
const convertOptions = {
|
|
2498
|
+
semconv,
|
|
2499
|
+
serviceName,
|
|
2500
|
+
resourceAttributes,
|
|
2501
|
+
terminal: run.terminal,
|
|
2502
|
+
cancelled: run.cancelled,
|
|
2503
|
+
parent: run.parent,
|
|
2504
|
+
content
|
|
2505
|
+
};
|
|
2506
|
+
const request = sessionToOtlp(file, convertOptions);
|
|
2507
|
+
const spans = countSpans(request);
|
|
2508
|
+
if (spans === 0) return { ok: true, skipped: true, reason: "no spans to export", attempts: 0, spans: 0, bytes: 0 };
|
|
2509
|
+
const fetchFn = options.fetch ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0);
|
|
2510
|
+
if (!fetchFn) return { ok: false, attempts: 0, spans, bytes: 0, error: "OTLP export requires fetch to be available in this runtime." };
|
|
2511
|
+
let body = protocol === "http/protobuf" ? encodeExportTraceServiceRequest(request) : JSON.stringify(request);
|
|
2512
|
+
const headers = {
|
|
2513
|
+
"content-type": protocol === "http/protobuf" ? "application/x-protobuf" : "application/json"
|
|
2514
|
+
};
|
|
2515
|
+
if (compression === "gzip") {
|
|
2516
|
+
body = await gzipAsync(typeof body === "string" ? buffer.Buffer.from(body, "utf8") : body);
|
|
2517
|
+
headers["content-encoding"] = "gzip";
|
|
2518
|
+
}
|
|
2519
|
+
Object.assign(headers, env.headers);
|
|
2520
|
+
const bytes = typeof body === "string" ? buffer.Buffer.byteLength(body, "utf8") : body.length;
|
|
2521
|
+
const started = Date.now();
|
|
2522
|
+
let attempts = 0;
|
|
2523
|
+
let lastError = "export failed";
|
|
2524
|
+
let lastStatus;
|
|
2525
|
+
for (; ; ) {
|
|
2526
|
+
attempts += 1;
|
|
2527
|
+
const remaining = policy.maxElapsedMs - (Date.now() - started);
|
|
2528
|
+
const outcome = await attemptOnce(
|
|
2529
|
+
fetchFn,
|
|
2530
|
+
env.endpoint,
|
|
2531
|
+
{ method: "POST", headers, body },
|
|
2532
|
+
Math.max(1, Math.min(timeoutMs, remaining)),
|
|
2533
|
+
protocol
|
|
2534
|
+
);
|
|
2535
|
+
if (outcome.kind === "ok") {
|
|
2536
|
+
return { ok: true, attempts, status: outcome.status, spans, bytes, ...outcome.partialSuccess ? { partialSuccess: outcome.partialSuccess } : {} };
|
|
2537
|
+
}
|
|
2538
|
+
lastError = outcome.message;
|
|
2539
|
+
lastStatus = outcome.kind === "http" ? outcome.status : void 0;
|
|
2540
|
+
const retryable = outcome.kind === "network" || outcome.retryable;
|
|
2541
|
+
if (!retryable || attempts >= policy.maxAttempts) break;
|
|
2542
|
+
const ceiling = Math.min(policy.maxDelayMs, policy.initialDelayMs * 2 ** (attempts - 1));
|
|
2543
|
+
const wait = outcome.kind === "http" && outcome.retryAfter !== void 0 ? Math.min(outcome.retryAfter, policy.maxDelayMs) : Math.random() * ceiling;
|
|
2544
|
+
if (Date.now() - started + wait >= policy.maxElapsedMs) break;
|
|
2545
|
+
await sleep(wait);
|
|
2546
|
+
}
|
|
2547
|
+
return { ok: false, attempts, ...lastStatus !== void 0 ? { status: lastStatus } : {}, spans, bytes, error: lastError };
|
|
2548
|
+
} catch (err) {
|
|
2549
|
+
return { ok: false, attempts: 0, spans: 0, bytes: 0, error: err instanceof Error ? err.message : String(err) };
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
};
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// src/utils/otlp/context.ts
|
|
2556
|
+
var TRACEPARENT = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/;
|
|
2557
|
+
var ALL_ZERO_TRACE = /^0{32}$/;
|
|
2558
|
+
var ALL_ZERO_SPAN = /^0{16}$/;
|
|
2559
|
+
var MAX_TRACESTATE = 512;
|
|
2560
|
+
function parseTraceparent(header) {
|
|
2561
|
+
if (typeof header !== "string") return void 0;
|
|
2562
|
+
const match = TRACEPARENT.exec(header.trim());
|
|
2563
|
+
if (!match) return void 0;
|
|
2564
|
+
const [, version, traceId, spanId, flagsHex, rest] = match;
|
|
2565
|
+
if (version === "ff") return void 0;
|
|
2566
|
+
if (version === "00" && rest) return void 0;
|
|
2567
|
+
if (ALL_ZERO_TRACE.test(traceId) || ALL_ZERO_SPAN.test(spanId)) return void 0;
|
|
2568
|
+
const flags = parseInt(flagsHex, 16);
|
|
2569
|
+
return { traceId, spanId, flags, sampled: (flags & 1) === 1 };
|
|
2570
|
+
}
|
|
2571
|
+
function formatTraceparent(parts) {
|
|
2572
|
+
const flags = typeof parts.flags === "number" ? parts.flags & 255 : parts.sampled === false ? 0 : 1;
|
|
2573
|
+
return `00-${parts.traceId}-${parts.spanId}-${flags.toString(16).padStart(2, "0")}`;
|
|
2574
|
+
}
|
|
2575
|
+
function traceparentOf(ctx) {
|
|
2576
|
+
if (!ctx?.traceId || !ctx.traceSpanId) return void 0;
|
|
2577
|
+
return formatTraceparent({ traceId: ctx.traceId, spanId: ctx.traceSpanId, flags: ctx.traceFlags ?? 1 });
|
|
2578
|
+
}
|
|
2579
|
+
function cleanTraceState(value) {
|
|
2580
|
+
if (typeof value !== "string") return void 0;
|
|
2581
|
+
const trimmed = value.trim();
|
|
2582
|
+
if (!trimmed || trimmed.length > MAX_TRACESTATE || !/^[\x20-\x7e]+$/.test(trimmed)) return void 0;
|
|
2583
|
+
return trimmed;
|
|
2584
|
+
}
|
|
2585
|
+
function resolveTraceParent(input) {
|
|
2586
|
+
if (input === void 0 || input === null) return void 0;
|
|
2587
|
+
const header = typeof input === "string" ? input : input?.traceparent;
|
|
2588
|
+
const parsed = parseTraceparent(header);
|
|
2589
|
+
if (!parsed) {
|
|
2590
|
+
warnOnce("[agent-sdk] Ignoring an invalid W3C traceparent; the trace starts a new root.");
|
|
2591
|
+
return void 0;
|
|
2592
|
+
}
|
|
2593
|
+
const traceState = typeof input === "object" ? cleanTraceState(input.tracestate) : void 0;
|
|
2594
|
+
return {
|
|
2595
|
+
traceId: parsed.traceId,
|
|
2596
|
+
spanId: parsed.spanId,
|
|
2597
|
+
flags: parsed.flags,
|
|
2598
|
+
sampled: parsed.sampled,
|
|
2599
|
+
remote: true,
|
|
2600
|
+
...traceState ? { traceState } : {}
|
|
2601
|
+
};
|
|
2602
|
+
}
|
|
2603
|
+
function persistedParentOf(parent) {
|
|
2604
|
+
if (!parent) return void 0;
|
|
2605
|
+
return { spanId: parent.spanId, flags: parent.flags, ...parent.traceState ? { traceState: parent.traceState } : {} };
|
|
2606
|
+
}
|
|
2607
|
+
function readPersistedParent(value) {
|
|
2608
|
+
if (!value || typeof value !== "object") return void 0;
|
|
2609
|
+
const raw = value;
|
|
2610
|
+
if (typeof raw.spanId !== "string" || !/^[0-9a-f]{16}$/.test(raw.spanId) || ALL_ZERO_SPAN.test(raw.spanId)) return void 0;
|
|
2611
|
+
const flags = Number(raw.flags);
|
|
2612
|
+
if (!Number.isInteger(flags) || flags < 0 || flags > 255) return void 0;
|
|
2613
|
+
const traceState = cleanTraceState(raw.traceState);
|
|
2614
|
+
return { spanId: raw.spanId, flags, ...traceState ? { traceState } : {} };
|
|
2615
|
+
}
|
|
2616
|
+
function restoreParent(persisted, traceId) {
|
|
2617
|
+
return {
|
|
2618
|
+
traceId,
|
|
2619
|
+
spanId: persisted.spanId,
|
|
2620
|
+
flags: persisted.flags,
|
|
2621
|
+
sampled: (persisted.flags & 1) === 1,
|
|
2622
|
+
remote: true,
|
|
2623
|
+
...persisted.traceState ? { traceState: persisted.traceState } : {}
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
// src/utils/tracing.ts
|
|
1237
2628
|
var DEFAULT_COGNIPEER_URL = "https://console.cognipeer.com/api/client/v1/tracing/sessions";
|
|
1238
2629
|
function fileSink(path2) {
|
|
1239
2630
|
return { type: "file", path: path2 };
|
|
@@ -1259,8 +2650,9 @@ function cognipeerSink(first, second) {
|
|
|
1259
2650
|
function httpSink(url, headers) {
|
|
1260
2651
|
return { type: "http", url, headers };
|
|
1261
2652
|
}
|
|
1262
|
-
function otlpSink(
|
|
1263
|
-
return { type: "otlp",
|
|
2653
|
+
function otlpSink(first, headers, options) {
|
|
2654
|
+
if (first !== null && typeof first === "object") return { type: "otlp", ...first };
|
|
2655
|
+
return { type: "otlp", endpoint: first, headers, ...options ?? {} };
|
|
1264
2656
|
}
|
|
1265
2657
|
function resolveLogsBaseDir(customPath, ensureDirectory = true) {
|
|
1266
2658
|
const root = process.cwd();
|
|
@@ -1333,23 +2725,23 @@ function extractMetadata(model, paths) {
|
|
|
1333
2725
|
if (!model) return void 0;
|
|
1334
2726
|
for (const path2 of paths) {
|
|
1335
2727
|
const value = getNestedValue2(model, path2);
|
|
1336
|
-
const
|
|
1337
|
-
if (
|
|
2728
|
+
const str2 = coerceToString(value);
|
|
2729
|
+
if (str2) return str2;
|
|
1338
2730
|
}
|
|
1339
2731
|
const maybeLc = model?._lc;
|
|
1340
2732
|
if (maybeLc) {
|
|
1341
2733
|
for (const path2 of paths) {
|
|
1342
2734
|
const value = getNestedValue2(maybeLc, path2);
|
|
1343
|
-
const
|
|
1344
|
-
if (
|
|
2735
|
+
const str2 = coerceToString(value);
|
|
2736
|
+
if (str2) return str2;
|
|
1345
2737
|
}
|
|
1346
2738
|
}
|
|
1347
2739
|
const maybeClient = model?.client || model?.api || model?.service;
|
|
1348
2740
|
if (maybeClient) {
|
|
1349
2741
|
for (const path2 of paths) {
|
|
1350
2742
|
const value = getNestedValue2(maybeClient, path2);
|
|
1351
|
-
const
|
|
1352
|
-
if (
|
|
2743
|
+
const str2 = coerceToString(value);
|
|
2744
|
+
if (str2) return str2;
|
|
1353
2745
|
}
|
|
1354
2746
|
}
|
|
1355
2747
|
const constructorName = model?.constructor?.name;
|
|
@@ -1380,8 +2772,8 @@ function inferModelFromMessages(messageList) {
|
|
|
1380
2772
|
if (!message) continue;
|
|
1381
2773
|
for (const path2 of messagePaths) {
|
|
1382
2774
|
const value = getNestedValue2(message, path2);
|
|
1383
|
-
const
|
|
1384
|
-
if (
|
|
2775
|
+
const str2 = coerceToString(value);
|
|
2776
|
+
if (str2) return str2;
|
|
1385
2777
|
}
|
|
1386
2778
|
}
|
|
1387
2779
|
return void 0;
|
|
@@ -1399,8 +2791,8 @@ function inferProviderFromMessages(messageList) {
|
|
|
1399
2791
|
if (!message) continue;
|
|
1400
2792
|
for (const path2 of messagePaths) {
|
|
1401
2793
|
const value = getNestedValue2(message, path2);
|
|
1402
|
-
const
|
|
1403
|
-
if (
|
|
2794
|
+
const str2 = coerceToString(value);
|
|
2795
|
+
if (str2) return str2;
|
|
1404
2796
|
}
|
|
1405
2797
|
}
|
|
1406
2798
|
return void 0;
|
|
@@ -1462,12 +2854,18 @@ function resolveSink(sink) {
|
|
|
1462
2854
|
return headers ? { type: "http", url, headers } : { type: "http", url };
|
|
1463
2855
|
}
|
|
1464
2856
|
case "otlp": {
|
|
1465
|
-
const
|
|
1466
|
-
if (
|
|
2857
|
+
const given = candidate.endpoint;
|
|
2858
|
+
if (given !== void 0 && (typeof given !== "string" || given.trim().length === 0)) {
|
|
2859
|
+
throw new Error("otlp sink requires a non-empty endpoint");
|
|
2860
|
+
}
|
|
2861
|
+
let exporter;
|
|
2862
|
+
try {
|
|
2863
|
+
exporter = createOtlpExporter({ ...candidate, endpoint: given?.trim() });
|
|
2864
|
+
} catch {
|
|
1467
2865
|
throw new Error("otlp sink requires a non-empty endpoint");
|
|
1468
2866
|
}
|
|
1469
2867
|
const headers = candidate.headers ? { ...candidate.headers } : void 0;
|
|
1470
|
-
return headers ? { type: "otlp", endpoint, headers } : { type: "otlp", endpoint };
|
|
2868
|
+
return headers ? { type: "otlp", endpoint: exporter.endpoint, headers, exporter } : { type: "otlp", endpoint: exporter.endpoint, exporter };
|
|
1471
2869
|
}
|
|
1472
2870
|
default: {
|
|
1473
2871
|
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
@@ -1477,6 +2875,17 @@ function resolveSink(sink) {
|
|
|
1477
2875
|
}
|
|
1478
2876
|
}
|
|
1479
2877
|
}
|
|
2878
|
+
function withoutUserinfo(endpoint) {
|
|
2879
|
+
try {
|
|
2880
|
+
const url = new URL(endpoint);
|
|
2881
|
+
if (!url.username && !url.password) return endpoint;
|
|
2882
|
+
url.username = "";
|
|
2883
|
+
url.password = "";
|
|
2884
|
+
return url.toString();
|
|
2885
|
+
} catch {
|
|
2886
|
+
return endpoint;
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
1480
2889
|
function snapshotSink(runtime) {
|
|
1481
2890
|
const sink = runtime.resolvedConfig.sink;
|
|
1482
2891
|
switch (sink.type) {
|
|
@@ -1489,7 +2898,7 @@ function snapshotSink(runtime) {
|
|
|
1489
2898
|
case "http":
|
|
1490
2899
|
return { type: "http", url: sink.url };
|
|
1491
2900
|
case "otlp":
|
|
1492
|
-
return { type: "otlp", endpoint: sink.endpoint };
|
|
2901
|
+
return { type: "otlp", endpoint: withoutUserinfo(sink.endpoint) };
|
|
1493
2902
|
default:
|
|
1494
2903
|
return { type: "custom" };
|
|
1495
2904
|
}
|
|
@@ -1507,11 +2916,11 @@ var TRACE_HTTP_RETRYABLE_STATUS = /* @__PURE__ */ new Set([404, 408, 425, 429, 5
|
|
|
1507
2916
|
var TRACE_HTTP_RETRY_BASE_MS = 250;
|
|
1508
2917
|
var TRACE_HTTP_RETRY_MAX_MS = 4e3;
|
|
1509
2918
|
var RetryableHttpError = class extends Error {
|
|
1510
|
-
constructor(status, message,
|
|
2919
|
+
constructor(status, message, retryAfterMs2) {
|
|
1511
2920
|
super(message);
|
|
1512
2921
|
this.name = "RetryableHttpError";
|
|
1513
2922
|
this.status = status;
|
|
1514
|
-
this.retryAfterMs =
|
|
2923
|
+
this.retryAfterMs = retryAfterMs2;
|
|
1515
2924
|
}
|
|
1516
2925
|
};
|
|
1517
2926
|
function traceSleep(ms) {
|
|
@@ -1604,206 +3013,23 @@ async function postStreamingSessionEnd(baseUrl, headers, payload) {
|
|
|
1604
3013
|
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/end`;
|
|
1605
3014
|
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1606
3015
|
}
|
|
1607
|
-
function
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
if (status === "success" || status === "completed") return 1;
|
|
1614
|
-
return 0;
|
|
1615
|
-
}
|
|
1616
|
-
function toOtlpSpanKind(type) {
|
|
1617
|
-
switch (type) {
|
|
1618
|
-
case "ai_call":
|
|
1619
|
-
case "summarization":
|
|
1620
|
-
return 3;
|
|
1621
|
-
// CLIENT — outgoing LLM request (the summarizer is one too)
|
|
1622
|
-
case "tool_call":
|
|
1623
|
-
return 1;
|
|
1624
|
-
// INTERNAL
|
|
1625
|
-
case "agent_iteration":
|
|
1626
|
-
return 1;
|
|
1627
|
-
// INTERNAL
|
|
1628
|
-
default:
|
|
1629
|
-
return 1;
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
function stringAttr(key, val) {
|
|
1633
|
-
return val != null ? { key, value: { stringValue: val } } : null;
|
|
1634
|
-
}
|
|
1635
|
-
function intAttr(key, val) {
|
|
1636
|
-
return val != null && !Number.isNaN(val) ? { key, value: { intValue: String(val) } } : null;
|
|
1637
|
-
}
|
|
1638
|
-
function doubleAttr(key, val) {
|
|
1639
|
-
return val != null && !Number.isNaN(val) ? { key, value: { doubleValue: val } } : null;
|
|
1640
|
-
}
|
|
1641
|
-
function eventToOtlpSpan(event) {
|
|
1642
|
-
const startNano = isoToUnixNano(event.timestamp);
|
|
1643
|
-
const endNano = event.durationMs != null ? `${new Date(new Date(event.timestamp).getTime() + event.durationMs).getTime()}000000` : startNano;
|
|
1644
|
-
const attrs = [
|
|
1645
|
-
stringAttr("cognipeer.event.type", event.type),
|
|
1646
|
-
stringAttr("cognipeer.event.label", event.label),
|
|
1647
|
-
intAttr("cognipeer.event.sequence", event.sequence),
|
|
1648
|
-
stringAttr("cognipeer.actor.scope", event.actor?.scope),
|
|
1649
|
-
stringAttr("cognipeer.actor.name", event.actor?.name),
|
|
1650
|
-
stringAttr("cognipeer.actor.role", event.actor?.role),
|
|
1651
|
-
stringAttr("cognipeer.model", event.model),
|
|
1652
|
-
intAttr("cognipeer.tokens.reasoning", event.reasoningTokens),
|
|
1653
|
-
stringAttr("cognipeer.finish_reason", event.finishReason),
|
|
1654
|
-
stringAttr("cognipeer.provider", event.provider),
|
|
1655
|
-
stringAttr("cognipeer.tool.details", event.toolDetails ? JSON.stringify(event.toolDetails) : void 0),
|
|
1656
|
-
intAttr("cognipeer.tokens.input", event.inputTokens),
|
|
1657
|
-
intAttr("cognipeer.tokens.output", event.outputTokens),
|
|
1658
|
-
intAttr("cognipeer.tokens.total", event.totalTokens),
|
|
1659
|
-
intAttr("cognipeer.tokens.cached_input", event.cachedInputTokens),
|
|
1660
|
-
intAttr("cognipeer.bytes.request", event.requestBytes),
|
|
1661
|
-
intAttr("cognipeer.bytes.response", event.responseBytes),
|
|
1662
|
-
stringAttr("cognipeer.tool.execution_id", event.toolExecutionId),
|
|
1663
|
-
stringAttr("cognipeer.retry_of", event.retryOf),
|
|
1664
|
-
stringAttr("cognipeer.event.id", event.id)
|
|
1665
|
-
].filter(Boolean);
|
|
1666
|
-
if (event.data?.sections && event.data.sections.length > 0) {
|
|
1667
|
-
try {
|
|
1668
|
-
attrs.push({ key: "cognipeer.sections", value: { stringValue: JSON.stringify(event.data.sections) } });
|
|
1669
|
-
} catch {
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
const span = {
|
|
1673
|
-
traceId: event.traceId,
|
|
1674
|
-
spanId: event.spanId,
|
|
1675
|
-
parentSpanId: event.parentSpanId || "",
|
|
1676
|
-
name: event.label || event.type,
|
|
1677
|
-
kind: toOtlpSpanKind(event.type),
|
|
1678
|
-
startTimeUnixNano: startNano,
|
|
1679
|
-
endTimeUnixNano: endNano,
|
|
1680
|
-
attributes: attrs,
|
|
1681
|
-
status: {
|
|
1682
|
-
code: toOtlpStatusCode(event.status),
|
|
1683
|
-
...event.status === "error" && event.error?.message ? { message: event.error.message } : {}
|
|
1684
|
-
}
|
|
1685
|
-
};
|
|
1686
|
-
if (event.error) {
|
|
1687
|
-
span.events = [{
|
|
1688
|
-
timeUnixNano: startNano,
|
|
1689
|
-
name: "exception",
|
|
1690
|
-
attributes: [
|
|
1691
|
-
{ key: "exception.message", value: { stringValue: event.error.message } },
|
|
1692
|
-
...event.error.stack ? [{ key: "exception.stacktrace", value: { stringValue: event.error.stack } }] : []
|
|
1693
|
-
]
|
|
1694
|
-
}];
|
|
1695
|
-
}
|
|
1696
|
-
return span;
|
|
1697
|
-
}
|
|
1698
|
-
function traceSessionToOtlp(session) {
|
|
1699
|
-
const traceId = session.traceId || generateTraceId();
|
|
1700
|
-
const rootSpanId = session.rootSpanId || generateSpanId();
|
|
1701
|
-
const startNano = isoToUnixNano(session.startedAt);
|
|
1702
|
-
const endNano = session.endedAt ? isoToUnixNano(session.endedAt) : startNano;
|
|
1703
|
-
const resourceAttrs = [
|
|
1704
|
-
{ key: "service.name", value: { stringValue: session.agent?.name || "cognipeer-agent" } },
|
|
1705
|
-
stringAttr("service.version", session.agent?.version),
|
|
1706
|
-
stringAttr("cognipeer.session.id", session.sessionId),
|
|
1707
|
-
stringAttr("cognipeer.thread.id", session.threadId),
|
|
1708
|
-
stringAttr("cognipeer.agent.model", session.agent?.model),
|
|
1709
|
-
stringAttr("cognipeer.agent.provider", session.agent?.provider),
|
|
1710
|
-
...Object.entries(session.metadata || {}).map(([key, value]) => stringAttr(`cognipeer.metadata.${key}`, value))
|
|
1711
|
-
].filter(Boolean);
|
|
1712
|
-
const rootAttrs = [
|
|
1713
|
-
stringAttr("cognipeer.session.status", session.status),
|
|
1714
|
-
doubleAttr("cognipeer.session.duration_ms", session.durationMs),
|
|
1715
|
-
intAttr("cognipeer.session.total_input_tokens", session.summary.totalInputTokens),
|
|
1716
|
-
intAttr("cognipeer.session.total_output_tokens", session.summary.totalOutputTokens),
|
|
1717
|
-
intAttr("cognipeer.session.total_cached_input_tokens", session.summary.totalCachedInputTokens),
|
|
1718
|
-
intAttr("cognipeer.session.total_bytes_in", session.summary.totalBytesIn),
|
|
1719
|
-
intAttr("cognipeer.session.total_bytes_out", session.summary.totalBytesOut),
|
|
1720
|
-
intAttr("cognipeer.session.event_count", session.events.length)
|
|
1721
|
-
].filter(Boolean);
|
|
1722
|
-
if (session.summary.eventCounts) {
|
|
1723
|
-
for (const [key, count] of Object.entries(session.summary.eventCounts)) {
|
|
1724
|
-
rootAttrs.push({ key: `cognipeer.session.event_count.${key}`, value: { intValue: String(count) } });
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
const rootSpan = {
|
|
1728
|
-
traceId,
|
|
1729
|
-
spanId: rootSpanId,
|
|
1730
|
-
parentSpanId: "",
|
|
1731
|
-
name: `agent_session: ${session.agent?.name || "agent"}`,
|
|
1732
|
-
kind: 1,
|
|
1733
|
-
// INTERNAL
|
|
1734
|
-
startTimeUnixNano: startNano,
|
|
1735
|
-
endTimeUnixNano: endNano,
|
|
1736
|
-
attributes: rootAttrs,
|
|
1737
|
-
status: {
|
|
1738
|
-
code: toOtlpStatusCode(session.status),
|
|
1739
|
-
...session.status === "error" && session.errors.length > 0 ? { message: session.errors.map((e) => e.message).join("; ") } : {}
|
|
1740
|
-
}
|
|
1741
|
-
};
|
|
1742
|
-
if (session.errors.length > 0) {
|
|
1743
|
-
rootSpan.events = session.errors.map((err) => ({
|
|
1744
|
-
timeUnixNano: err.timestamp ? isoToUnixNano(err.timestamp) : startNano,
|
|
1745
|
-
name: "exception",
|
|
1746
|
-
attributes: [
|
|
1747
|
-
{ key: "exception.message", value: { stringValue: err.message } },
|
|
1748
|
-
...err.stack ? [{ key: "exception.stacktrace", value: { stringValue: err.stack } }] : [],
|
|
1749
|
-
...err.type ? [{ key: "exception.type", value: { stringValue: err.type } }] : []
|
|
1750
|
-
]
|
|
1751
|
-
}));
|
|
1752
|
-
}
|
|
1753
|
-
const childSpans = session.events.map((event) => {
|
|
1754
|
-
const span = eventToOtlpSpan({
|
|
1755
|
-
...event,
|
|
1756
|
-
traceId: event.traceId || traceId,
|
|
1757
|
-
spanId: event.spanId || generateSpanId(),
|
|
1758
|
-
parentSpanId: event.parentSpanId || rootSpanId
|
|
1759
|
-
});
|
|
1760
|
-
return span;
|
|
3016
|
+
function traceSessionToOtlp(session, options = {}) {
|
|
3017
|
+
return sessionToOtlp(session, {
|
|
3018
|
+
semconv: "both",
|
|
3019
|
+
terminal: session.status !== "paused" && session.status !== "in_progress",
|
|
3020
|
+
...options,
|
|
3021
|
+
content: resolveContentOptions(options.content)
|
|
1761
3022
|
});
|
|
1762
|
-
return {
|
|
1763
|
-
resourceSpans: [{
|
|
1764
|
-
resource: { attributes: resourceAttrs },
|
|
1765
|
-
scopeSpans: [{
|
|
1766
|
-
scope: {
|
|
1767
|
-
name: "cognipeer-agent-sdk",
|
|
1768
|
-
version: "1.0.0"
|
|
1769
|
-
},
|
|
1770
|
-
spans: [rootSpan, ...childSpans]
|
|
1771
|
-
}]
|
|
1772
|
-
}]
|
|
1773
|
-
};
|
|
1774
3023
|
}
|
|
1775
|
-
|
|
1776
|
-
const
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
"
|
|
1782
|
-
...
|
|
3024
|
+
function traceErrorOf(err) {
|
|
3025
|
+
const e = err;
|
|
3026
|
+
const message = typeof e?.message === "string" && e.message ? e.message : String(err);
|
|
3027
|
+
const type = err instanceof Error && typeof err.name === "string" && err.name ? err.name : void 0;
|
|
3028
|
+
return {
|
|
3029
|
+
message,
|
|
3030
|
+
...typeof e?.stack === "string" ? { stack: e.stack } : {},
|
|
3031
|
+
...type ? { type } : {}
|
|
1783
3032
|
};
|
|
1784
|
-
try {
|
|
1785
|
-
const response = await fetchFn(endpoint, {
|
|
1786
|
-
method: "POST",
|
|
1787
|
-
headers: finalHeaders,
|
|
1788
|
-
body: JSON.stringify(payload)
|
|
1789
|
-
});
|
|
1790
|
-
if (!response.ok) {
|
|
1791
|
-
let responseText = "";
|
|
1792
|
-
try {
|
|
1793
|
-
responseText = await response.text();
|
|
1794
|
-
} catch {
|
|
1795
|
-
}
|
|
1796
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1797
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1798
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1799
|
-
}
|
|
1800
|
-
} catch (err) {
|
|
1801
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1802
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1803
|
-
console.error("[Tracing] OTLP export failed:", errMsg);
|
|
1804
|
-
}
|
|
1805
|
-
throw err;
|
|
1806
|
-
}
|
|
1807
3033
|
}
|
|
1808
3034
|
function createEmptySummary() {
|
|
1809
3035
|
return {
|
|
@@ -1823,10 +3049,16 @@ function generateEventId(sequence) {
|
|
|
1823
3049
|
return `evt_${String(sequence).padStart(4, "0")}_${nanoid.nanoid(4)}`;
|
|
1824
3050
|
}
|
|
1825
3051
|
function generateTraceId() {
|
|
1826
|
-
|
|
3052
|
+
for (; ; ) {
|
|
3053
|
+
const id = crypto__default.default.randomBytes(16).toString("hex");
|
|
3054
|
+
if (/[1-9a-f]/.test(id)) return id;
|
|
3055
|
+
}
|
|
1827
3056
|
}
|
|
1828
3057
|
function generateSpanId() {
|
|
1829
|
-
|
|
3058
|
+
for (; ; ) {
|
|
3059
|
+
const id = crypto__default.default.randomBytes(8).toString("hex");
|
|
3060
|
+
if (/[1-9a-f]/.test(id)) return id;
|
|
3061
|
+
}
|
|
1830
3062
|
}
|
|
1831
3063
|
function defaultEventLabel(type) {
|
|
1832
3064
|
switch (type) {
|
|
@@ -2103,9 +3335,64 @@ function readTraceContinuation(value) {
|
|
|
2103
3335
|
nextSequence,
|
|
2104
3336
|
part,
|
|
2105
3337
|
summary,
|
|
2106
|
-
errors: Array.isArray(raw.errors) ? raw.errors : []
|
|
3338
|
+
errors: Array.isArray(raw.errors) ? raw.errors : [],
|
|
3339
|
+
...(() => {
|
|
3340
|
+
const parent = readPersistedParent(raw.parent);
|
|
3341
|
+
return parent ? { parent } : {};
|
|
3342
|
+
})(),
|
|
3343
|
+
...(() => {
|
|
3344
|
+
const pendingSpans = readPendingSpans(raw.pendingSpans);
|
|
3345
|
+
return pendingSpans.length > 0 ? { pendingSpans } : {};
|
|
3346
|
+
})()
|
|
2107
3347
|
};
|
|
2108
3348
|
}
|
|
3349
|
+
var MAX_CARRIED_SPANS = 64;
|
|
3350
|
+
var isSubagentSpanRecord = (event) => event.type === "span" && event.actor?.role === "subagent";
|
|
3351
|
+
function carriedSpanOf(record) {
|
|
3352
|
+
const identity2 = (record.data?.sections ?? []).filter(
|
|
3353
|
+
(section) => section.kind === "metadata" && section.identity === true
|
|
3354
|
+
);
|
|
3355
|
+
return {
|
|
3356
|
+
sessionId: record.sessionId,
|
|
3357
|
+
traceId: record.traceId,
|
|
3358
|
+
spanId: record.spanId,
|
|
3359
|
+
parentSpanId: record.parentSpanId,
|
|
3360
|
+
id: record.id,
|
|
3361
|
+
type: record.type,
|
|
3362
|
+
label: record.label,
|
|
3363
|
+
sequence: record.sequence,
|
|
3364
|
+
timestamp: record.timestamp,
|
|
3365
|
+
actor: record.actor,
|
|
3366
|
+
status: record.status,
|
|
3367
|
+
durationMs: record.durationMs,
|
|
3368
|
+
...identity2.length > 0 ? { data: { sections: identity2 } } : {}
|
|
3369
|
+
};
|
|
3370
|
+
}
|
|
3371
|
+
function readPendingSpans(value) {
|
|
3372
|
+
if (!Array.isArray(value)) return [];
|
|
3373
|
+
const out = [];
|
|
3374
|
+
for (const item of value.slice(0, MAX_CARRIED_SPANS)) {
|
|
3375
|
+
if (!item || typeof item !== "object") continue;
|
|
3376
|
+
const raw = item;
|
|
3377
|
+
if (typeof raw.spanId !== "string" || raw.spanId.length === 0) continue;
|
|
3378
|
+
if (raw.status !== "pending" || !isSubagentSpanRecord(raw)) continue;
|
|
3379
|
+
if (typeof raw.sequence !== "number" || !Number.isInteger(raw.sequence) || raw.sequence < 1) continue;
|
|
3380
|
+
if (typeof raw.timestamp !== "string" || Number.isNaN(Date.parse(raw.timestamp))) continue;
|
|
3381
|
+
if (typeof raw.label !== "string" || typeof raw.id !== "string" || typeof raw.sessionId !== "string") continue;
|
|
3382
|
+
if (raw.parentSpanId !== void 0 && typeof raw.parentSpanId !== "string") continue;
|
|
3383
|
+
if (raw.durationMs !== void 0 && (typeof raw.durationMs !== "number" || !Number.isFinite(raw.durationMs))) continue;
|
|
3384
|
+
out.push(carriedSpanOf(raw));
|
|
3385
|
+
}
|
|
3386
|
+
return out;
|
|
3387
|
+
}
|
|
3388
|
+
function pendingSpansOf(session) {
|
|
3389
|
+
const candidates = [
|
|
3390
|
+
...session.carriedSpans ?? [],
|
|
3391
|
+
...session.events.filter(isSubagentSpanRecord)
|
|
3392
|
+
];
|
|
3393
|
+
if (candidates.length === 0) return [];
|
|
3394
|
+
return foldSupersededSpans(candidates).filter((event) => event.status === "pending").slice(-MAX_CARRIED_SPANS).map(carriedSpanOf);
|
|
3395
|
+
}
|
|
2109
3396
|
function traceContinuationOf(session) {
|
|
2110
3397
|
return {
|
|
2111
3398
|
v: 1,
|
|
@@ -2119,15 +3406,32 @@ function traceContinuationOf(session) {
|
|
|
2119
3406
|
summary: JSON.parse(JSON.stringify(session.summary)),
|
|
2120
3407
|
// Sink failures belong to the part that hit them; carrying them on would
|
|
2121
3408
|
// mark every later part `partial`.
|
|
2122
|
-
errors: session.errors.filter((error) => error.type !== "sink")
|
|
3409
|
+
errors: session.errors.filter((error) => error.type !== "sink"),
|
|
3410
|
+
// Where the root hangs, so the leg that ends the run exports it under the same remote parent.
|
|
3411
|
+
...session.parent ? { parent: persistedParentOf(session.parent) } : {},
|
|
3412
|
+
...(() => {
|
|
3413
|
+
const pendingSpans = pendingSpansOf(session);
|
|
3414
|
+
return pendingSpans.length > 0 ? { pendingSpans } : {};
|
|
3415
|
+
})()
|
|
2123
3416
|
};
|
|
2124
3417
|
}
|
|
2125
|
-
function createTraceSession(opts, continuation) {
|
|
3418
|
+
function createTraceSession(opts, continuation, extras) {
|
|
2126
3419
|
const cfg = withDefaults(opts.tracing);
|
|
2127
3420
|
if (!cfg.enabled) return void 0;
|
|
3421
|
+
let parent;
|
|
3422
|
+
if (continuation) {
|
|
3423
|
+
if (continuation.parent && continuation.traceId) parent = restoreParent(continuation.parent, continuation.traceId);
|
|
3424
|
+
} else {
|
|
3425
|
+
parent = resolveTraceParent(extras?.traceParent ?? opts.tracing?.parent);
|
|
3426
|
+
}
|
|
3427
|
+
const exporters = [...extras?.exporters ?? []];
|
|
3428
|
+
const contentExporters = [
|
|
3429
|
+
...cfg.sink.type === "otlp" ? [cfg.sink.exporter] : [],
|
|
3430
|
+
...exporters
|
|
3431
|
+
].filter((exporter) => exporter.wantsContent);
|
|
2128
3432
|
const providedSessionId = opts.tracing?.sessionId?.trim();
|
|
2129
3433
|
const sessionId = continuation?.sessionId || providedSessionId || generateSessionId();
|
|
2130
|
-
const traceId = continuation?.traceId || generateTraceId();
|
|
3434
|
+
const traceId = continuation?.traceId || parent?.traceId || generateTraceId();
|
|
2131
3435
|
const rootSpanId = continuation?.rootSpanId || generateSpanId();
|
|
2132
3436
|
const runtime = {
|
|
2133
3437
|
sessionId,
|
|
@@ -2146,7 +3450,20 @@ function createTraceSession(opts, continuation) {
|
|
|
2146
3450
|
// again would reset a streaming receiver's copy.
|
|
2147
3451
|
sessionStarted: Boolean(continuation),
|
|
2148
3452
|
sequenceOffset: continuation ? continuation.nextSequence - 1 : 0,
|
|
2149
|
-
part: continuation ? continuation.part + 1 : 1
|
|
3453
|
+
part: continuation ? continuation.part + 1 : 1,
|
|
3454
|
+
...continuation?.pendingSpans?.length ? { carriedSpans: continuation.pendingSpans } : {},
|
|
3455
|
+
...exporters.length ? { exporters } : {},
|
|
3456
|
+
exportReports: [],
|
|
3457
|
+
...parent ? { parent } : {},
|
|
3458
|
+
...contentExporters.length > 0 ? {
|
|
3459
|
+
captureContent: true,
|
|
3460
|
+
captureLimits: {
|
|
3461
|
+
// Headroom over the export cap: a redact hook runs before the cap and must see a
|
|
3462
|
+
// secret whole, even one that straddles the point where the export cuts.
|
|
3463
|
+
maxStringChars: 4 * Math.max(...contentExporters.map((exporter) => exporter.contentOptions?.maxStringChars ?? 4096)),
|
|
3464
|
+
maxMessages: Math.max(...contentExporters.map((exporter) => exporter.contentOptions?.maxMessages ?? 32))
|
|
3465
|
+
}
|
|
3466
|
+
} : {}
|
|
2150
3467
|
};
|
|
2151
3468
|
if (cfg.sink.type === "file") {
|
|
2152
3469
|
const baseDir = cfg.sink.baseDir;
|
|
@@ -2213,7 +3530,7 @@ function recordTraceEvent(session, event) {
|
|
|
2213
3530
|
const baseLabel = event.label?.trim().length ? event.label.trim() : defaultEventLabel(event.type);
|
|
2214
3531
|
const eventLabel = `${baseLabel} #${sequence}`;
|
|
2215
3532
|
const durationMs = event.durationMs !== void 0 ? Number(event.durationMs) : void 0;
|
|
2216
|
-
if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0) {
|
|
3533
|
+
if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0 && event.countDuration !== false && !isSubagentTraceScope(session)) {
|
|
2217
3534
|
session.summary.totalDurationMs += durationMs;
|
|
2218
3535
|
}
|
|
2219
3536
|
const inputTokens = event.inputTokens !== void 0 ? Number(event.inputTokens) : void 0;
|
|
@@ -2262,10 +3579,20 @@ function recordTraceEvent(session, event) {
|
|
|
2262
3579
|
}
|
|
2263
3580
|
}
|
|
2264
3581
|
}
|
|
3582
|
+
if (!session.resolvedConfig.logData && event.sections?.length) {
|
|
3583
|
+
const identity2 = event.sections.filter((section) => section.kind === "metadata" && section.identity === true);
|
|
3584
|
+
if (identity2.length > 0) sections = ensureUniqueSections(id, identity2);
|
|
3585
|
+
}
|
|
3586
|
+
if (event.alwaysSections?.length) {
|
|
3587
|
+
const identity2 = event.alwaysSections.map(
|
|
3588
|
+
(section) => section.kind === "metadata" ? { ...section, identity: true } : section
|
|
3589
|
+
);
|
|
3590
|
+
sections = ensureUniqueSections(id, [...identity2, ...sections ?? []]);
|
|
3591
|
+
}
|
|
2265
3592
|
const resolvedModel = event.model ?? inferModelFromMessages(event.messageList);
|
|
2266
3593
|
const resolvedProvider = event.provider ?? inferProviderFromMessages(event.messageList);
|
|
2267
3594
|
const isAiCall = event.type === "ai_call";
|
|
2268
|
-
const spanId = generateSpanId();
|
|
3595
|
+
const spanId = event.spanId || generateSpanId();
|
|
2269
3596
|
const parentSpanId = event.parentSpanId || session.currentIterationSpanId || session.rootSpanId;
|
|
2270
3597
|
const record = {
|
|
2271
3598
|
sessionId: session.sessionId,
|
|
@@ -2296,6 +3623,16 @@ function recordTraceEvent(session, event) {
|
|
|
2296
3623
|
// different facts, and a zero would erase the difference.
|
|
2297
3624
|
...reasoningTokens !== void 0 && !Number.isNaN(reasoningTokens) ? { reasoningTokens } : {},
|
|
2298
3625
|
...event.finishReason ? { finishReason: event.finishReason } : {},
|
|
3626
|
+
// Provider facts: absent when the provider did not say, never zero or empty.
|
|
3627
|
+
...event.responseId ? { responseId: event.responseId } : {},
|
|
3628
|
+
...event.responseModel ? { responseModel: event.responseModel } : {},
|
|
3629
|
+
...event.rawFinishReason ? { rawFinishReason: event.rawFinishReason } : {},
|
|
3630
|
+
...typeof event.cacheWriteTokens === "number" && event.cacheWriteTokens > 0 ? { cacheWriteTokens: event.cacheWriteTokens } : {},
|
|
3631
|
+
...event.usageBasis && (event.usageBasis.inputExcludesCache || event.usageBasis.outputExcludesReasoning) ? { usageBasis: { ...event.usageBasis } } : {},
|
|
3632
|
+
...event.streaming ? { streaming: true } : {},
|
|
3633
|
+
...event.outputType ? { outputType: event.outputType } : {},
|
|
3634
|
+
...event.toolCallId ? { toolCallId: event.toolCallId } : {},
|
|
3635
|
+
...event.skipReason ? { skipReason: event.skipReason } : {},
|
|
2299
3636
|
requestBytes,
|
|
2300
3637
|
responseBytes,
|
|
2301
3638
|
model: resolvedModel,
|
|
@@ -2317,6 +3654,15 @@ function recordTraceEvent(session, event) {
|
|
|
2317
3654
|
timestamp: timestampIso
|
|
2318
3655
|
});
|
|
2319
3656
|
}
|
|
3657
|
+
if (session.captureContent && event.capture) {
|
|
3658
|
+
try {
|
|
3659
|
+
attachCapturedContent(
|
|
3660
|
+
record,
|
|
3661
|
+
buildCapturedContent(event.capture, session.captureLimits ?? { maxStringChars: 4096, maxMessages: 32 })
|
|
3662
|
+
);
|
|
3663
|
+
} catch {
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
2320
3666
|
session.events.push(record);
|
|
2321
3667
|
const sink = session.resolvedConfig.sink;
|
|
2322
3668
|
if (sink.type === "custom" && typeof sink.onEvent === "function") {
|
|
@@ -2359,6 +3705,69 @@ var DEFERRED_TRACE_EVENTS_KEY = "__deferredTraceEvents";
|
|
|
2359
3705
|
function isTraceSessionOpen(session) {
|
|
2360
3706
|
return Boolean(session) && !session.closed;
|
|
2361
3707
|
}
|
|
3708
|
+
var SUBAGENT_TRACE_SCOPE = Symbol("subagentTraceScope");
|
|
3709
|
+
function createSubagentTraceScope(parent, info) {
|
|
3710
|
+
const scope = { ...info, iterations: info.iterations ?? 0 };
|
|
3711
|
+
let currentIterationSpanId;
|
|
3712
|
+
return new Proxy(parent, {
|
|
3713
|
+
get(target, prop) {
|
|
3714
|
+
if (prop === SUBAGENT_TRACE_SCOPE) return scope;
|
|
3715
|
+
if (prop === "rootSpanId") return scope.agentSpanId;
|
|
3716
|
+
if (prop === "currentIterationSpanId") return currentIterationSpanId;
|
|
3717
|
+
return Reflect.get(target, prop);
|
|
3718
|
+
},
|
|
3719
|
+
set(target, prop, value) {
|
|
3720
|
+
if (prop === "currentIterationSpanId") {
|
|
3721
|
+
currentIterationSpanId = value;
|
|
3722
|
+
return true;
|
|
3723
|
+
}
|
|
3724
|
+
return Reflect.set(target, prop, value);
|
|
3725
|
+
}
|
|
3726
|
+
});
|
|
3727
|
+
}
|
|
3728
|
+
function subagentTraceScopeOf(session) {
|
|
3729
|
+
if (!session) return void 0;
|
|
3730
|
+
return session[SUBAGENT_TRACE_SCOPE];
|
|
3731
|
+
}
|
|
3732
|
+
function canPauseForHuman(session) {
|
|
3733
|
+
return subagentTraceScopeOf(session)?.hitl !== false;
|
|
3734
|
+
}
|
|
3735
|
+
function isSubagentTraceScope(session) {
|
|
3736
|
+
return subagentTraceScopeOf(session) !== void 0;
|
|
3737
|
+
}
|
|
3738
|
+
function recordSubagentSpan(session, span) {
|
|
3739
|
+
const sections = [];
|
|
3740
|
+
if (session.resolvedConfig.logData) {
|
|
3741
|
+
if (span.task !== void 0) sections.push({ kind: "message", label: "Task", role: "user", content: span.task });
|
|
3742
|
+
if (span.result) sections.push({ kind: "message", label: "Result", role: "assistant", content: span.result });
|
|
3743
|
+
}
|
|
3744
|
+
recordTraceEvent(session, {
|
|
3745
|
+
type: "span",
|
|
3746
|
+
spanId: span.spanId,
|
|
3747
|
+
parentSpanId: span.parentSpanId,
|
|
3748
|
+
label: `Sub-agent ${span.name}`,
|
|
3749
|
+
actor: { scope: "agent", name: span.name, role: "subagent" },
|
|
3750
|
+
status: span.status,
|
|
3751
|
+
durationMs: span.durationMs,
|
|
3752
|
+
// The child's own calls and the delegating tool_call already hold this time.
|
|
3753
|
+
countDuration: false,
|
|
3754
|
+
...span.error ? { error: { message: span.error } } : {},
|
|
3755
|
+
// The Console reads which sub-agent ran from here, so it survives logData off.
|
|
3756
|
+
alwaysSections: [{ kind: "metadata", label: "Sub-agent", data: sanitizeTracePayload(span.info) }],
|
|
3757
|
+
sections
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
function foldSupersededSpans(events) {
|
|
3761
|
+
const rank = (event, index) => typeof event.sequence === "number" && Number.isFinite(event.sequence) ? event.sequence : index;
|
|
3762
|
+
const winner = /* @__PURE__ */ new Map();
|
|
3763
|
+
for (let i = 0; i < events.length; i++) {
|
|
3764
|
+
const id = events[i].spanId;
|
|
3765
|
+
if (!id) continue;
|
|
3766
|
+
const current = winner.get(id);
|
|
3767
|
+
if (current === void 0 || rank(events[i], i) >= rank(events[current], current)) winner.set(id, i);
|
|
3768
|
+
}
|
|
3769
|
+
return events.filter((event, i) => !(event.spanId && event.status === "pending" && winner.get(event.spanId) !== i));
|
|
3770
|
+
}
|
|
2362
3771
|
function recordOrDeferTraceEvent(ctx, event, options) {
|
|
2363
3772
|
const session = ctx?.__traceSession;
|
|
2364
3773
|
if (isTraceSessionOpen(session)) {
|
|
@@ -2369,7 +3778,8 @@ function recordOrDeferTraceEvent(ctx, event, options) {
|
|
|
2369
3778
|
const held = Array.isArray(ctx?.[DEFERRED_TRACE_EVENTS_KEY]) ? ctx[DEFERRED_TRACE_EVENTS_KEY] : [];
|
|
2370
3779
|
return {
|
|
2371
3780
|
...ctx || {},
|
|
2372
|
-
|
|
3781
|
+
// `capture` (content for exporters) is never parked on ctx, which callers persist.
|
|
3782
|
+
[DEFERRED_TRACE_EVENTS_KEY]: [...held, { ...event, capture: void 0, timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString() }]
|
|
2373
3783
|
};
|
|
2374
3784
|
}
|
|
2375
3785
|
function replayDeferredTraceEvents(session, deferred) {
|
|
@@ -2403,6 +3813,7 @@ async function finalizeTraceSession(session, params = {}) {
|
|
|
2403
3813
|
message: params.error.message || "Unknown error",
|
|
2404
3814
|
stack: params.error.stack,
|
|
2405
3815
|
type: "session",
|
|
3816
|
+
...params.error.name ? { errorName: params.error.name } : {},
|
|
2406
3817
|
timestamp: endedAtIso
|
|
2407
3818
|
});
|
|
2408
3819
|
}
|
|
@@ -2426,24 +3837,62 @@ async function finalizeTraceSession(session, params = {}) {
|
|
|
2426
3837
|
...(session.part ?? 1) > 1 ? { continuation: { part: session.part, firstSequence: (session.sequenceOffset ?? 0) + 1 } } : {}
|
|
2427
3838
|
});
|
|
2428
3839
|
const payloadForSink = buildPayload(initialStatus);
|
|
3840
|
+
const carried = session.carriedSpans ?? [];
|
|
3841
|
+
const exportPayload = carried.length > 0 ? { ...payloadForSink, events: [...carried, ...payloadForSink.events] } : payloadForSink;
|
|
2429
3842
|
let sinkFailed = false;
|
|
2430
3843
|
const sink = session.resolvedConfig.sink;
|
|
2431
3844
|
const isStreamingMode = session.resolvedConfig.mode === "streaming";
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
3845
|
+
const terminal = initialStatus !== "paused" && initialStatus !== "in_progress";
|
|
3846
|
+
const exportTargets = [];
|
|
3847
|
+
if (sink.type === "otlp") exportTargets.push({ exporter: sink.exporter, isSink: true });
|
|
3848
|
+
if (!isSubagentTraceScope(session)) {
|
|
3849
|
+
for (const exporter of session.exporters ?? []) exportTargets.push({ exporter, isSink: false });
|
|
3850
|
+
}
|
|
3851
|
+
const unsampled = session.parent !== void 0 && !session.parent.sampled;
|
|
3852
|
+
if (exportTargets.length > 0) {
|
|
3853
|
+
const results = await Promise.all(
|
|
3854
|
+
exportTargets.map(async ({ exporter }) => {
|
|
3855
|
+
if (unsampled) {
|
|
3856
|
+
return { ok: true, skipped: true, reason: "the upstream traceparent is not sampled (sampled=0)", attempts: 0, spans: 0, bytes: 0 };
|
|
3857
|
+
}
|
|
3858
|
+
try {
|
|
3859
|
+
return await exporter.exportSession(exportPayload, {
|
|
3860
|
+
terminal,
|
|
3861
|
+
cancelled: params.cancelled,
|
|
3862
|
+
parent: session.parent
|
|
3863
|
+
});
|
|
3864
|
+
} catch (err) {
|
|
3865
|
+
return { ok: false, attempts: 0, spans: 0, bytes: 0, error: err instanceof Error ? err.message : String(err) };
|
|
3866
|
+
}
|
|
3867
|
+
})
|
|
3868
|
+
);
|
|
3869
|
+
results.forEach((result, index) => {
|
|
3870
|
+
const { exporter, isSink } = exportTargets[index];
|
|
3871
|
+
(session.exportReports ?? (session.exportReports = [])).push({ exporter: exporter.name, endpoint: exporter.endpoint, sink: isSink, terminal, result });
|
|
3872
|
+
if (result.ok) {
|
|
3873
|
+
const rejected = result.partialSuccess?.rejectedSpans ?? 0;
|
|
3874
|
+
if ((rejected > 0 || result.partialSuccess?.message) && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
3875
|
+
const detail = result.partialSuccess?.message ? `: ${result.partialSuccess.message}` : "";
|
|
3876
|
+
console.warn(`[Tracing] OTLP exporter "${exporter.name}": the collector rejected ${rejected} span(s)${detail}`);
|
|
3877
|
+
}
|
|
3878
|
+
return;
|
|
3879
|
+
}
|
|
3880
|
+
const message = result.error ?? "OTLP export failed";
|
|
3881
|
+
if (isSink) {
|
|
3882
|
+
sinkFailed = true;
|
|
3883
|
+
session.errors.push({ eventId: "sink", message, type: "sink", timestamp: endedAtIso });
|
|
3884
|
+
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
3885
|
+
console.error("[Tracing] OTLP export failed:", message);
|
|
3886
|
+
}
|
|
3887
|
+
} else if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
3888
|
+
console.warn(`[Tracing] OTLP exporter "${exporter.name}" failed:`, message);
|
|
3889
|
+
}
|
|
3890
|
+
});
|
|
3891
|
+
}
|
|
3892
|
+
if (params.exportOnly) {
|
|
3893
|
+
return buildPayload(payloadForSink.status);
|
|
3894
|
+
}
|
|
3895
|
+
if (sink.type === "cognipeer" || sink.type === "http") {
|
|
2447
3896
|
try {
|
|
2448
3897
|
const headers = sink.type === "cognipeer" ? { Authorization: `Bearer ${sink.apiKey}` } : sink.headers;
|
|
2449
3898
|
if (isStreamingMode && session.sessionStarted) {
|
|
@@ -2539,6 +3988,23 @@ async function finalizeTraceSession(session, params = {}) {
|
|
|
2539
3988
|
}
|
|
2540
3989
|
return finalPayload;
|
|
2541
3990
|
}
|
|
3991
|
+
async function closeTraceContinuation(continuation, params = {}) {
|
|
3992
|
+
const parsed = readTraceContinuation(continuation);
|
|
3993
|
+
if (!parsed) return void 0;
|
|
3994
|
+
const tracing = { ...params.tracing ?? {}, enabled: true };
|
|
3995
|
+
const hasOtlpSink = withDefaults(tracing).sink.type === "otlp";
|
|
3996
|
+
if (!hasOtlpSink && !params.exporters?.length) return void 0;
|
|
3997
|
+
const session = createTraceSession({ tracing }, parsed, { exporters: params.exporters });
|
|
3998
|
+
if (!session) return void 0;
|
|
3999
|
+
replayDeferredTraceEvents(session, params.events);
|
|
4000
|
+
const status = params.status ?? "partial";
|
|
4001
|
+
return finalizeTraceSession(session, {
|
|
4002
|
+
agentRuntime: params.agentRuntime,
|
|
4003
|
+
status,
|
|
4004
|
+
error: status === "error" ? params.error ?? { message: "The run ended in an error before it could be resumed." } : null,
|
|
4005
|
+
exportOnly: true
|
|
4006
|
+
});
|
|
4007
|
+
}
|
|
2542
4008
|
function sanitizeTracePayload(value) {
|
|
2543
4009
|
if (value === void 0) return void 0;
|
|
2544
4010
|
try {
|
|
@@ -2578,6 +4044,72 @@ function estimatePayloadBytes(value) {
|
|
|
2578
4044
|
}
|
|
2579
4045
|
}
|
|
2580
4046
|
}
|
|
4047
|
+
|
|
4048
|
+
// src/providers/wireInfo.ts
|
|
4049
|
+
var WIRE_INFO = Symbol.for("cognipeer.agent-sdk.wireInfo");
|
|
4050
|
+
function usageBasisOf(provider) {
|
|
4051
|
+
switch (provider) {
|
|
4052
|
+
case "anthropic":
|
|
4053
|
+
case "bedrock":
|
|
4054
|
+
return { inputExcludesCache: true };
|
|
4055
|
+
case "vertex":
|
|
4056
|
+
return { outputExcludesReasoning: true };
|
|
4057
|
+
default:
|
|
4058
|
+
return void 0;
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
function attachWireInfo(message, info) {
|
|
4062
|
+
const clean = {};
|
|
4063
|
+
if (info.provider) clean.provider = info.provider;
|
|
4064
|
+
if (info.responseId) clean.responseId = info.responseId;
|
|
4065
|
+
if (info.responseModel) clean.responseModel = info.responseModel;
|
|
4066
|
+
if (info.rawFinishReason) clean.rawFinishReason = info.rawFinishReason;
|
|
4067
|
+
if (info.streaming) clean.streaming = true;
|
|
4068
|
+
const basis = info.usageBasis ?? usageBasisOf(info.provider);
|
|
4069
|
+
if (basis) clean.usageBasis = basis;
|
|
4070
|
+
message[WIRE_INFO] = clean;
|
|
4071
|
+
return message;
|
|
4072
|
+
}
|
|
4073
|
+
function wireInfoOf(message) {
|
|
4074
|
+
if (!message || typeof message !== "object") return void 0;
|
|
4075
|
+
return message[WIRE_INFO];
|
|
4076
|
+
}
|
|
4077
|
+
|
|
4078
|
+
// src/utils/traceFacts.ts
|
|
4079
|
+
var nonEmpty2 = (value) => typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
4080
|
+
var isRunId = (id) => /^(run-|lc_run)/i.test(id);
|
|
4081
|
+
function providerHintOf(model, response) {
|
|
4082
|
+
const named = getProviderName(model);
|
|
4083
|
+
if (named) return named;
|
|
4084
|
+
const fromWire = wireInfoOf(response)?.provider;
|
|
4085
|
+
if (fromWire) return fromWire;
|
|
4086
|
+
try {
|
|
4087
|
+
return nonEmpty2(getModelCapabilities(model).provider);
|
|
4088
|
+
} catch {
|
|
4089
|
+
return void 0;
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
function traceResponseFacts(model, response, rawUsage, streaming) {
|
|
4093
|
+
const wire = wireInfoOf(response);
|
|
4094
|
+
const meta = response?.response_metadata ?? {};
|
|
4095
|
+
const message = response;
|
|
4096
|
+
const idCandidate = nonEmpty2(wire?.responseId) ?? nonEmpty2(meta.id) ?? nonEmpty2(message?.id);
|
|
4097
|
+
const responseId = idCandidate && !isRunId(idCandidate) ? idCandidate : void 0;
|
|
4098
|
+
const responseModel = nonEmpty2(wire?.responseModel) ?? nonEmpty2(meta.model_name) ?? nonEmpty2(meta.model) ?? nonEmpty2(meta.modelName);
|
|
4099
|
+
const rawFinishReason = nonEmpty2(wire?.rawFinishReason) ?? nonEmpty2(meta.stop_reason) ?? nonEmpty2(meta.finish_reason) ?? nonEmpty2(meta.finishReason);
|
|
4100
|
+
const cacheWriteTokens = cacheWriteTokensOf(rawUsage);
|
|
4101
|
+
const provider = providerHintOf(model, response);
|
|
4102
|
+
const isStreaming = streaming ?? wire?.streaming;
|
|
4103
|
+
return {
|
|
4104
|
+
...provider ? { provider } : {},
|
|
4105
|
+
...responseId ? { responseId } : {},
|
|
4106
|
+
...responseModel ? { responseModel } : {},
|
|
4107
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
4108
|
+
...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {},
|
|
4109
|
+
...wire?.usageBasis ? { usageBasis: { ...wire.usageBasis } } : {},
|
|
4110
|
+
...isStreaming ? { streaming: true } : {}
|
|
4111
|
+
};
|
|
4112
|
+
}
|
|
2581
4113
|
function toMessageUsage(u) {
|
|
2582
4114
|
return {
|
|
2583
4115
|
prompt_tokens: u.inputTokens,
|
|
@@ -2600,7 +4132,12 @@ function fromNativeProvider(provider, options) {
|
|
|
2600
4132
|
if (link.signal) request.signal = link.signal;
|
|
2601
4133
|
request = await applyTransform(request);
|
|
2602
4134
|
const response = await provider.complete(request);
|
|
2603
|
-
return toBaseChatMessage(response)
|
|
4135
|
+
return attachWireInfo(toBaseChatMessage(response), {
|
|
4136
|
+
provider: provider.providerName,
|
|
4137
|
+
responseId: response.id,
|
|
4138
|
+
responseModel: response.model,
|
|
4139
|
+
rawFinishReason: response.rawFinishReason
|
|
4140
|
+
});
|
|
2604
4141
|
} finally {
|
|
2605
4142
|
link.dispose();
|
|
2606
4143
|
}
|
|
@@ -2619,6 +4156,8 @@ function fromNativeProvider(provider, options) {
|
|
|
2619
4156
|
let reasoningText = "";
|
|
2620
4157
|
let finishReason;
|
|
2621
4158
|
let responseModel;
|
|
4159
|
+
let responseId;
|
|
4160
|
+
let rawFinishReason;
|
|
2622
4161
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
2623
4162
|
for await (const chunk of provider.completeStream(request)) {
|
|
2624
4163
|
if (chunk.delta.content) {
|
|
@@ -2626,6 +4165,8 @@ function fromNativeProvider(provider, options) {
|
|
|
2626
4165
|
yield chunk.delta.content;
|
|
2627
4166
|
}
|
|
2628
4167
|
if (chunk.model) responseModel = chunk.model;
|
|
4168
|
+
if (chunk.id) responseId = chunk.id;
|
|
4169
|
+
if (chunk.rawFinishReason) rawFinishReason = chunk.rawFinishReason;
|
|
2629
4170
|
if (chunk.finishReason) finishReason = chunk.finishReason;
|
|
2630
4171
|
if (chunk.delta.reasoning?.blocks?.length) {
|
|
2631
4172
|
reasoningBlocks = chunk.delta.reasoning.blocks;
|
|
@@ -2647,7 +4188,8 @@ function fromNativeProvider(provider, options) {
|
|
|
2647
4188
|
id: tc.id,
|
|
2648
4189
|
name: tc.name ?? "",
|
|
2649
4190
|
arguments: tc.arguments ?? "",
|
|
2650
|
-
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
4191
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {},
|
|
4192
|
+
...tc.idSynthesized ? { idSynthesized: true } : {}
|
|
2651
4193
|
});
|
|
2652
4194
|
}
|
|
2653
4195
|
}
|
|
@@ -2671,7 +4213,13 @@ function fromNativeProvider(provider, options) {
|
|
|
2671
4213
|
...responseModel ? { model_name: responseModel } : {}
|
|
2672
4214
|
};
|
|
2673
4215
|
}
|
|
2674
|
-
yield finalMessage
|
|
4216
|
+
yield attachWireInfo(finalMessage, {
|
|
4217
|
+
provider: provider.providerName,
|
|
4218
|
+
responseId,
|
|
4219
|
+
responseModel,
|
|
4220
|
+
rawFinishReason,
|
|
4221
|
+
streaming: true
|
|
4222
|
+
});
|
|
2675
4223
|
} finally {
|
|
2676
4224
|
link.dispose();
|
|
2677
4225
|
}
|
|
@@ -3045,7 +4593,8 @@ function toBaseChatMessage(response) {
|
|
|
3045
4593
|
id: tc.id,
|
|
3046
4594
|
type: "function",
|
|
3047
4595
|
function: { name: tc.name, arguments: tc.arguments },
|
|
3048
|
-
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
4596
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {},
|
|
4597
|
+
...tc.idSynthesized ? { idSynthesized: true } : {}
|
|
3049
4598
|
}));
|
|
3050
4599
|
}
|
|
3051
4600
|
if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
|
|
@@ -3067,7 +4616,8 @@ function assembleMessage(content, toolCalls, usage) {
|
|
|
3067
4616
|
id: tc.id,
|
|
3068
4617
|
type: "function",
|
|
3069
4618
|
function: { name: tc.name, arguments: tc.arguments },
|
|
3070
|
-
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
4619
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {},
|
|
4620
|
+
...tc.idSynthesized ? { idSynthesized: true } : {}
|
|
3071
4621
|
}));
|
|
3072
4622
|
}
|
|
3073
4623
|
return msg;
|
|
@@ -3961,7 +5511,7 @@ var CCRStore = class _CCRStore {
|
|
|
3961
5511
|
}
|
|
3962
5512
|
static hashOf(value) {
|
|
3963
5513
|
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
3964
|
-
return crypto.createHash("
|
|
5514
|
+
return crypto.createHash("sha256").update(serialized).digest("hex").slice(0, 16);
|
|
3965
5515
|
}
|
|
3966
5516
|
};
|
|
3967
5517
|
var DedupTracker = class {
|
|
@@ -3974,7 +5524,7 @@ var DedupTracker = class {
|
|
|
3974
5524
|
* first time it has been seen.
|
|
3975
5525
|
*/
|
|
3976
5526
|
checkAndRegister(content, executionId, toolName) {
|
|
3977
|
-
const hash = crypto.createHash("
|
|
5527
|
+
const hash = crypto.createHash("sha256").update(content).digest("hex");
|
|
3978
5528
|
const existing = this.seen.get(hash);
|
|
3979
5529
|
if (!existing) {
|
|
3980
5530
|
this.seen.set(hash, { executionId, toolName });
|
|
@@ -4511,7 +6061,7 @@ function createAgentCoreNode(opts) {
|
|
|
4511
6061
|
const actorVersion = runtime.version ?? opts.version;
|
|
4512
6062
|
let traceToolDefinitions;
|
|
4513
6063
|
const computeTraceToolDefinitions = (menu) => {
|
|
4514
|
-
if (!traceSession || !traceSession.resolvedConfig.logData || menu.length === 0) return void 0;
|
|
6064
|
+
if (!traceSession || !(traceSession.resolvedConfig.logData || traceSession.captureContent) || menu.length === 0) return void 0;
|
|
4515
6065
|
try {
|
|
4516
6066
|
const wire = shouldUseStrictToolCalling ? prepareStrictToolMenu(menu).menu : menu;
|
|
4517
6067
|
return wire.map((tool) => {
|
|
@@ -4724,8 +6274,9 @@ ${append}`;
|
|
|
4724
6274
|
// outcome, and an "error" status would flip the whole trace session
|
|
4725
6275
|
// status to error for a run that behaved exactly as configured.
|
|
4726
6276
|
status: "skipped",
|
|
6277
|
+
skipReason: "blocked",
|
|
4727
6278
|
model: getModelName(runtime.model || opts.model),
|
|
4728
|
-
provider:
|
|
6279
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
4729
6280
|
messageList: state.messages
|
|
4730
6281
|
});
|
|
4731
6282
|
return {
|
|
@@ -4754,9 +6305,12 @@ ${append}`;
|
|
|
4754
6305
|
for (const key of ["usage", "usage_metadata", "response_metadata"]) {
|
|
4755
6306
|
if (merged[key] === void 0 && original?.[key] !== void 0) merged[key] = original[key];
|
|
4756
6307
|
}
|
|
6308
|
+
if (wireInfoOf(merged) === void 0 && wireInfoOf(original) !== void 0) merged[WIRE_INFO] = wireInfoOf(original);
|
|
4757
6309
|
return merged;
|
|
4758
6310
|
};
|
|
4759
6311
|
let response;
|
|
6312
|
+
let sentMessages;
|
|
6313
|
+
let streamedCall = false;
|
|
4760
6314
|
let modelAttempt = 0;
|
|
4761
6315
|
const maxModelRetries = host?.maxModelRetries ?? 0;
|
|
4762
6316
|
const finishCancelledTurn = (partialText) => {
|
|
@@ -4770,12 +6324,16 @@ ${append}`;
|
|
|
4770
6324
|
// "skipped", not "error": the call did not fail, the caller ended it —
|
|
4771
6325
|
// and an "error" would flip the whole session to error.
|
|
4772
6326
|
status: "skipped",
|
|
6327
|
+
// The call reached the provider and was hung up on: still a model call, not a skipped one.
|
|
6328
|
+
skipReason: "cancelled",
|
|
6329
|
+
...streamedCall ? { streaming: true } : {},
|
|
4773
6330
|
durationMs: Date.now() - start,
|
|
4774
6331
|
requestBytes: promptBytes,
|
|
4775
6332
|
model: getModelName(runtime.model || opts.model),
|
|
4776
|
-
provider:
|
|
6333
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
4777
6334
|
messageList: state.messages,
|
|
4778
|
-
toolDefinitions: traceToolDefinitions
|
|
6335
|
+
toolDefinitions: traceToolDefinitions,
|
|
6336
|
+
capture: { input: sentMessages ?? wireMessages, toolDefinitions: traceToolDefinitions }
|
|
4779
6337
|
});
|
|
4780
6338
|
onEvent?.({ type: "cancelled", stage: "agent", reason });
|
|
4781
6339
|
onProgress?.({ stage: "agent", message: "Cancelled", detail: { reason } });
|
|
@@ -4791,8 +6349,9 @@ ${append}`;
|
|
|
4791
6349
|
label: "Assistant (plugin short-circuit)",
|
|
4792
6350
|
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
4793
6351
|
status: "skipped",
|
|
6352
|
+
skipReason: "short_circuit",
|
|
4794
6353
|
model: getModelName(runtime.model || opts.model),
|
|
4795
|
-
provider:
|
|
6354
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
4796
6355
|
messageList: state.messages,
|
|
4797
6356
|
toolDefinitions: traceToolDefinitions
|
|
4798
6357
|
});
|
|
@@ -4800,8 +6359,10 @@ ${append}`;
|
|
|
4800
6359
|
let streamedText = "";
|
|
4801
6360
|
try {
|
|
4802
6361
|
const normalizedMessages = normalizeBedrockToolPairing([...wireMessages]);
|
|
6362
|
+
sentMessages = normalizedMessages;
|
|
4803
6363
|
debugToolPairing(normalizedMessages);
|
|
4804
6364
|
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
6365
|
+
streamedCall = true;
|
|
4805
6366
|
let streamedMessage;
|
|
4806
6367
|
let cutByCancel = false;
|
|
4807
6368
|
for await (const chunk of modelWithTools.stream(normalizedMessages, invokeParams)) {
|
|
@@ -4847,12 +6408,14 @@ ${append}`;
|
|
|
4847
6408
|
durationMs: durationMs2,
|
|
4848
6409
|
requestBytes: promptBytes,
|
|
4849
6410
|
model: getModelName(runtime.model || opts.model),
|
|
4850
|
-
provider:
|
|
4851
|
-
error:
|
|
6411
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
6412
|
+
error: traceErrorOf(err),
|
|
6413
|
+
...streamedCall ? { streaming: true } : {},
|
|
4852
6414
|
messageList: state.messages,
|
|
4853
6415
|
toolDefinitions: traceToolDefinitions,
|
|
4854
6416
|
responseFormat: traceResponseFormat,
|
|
4855
|
-
responseFormatStrategy: traceResponseFormatStrategy
|
|
6417
|
+
responseFormatStrategy: traceResponseFormatStrategy,
|
|
6418
|
+
capture: { input: sentMessages ?? wireMessages, toolDefinitions: traceToolDefinitions }
|
|
4856
6419
|
});
|
|
4857
6420
|
throw err;
|
|
4858
6421
|
}
|
|
@@ -4905,6 +6468,8 @@ ${append}`;
|
|
|
4905
6468
|
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
4906
6469
|
const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
|
|
4907
6470
|
const finishReason = response?.response_metadata?.finish_reason ?? response?.response_metadata?.finishReason ?? response?.finishReason;
|
|
6471
|
+
const facts = traceResponseFacts(runtime.model || opts.model, response, rawUsage, streamedCall);
|
|
6472
|
+
const jsonOutput = Boolean(responseFormat) && responseFormat?.response_format?.type !== "text" && responseFormat?.type !== "text";
|
|
4908
6473
|
recordTraceEvent(traceSession, {
|
|
4909
6474
|
type: "ai_call",
|
|
4910
6475
|
label: "Assistant Response",
|
|
@@ -4921,11 +6486,13 @@ ${append}`;
|
|
|
4921
6486
|
requestBytes: promptBytes,
|
|
4922
6487
|
responseBytes,
|
|
4923
6488
|
model: modelName,
|
|
4924
|
-
|
|
6489
|
+
...facts,
|
|
6490
|
+
outputType: jsonOutput ? "json" : "text",
|
|
4925
6491
|
messageList: messagesWithResponse,
|
|
4926
6492
|
toolDefinitions: traceToolDefinitions,
|
|
4927
6493
|
responseFormat: traceResponseFormat,
|
|
4928
|
-
responseFormatStrategy: traceResponseFormatStrategy
|
|
6494
|
+
responseFormatStrategy: traceResponseFormatStrategy,
|
|
6495
|
+
capture: { input: sentMessages ?? wireMessages, output: response, toolDefinitions: traceToolDefinitions }
|
|
4929
6496
|
});
|
|
4930
6497
|
if (normalized) {
|
|
4931
6498
|
recordUsage(state, modelName, normalized);
|
|
@@ -4936,6 +6503,9 @@ ${append}`;
|
|
|
4936
6503
|
|
|
4937
6504
|
// src/utils/traceDecisions.ts
|
|
4938
6505
|
var TRACED_KEY = "__outcomeTraced";
|
|
6506
|
+
function surfacedFromSubagent(entry) {
|
|
6507
|
+
return Boolean(entry.metadata?.__subagent);
|
|
6508
|
+
}
|
|
4939
6509
|
function waitedMs(from, to) {
|
|
4940
6510
|
if (!from || !to) return void 0;
|
|
4941
6511
|
const ms = Date.parse(to) - Date.parse(from);
|
|
@@ -4948,8 +6518,14 @@ function sameJson(a, b) {
|
|
|
4948
6518
|
return false;
|
|
4949
6519
|
}
|
|
4950
6520
|
}
|
|
6521
|
+
var idSection = (label, data) => ({
|
|
6522
|
+
kind: "metadata",
|
|
6523
|
+
label,
|
|
6524
|
+
data,
|
|
6525
|
+
identity: true
|
|
6526
|
+
});
|
|
4951
6527
|
function recordApprovalRequested(session, entry) {
|
|
4952
|
-
if (!session) return;
|
|
6528
|
+
if (!session || surfacedFromSubagent(entry) || !canPauseForHuman(session)) return;
|
|
4953
6529
|
const logData = session.resolvedConfig.logData;
|
|
4954
6530
|
const sections = [
|
|
4955
6531
|
{
|
|
@@ -4973,14 +6549,14 @@ function recordApprovalRequested(session, entry) {
|
|
|
4973
6549
|
timestamp: entry.requestedAt,
|
|
4974
6550
|
status: "pending",
|
|
4975
6551
|
actor: { scope: "agent", name: entry.toolName, role: "approval_request" },
|
|
4976
|
-
sections
|
|
6552
|
+
sections: [...sections, idSection("Approval ids", { approvalId: entry.id, toolCallId: entry.toolCallId, status: "pending", requestedAt: entry.requestedAt })]
|
|
4977
6553
|
});
|
|
4978
6554
|
}
|
|
4979
6555
|
function recordHumanDecisions(session, state) {
|
|
4980
6556
|
if (!session) return;
|
|
4981
6557
|
const logData = session.resolvedConfig.logData;
|
|
4982
6558
|
for (const entry of state.pendingApprovals ?? []) {
|
|
4983
|
-
if (!entry.decidedAt || entry.metadata?.[TRACED_KEY]) continue;
|
|
6559
|
+
if (!entry.decidedAt || entry.metadata?.[TRACED_KEY] || surfacedFromSubagent(entry)) continue;
|
|
4984
6560
|
if (entry.status !== "approved" && entry.status !== "rejected") continue;
|
|
4985
6561
|
const approved = entry.status === "approved";
|
|
4986
6562
|
const edited = approved && entry.approvedArgs !== void 0 && !sameJson(entry.approvedArgs, entry.args);
|
|
@@ -5014,12 +6590,19 @@ function recordHumanDecisions(session, state) {
|
|
|
5014
6590
|
durationMs: waitedMs(entry.requestedAt, entry.decidedAt),
|
|
5015
6591
|
status: "success",
|
|
5016
6592
|
actor: { scope: "human", name: entry.decidedBy || "reviewer", role: "approver" },
|
|
5017
|
-
sections
|
|
6593
|
+
sections: [...sections, idSection("Decision ids", {
|
|
6594
|
+
approvalId: entry.id,
|
|
6595
|
+
toolCallId: entry.toolCallId,
|
|
6596
|
+
decision: entry.status,
|
|
6597
|
+
requestedAt: entry.requestedAt,
|
|
6598
|
+
decidedAt: entry.decidedAt,
|
|
6599
|
+
...waitedMs(entry.requestedAt, entry.decidedAt) !== void 0 ? { waitedMs: waitedMs(entry.requestedAt, entry.decidedAt) } : {}
|
|
6600
|
+
})]
|
|
5018
6601
|
});
|
|
5019
6602
|
entry.metadata = { ...entry.metadata || {}, [TRACED_KEY]: true };
|
|
5020
6603
|
}
|
|
5021
6604
|
for (const entry of state.pendingUserQuestions ?? []) {
|
|
5022
|
-
if (!entry.answeredAt || entry.metadata?.[TRACED_KEY]) continue;
|
|
6605
|
+
if (!entry.answeredAt || entry.metadata?.[TRACED_KEY] || surfacedFromSubagent(entry)) continue;
|
|
5023
6606
|
if (entry.status !== "answered" && entry.status !== "cancelled") continue;
|
|
5024
6607
|
const clientTool = readClientTool(entry);
|
|
5025
6608
|
if (clientTool) {
|
|
@@ -5059,13 +6642,20 @@ function recordHumanDecisions(session, state) {
|
|
|
5059
6642
|
durationMs: waitedMs(entry.requestedAt, entry.answeredAt),
|
|
5060
6643
|
status: cancelled ? "skipped" : "success",
|
|
5061
6644
|
actor: { scope: "human", name: entry.answeredBy || "user", role: "user" },
|
|
5062
|
-
sections
|
|
6645
|
+
sections: [...sections, idSection("Answer ids", {
|
|
6646
|
+
questionId: entry.id,
|
|
6647
|
+
toolCallId: entry.toolCallId,
|
|
6648
|
+
status: entry.status,
|
|
6649
|
+
requestedAt: entry.requestedAt,
|
|
6650
|
+
answeredAt: entry.answeredAt,
|
|
6651
|
+
...waitedMs(entry.requestedAt, entry.answeredAt) !== void 0 ? { waitedMs: waitedMs(entry.requestedAt, entry.answeredAt) } : {}
|
|
6652
|
+
})]
|
|
5063
6653
|
});
|
|
5064
6654
|
entry.metadata = { ...entry.metadata || {}, [TRACED_KEY]: true };
|
|
5065
6655
|
}
|
|
5066
6656
|
}
|
|
5067
6657
|
function recordClientToolRequested(session, entry) {
|
|
5068
|
-
if (!session) return;
|
|
6658
|
+
if (!session || surfacedFromSubagent(entry) || !canPauseForHuman(session)) return;
|
|
5069
6659
|
const clientTool = readClientTool(entry);
|
|
5070
6660
|
if (!clientTool) return;
|
|
5071
6661
|
const sections = [
|
|
@@ -5084,7 +6674,7 @@ function recordClientToolRequested(session, entry) {
|
|
|
5084
6674
|
timestamp: entry.requestedAt,
|
|
5085
6675
|
status: "pending",
|
|
5086
6676
|
actor: { scope: "client", name: clientTool.name, role: "tool" },
|
|
5087
|
-
sections
|
|
6677
|
+
sections: [...sections, idSection("Client tool ids", { questionId: entry.id, toolCallId: entry.toolCallId, status: "pending", requestedAt: entry.requestedAt })]
|
|
5088
6678
|
});
|
|
5089
6679
|
}
|
|
5090
6680
|
function readClientTool(entry) {
|
|
@@ -5131,7 +6721,14 @@ function recordClientToolResult(session, entry, clientTool, toolHistory) {
|
|
|
5131
6721
|
durationMs: waitedMs(entry.requestedAt, entry.answeredAt) ?? ranMs,
|
|
5132
6722
|
status: failed ? "error" : "success",
|
|
5133
6723
|
actor: { scope: "client", name: clientTool.name, role: "tool" },
|
|
5134
|
-
sections
|
|
6724
|
+
sections: [...sections, idSection("Client tool ids", {
|
|
6725
|
+
questionId: entry.id,
|
|
6726
|
+
toolCallId: entry.toolCallId,
|
|
6727
|
+
status: failed ? "error" : "answered",
|
|
6728
|
+
requestedAt: entry.requestedAt,
|
|
6729
|
+
answeredAt: entry.answeredAt,
|
|
6730
|
+
...waitedMs(entry.requestedAt, entry.answeredAt) !== void 0 ? { waitedMs: waitedMs(entry.requestedAt, entry.answeredAt) } : {}
|
|
6731
|
+
})]
|
|
5135
6732
|
});
|
|
5136
6733
|
}
|
|
5137
6734
|
|
|
@@ -5237,9 +6834,11 @@ function normalizeToolCall(call) {
|
|
|
5237
6834
|
return {
|
|
5238
6835
|
id: call.id,
|
|
5239
6836
|
name,
|
|
5240
|
-
args: call.args ?? call.arguments ?? call.input ?? call.function?.arguments ?? call.function_call?.arguments
|
|
6837
|
+
args: call.args ?? call.arguments ?? call.input ?? call.function?.arguments ?? call.function_call?.arguments,
|
|
6838
|
+
...call.idSynthesized === true ? { idSynthesized: true } : {}
|
|
5241
6839
|
};
|
|
5242
6840
|
}
|
|
6841
|
+
var providerToolCallId = (tc) => tc.id && !tc.idSynthesized ? tc.id : void 0;
|
|
5243
6842
|
function normalizeToolSchema(tool, toolName) {
|
|
5244
6843
|
const schema = tool.schema;
|
|
5245
6844
|
if (!schema) return void 0;
|
|
@@ -5497,6 +7096,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
5497
7096
|
label: `Tool Denied - ${toolName}`,
|
|
5498
7097
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5499
7098
|
status: "skipped",
|
|
7099
|
+
skipReason: "denied",
|
|
7100
|
+
toolCallId: providerToolCallId(tc),
|
|
5500
7101
|
toolDetails,
|
|
5501
7102
|
toolExecutionId: toolCallId,
|
|
5502
7103
|
sections: buildToolTraceSections({
|
|
@@ -5568,6 +7169,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
5568
7169
|
label: `Tool Skipped - ${toolName}`,
|
|
5569
7170
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5570
7171
|
status: "skipped",
|
|
7172
|
+
skipReason: "skipped",
|
|
7173
|
+
toolCallId: providerToolCallId(tc),
|
|
5571
7174
|
toolDetails,
|
|
5572
7175
|
toolExecutionId: tc.id,
|
|
5573
7176
|
sections: buildToolTraceSections({
|
|
@@ -5704,10 +7307,13 @@ function createToolsNode(initialTools, opts) {
|
|
|
5704
7307
|
label: `Tool Error - ${toolName}`,
|
|
5705
7308
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5706
7309
|
status: "error",
|
|
7310
|
+
// The tool was not run: an open breaker refused the call.
|
|
7311
|
+
skipReason: "skipped",
|
|
7312
|
+
toolCallId: providerToolCallId(tc),
|
|
5707
7313
|
requestBytes: inputBytes,
|
|
5708
7314
|
toolDetails,
|
|
5709
7315
|
toolExecutionId: toolCallId,
|
|
5710
|
-
error: { message: breakerMsg },
|
|
7316
|
+
error: { message: breakerMsg, type: "circuit_breaker_open" },
|
|
5711
7317
|
sections: buildToolTraceSections({
|
|
5712
7318
|
args,
|
|
5713
7319
|
executionId: toolCallId,
|
|
@@ -5721,6 +7327,7 @@ function createToolsNode(initialTools, opts) {
|
|
|
5721
7327
|
toolCount += 1;
|
|
5722
7328
|
return { status: "error" };
|
|
5723
7329
|
}
|
|
7330
|
+
let traceSpanId;
|
|
5724
7331
|
try {
|
|
5725
7332
|
if (cachedHit !== void 0) {
|
|
5726
7333
|
const executionId2 = nanoid.nanoid();
|
|
@@ -5766,6 +7373,9 @@ function createToolsNode(initialTools, opts) {
|
|
|
5766
7373
|
type: "tool_call",
|
|
5767
7374
|
label: shortCircuitSource === "plugin" ? `Tool Short-Circuited - ${toolName}` : `Tool Execution - ${toolName}`,
|
|
5768
7375
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
7376
|
+
// Answered from the cache or by a plugin: nothing executed.
|
|
7377
|
+
skipReason: "short_circuit",
|
|
7378
|
+
toolCallId: providerToolCallId(tc),
|
|
5769
7379
|
durationMs: 0,
|
|
5770
7380
|
requestBytes: inputBytes,
|
|
5771
7381
|
responseBytes: outputBytes2,
|
|
@@ -5800,7 +7410,16 @@ function createToolsNode(initialTools, opts) {
|
|
|
5800
7410
|
onEvent?.({ type: "tool_call", phase: "start", name: toolName, id: tc.id, args });
|
|
5801
7411
|
onProgress?.({ stage: "tools", message: `Running tool ${tc.name}` });
|
|
5802
7412
|
const anyTool = tool;
|
|
5803
|
-
|
|
7413
|
+
traceSpanId = traceSession ? generateSpanId() : void 0;
|
|
7414
|
+
const callOptions = {
|
|
7415
|
+
cancellationToken,
|
|
7416
|
+
signal: abortSignal,
|
|
7417
|
+
toolCallId,
|
|
7418
|
+
...traceSpanId ? { traceSpanId } : {},
|
|
7419
|
+
// So the tool can propagate the trace to what it calls (traceparentOf).
|
|
7420
|
+
...traceSpanId && traceSession?.traceId ? { traceId: traceSession.traceId } : {},
|
|
7421
|
+
...traceSpanId && traceSession?.parent ? { traceFlags: traceSession.parent.flags } : {}
|
|
7422
|
+
};
|
|
5804
7423
|
const invokeOnce = async () => {
|
|
5805
7424
|
if (typeof anyTool.func === "function") return anyTool.func(args, callOptions);
|
|
5806
7425
|
if (typeof anyTool.invoke === "function") return anyTool.invoke(args, callOptions);
|
|
@@ -5983,9 +7602,13 @@ function createToolsNode(initialTools, opts) {
|
|
|
5983
7602
|
const outputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedOutput) : void 0;
|
|
5984
7603
|
recordTraceEvent(traceSession, {
|
|
5985
7604
|
type: "tool_call",
|
|
7605
|
+
spanId: traceSpanId,
|
|
5986
7606
|
label: `Tool Execution - ${toolName}`,
|
|
5987
7607
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5988
|
-
...reportedFailure ? { status: "error", error: { message: reportedFailure } } : {},
|
|
7608
|
+
...reportedFailure ? { status: "error", error: { message: reportedFailure, type: "tool_error" } } : {},
|
|
7609
|
+
toolCallId: providerToolCallId(tc),
|
|
7610
|
+
// `output` is already past postToolUse, so a redaction plugin has applied.
|
|
7611
|
+
capture: reportedFailure ? { toolArguments: args } : { toolArguments: args, toolResult: output, hasToolResult: true },
|
|
5989
7612
|
durationMs,
|
|
5990
7613
|
requestBytes: inputBytes,
|
|
5991
7614
|
responseBytes: outputBytes,
|
|
@@ -6045,15 +7668,18 @@ function createToolsNode(initialTools, opts) {
|
|
|
6045
7668
|
const errorOutput = { message, stack: host?.has("postToolUse") ? void 0 : error?.stack };
|
|
6046
7669
|
recordTraceEvent(traceSession, {
|
|
6047
7670
|
type: "tool_call",
|
|
7671
|
+
spanId: traceSpanId,
|
|
6048
7672
|
label: `Tool Error - ${toolName}`,
|
|
6049
7673
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
6050
7674
|
status: "error",
|
|
7675
|
+
toolCallId: providerToolCallId(tc),
|
|
7676
|
+
capture: { toolArguments: args },
|
|
6051
7677
|
durationMs,
|
|
6052
7678
|
requestBytes: inputBytes,
|
|
6053
7679
|
responseBytes: traceSession?.resolvedConfig.logData ? estimatePayloadBytes(errorOutput) : void 0,
|
|
6054
7680
|
toolDetails,
|
|
6055
7681
|
toolExecutionId: executionId,
|
|
6056
|
-
error: { message, stack: host?.has("postToolUse") ? void 0 : error?.stack },
|
|
7682
|
+
error: { ...traceErrorOf(error), message, stack: host?.has("postToolUse") ? void 0 : error?.stack },
|
|
6057
7683
|
sections: buildToolTraceSections({
|
|
6058
7684
|
args: sanitizedArgs,
|
|
6059
7685
|
durationMs,
|
|
@@ -6168,6 +7794,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
6168
7794
|
label: `Tool Skipped - ${tc.name}`,
|
|
6169
7795
|
actor: { scope: "tool", name: tc.name, role: "tool" },
|
|
6170
7796
|
status: "skipped",
|
|
7797
|
+
skipReason: "skipped",
|
|
7798
|
+
toolCallId: providerToolCallId(tc),
|
|
6171
7799
|
toolDetails,
|
|
6172
7800
|
toolExecutionId: tc.id,
|
|
6173
7801
|
sections: buildToolTraceSections({
|
|
@@ -6334,7 +7962,7 @@ function createReflectionNode(opts, resolved) {
|
|
|
6334
7962
|
label: "Reflection error",
|
|
6335
7963
|
actor: { scope: "agent", name: opts.name || "agent", role: "reflection" },
|
|
6336
7964
|
status: "error",
|
|
6337
|
-
error:
|
|
7965
|
+
error: traceErrorOf(err)
|
|
6338
7966
|
});
|
|
6339
7967
|
return {};
|
|
6340
7968
|
}
|
|
@@ -7005,7 +8633,7 @@ function createAskUserQuestionTool(stateRef, config) {
|
|
|
7005
8633
|
questions: entry.questions,
|
|
7006
8634
|
allowFreeText
|
|
7007
8635
|
});
|
|
7008
|
-
recordTraceEvent(ctx.__traceSession, {
|
|
8636
|
+
if (canPauseForHuman(ctx.__traceSession)) recordTraceEvent(ctx.__traceSession, {
|
|
7009
8637
|
type: "user_question",
|
|
7010
8638
|
label: "Question to user",
|
|
7011
8639
|
timestamp: entry.requestedAt,
|
|
@@ -7345,7 +8973,7 @@ function buildSubagentCatalogBlock(subagents, policy, toolNames, opts) {
|
|
|
7345
8973
|
// src/plugins/host.ts
|
|
7346
8974
|
init_content();
|
|
7347
8975
|
var DEFAULT_PRIORITY = 100;
|
|
7348
|
-
var
|
|
8976
|
+
var DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
7349
8977
|
var HOOK_SPECS = {
|
|
7350
8978
|
sessionStart: { kind: "gate", mutable: ["messages"], collect: ["systemPromptAppend"] },
|
|
7351
8979
|
userPromptSubmit: {
|
|
@@ -7450,7 +9078,7 @@ function collectRegistrations(plugin, registrations, into, orderRef) {
|
|
|
7450
9078
|
plugin: plugin.name,
|
|
7451
9079
|
priority: plugin.priority ?? DEFAULT_PRIORITY,
|
|
7452
9080
|
failureMode: plugin.failureMode ?? "open",
|
|
7453
|
-
timeoutMs: plugin.timeoutMs ??
|
|
9081
|
+
timeoutMs: plugin.timeoutMs ?? DEFAULT_TIMEOUT_MS2,
|
|
7454
9082
|
order: orderRef.value++,
|
|
7455
9083
|
handler
|
|
7456
9084
|
});
|
|
@@ -7505,6 +9133,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7505
9133
|
let contributions = {
|
|
7506
9134
|
tools: [],
|
|
7507
9135
|
toolDescriptions: {},
|
|
9136
|
+
traceExporters: [],
|
|
7508
9137
|
guardrails: [],
|
|
7509
9138
|
applySystemPrompt: (base) => base,
|
|
7510
9139
|
applyModelWrappers: (model) => model
|
|
@@ -7513,6 +9142,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7513
9142
|
async function runSetup(setupInput) {
|
|
7514
9143
|
const tools = [];
|
|
7515
9144
|
const toolDescriptions = {};
|
|
9145
|
+
const traceExporters = [];
|
|
7516
9146
|
const guardrails = [];
|
|
7517
9147
|
const promptSteps = [];
|
|
7518
9148
|
const modelWrappers = [];
|
|
@@ -7550,6 +9180,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7550
9180
|
);
|
|
7551
9181
|
}
|
|
7552
9182
|
if (plugin.toolDescriptions) Object.assign(toolDescriptions, plugin.toolDescriptions);
|
|
9183
|
+
if (plugin.traceExporters?.length) traceExporters.push(...plugin.traceExporters.filter(Boolean));
|
|
7553
9184
|
if (plugin.guardrails?.length) guardrails.push(...plugin.guardrails);
|
|
7554
9185
|
if (typeof plugin.wrapModel === "function") {
|
|
7555
9186
|
modelWrappers.push({ plugin: plugin.name, wrap: plugin.wrapModel });
|
|
@@ -7565,6 +9196,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7565
9196
|
contributions = {
|
|
7566
9197
|
tools,
|
|
7567
9198
|
toolDescriptions,
|
|
9199
|
+
traceExporters,
|
|
7568
9200
|
guardrails,
|
|
7569
9201
|
applySystemPrompt: (base) => promptSteps.reduce((current, step) => {
|
|
7570
9202
|
try {
|
|
@@ -8288,19 +9920,22 @@ function createAgent(opts) {
|
|
|
8288
9920
|
detail: { reason: budget.reason, iteration: iterations }
|
|
8289
9921
|
});
|
|
8290
9922
|
}
|
|
9923
|
+
recordHumanDecisions(state.ctx?.__traceSession, state);
|
|
8291
9924
|
const ctx = { ...state.ctx || {}, __limitBreached: budget.reason };
|
|
8292
9925
|
state = { ...state, ctx };
|
|
8293
9926
|
break;
|
|
8294
9927
|
}
|
|
8295
9928
|
const traceSession = state.ctx?.__traceSession;
|
|
8296
9929
|
if (traceSession) {
|
|
8297
|
-
const
|
|
9930
|
+
const subagentScope = subagentTraceScopeOf(traceSession);
|
|
9931
|
+
const iterationNumber = subagentScope ? ++subagentScope.iterations : (traceSession.summary.eventCounts.agent_iteration ?? 0) - (traceSession.summary.subagentIterations ?? 0) + 1;
|
|
8298
9932
|
const iterEvent = recordTraceEvent(traceSession, {
|
|
8299
9933
|
type: "agent_iteration",
|
|
8300
9934
|
label: `Iteration ${iterationNumber}`,
|
|
8301
9935
|
actor: { scope: "agent", name: opts.name || "agent", role: "orchestrator" },
|
|
8302
9936
|
parentSpanId: traceSession.rootSpanId
|
|
8303
9937
|
});
|
|
9938
|
+
if (subagentScope) traceSession.summary.subagentIterations = (traceSession.summary.subagentIterations ?? 0) + 1;
|
|
8304
9939
|
if (iterEvent) {
|
|
8305
9940
|
traceSession.currentIterationSpanId = iterEvent.spanId;
|
|
8306
9941
|
}
|
|
@@ -8585,7 +10220,10 @@ function createAgent(opts) {
|
|
|
8585
10220
|
}
|
|
8586
10221
|
emit({ type: "progress", ...progress });
|
|
8587
10222
|
};
|
|
8588
|
-
const traceSession = createTraceSession(opts, readTraceContinuation(input.ctx?.__traceContinuation)
|
|
10223
|
+
const traceSession = createTraceSession(opts, readTraceContinuation(input.ctx?.__traceContinuation), {
|
|
10224
|
+
exporters: pluginHost.contributions.traceExporters,
|
|
10225
|
+
traceParent: config?.traceParent
|
|
10226
|
+
});
|
|
8589
10227
|
const ctx = {
|
|
8590
10228
|
...input.ctx || {},
|
|
8591
10229
|
__onEvent: onEvent,
|
|
@@ -8610,7 +10248,9 @@ function createAgent(opts) {
|
|
|
8610
10248
|
const inheritedSession = config?.__pluginSession;
|
|
8611
10249
|
ctx.__runId = inheritedSession?.runId ?? traceSession?.sessionId ?? `run_${nanoid.nanoid(10)}`;
|
|
8612
10250
|
const stateHolder = inheritedSession?.stateHolder ?? { value: void 0 };
|
|
8613
|
-
const traceRecorder = createPluginTraceRecorder(
|
|
10251
|
+
const traceRecorder = createPluginTraceRecorder(
|
|
10252
|
+
() => traceSession ?? (subagentTraceScopeOf(ctx.__traceSession) ? ctx.__traceSession : void 0)
|
|
10253
|
+
);
|
|
8614
10254
|
const runHost = inheritedSession?.host ?? (pluginHost.hasAny() ? pluginHost.beginRun({
|
|
8615
10255
|
runId: ctx.__runId,
|
|
8616
10256
|
agentName: opts.name,
|
|
@@ -8735,7 +10375,7 @@ function createAgent(opts) {
|
|
|
8735
10375
|
await finalizeTraceSession(traceSession, {
|
|
8736
10376
|
agentRuntime: runtime,
|
|
8737
10377
|
status: "error",
|
|
8738
|
-
error: { message: err?.message, stack: err?.stack }
|
|
10378
|
+
error: { message: err?.message, stack: err?.stack, name: err?.name }
|
|
8739
10379
|
});
|
|
8740
10380
|
await endSession("error", { error: err instanceof Error ? err : new Error(String(err)), state: stateHolder.value });
|
|
8741
10381
|
if (userTokenCounter) {
|
|
@@ -8756,7 +10396,10 @@ function createAgent(opts) {
|
|
|
8756
10396
|
const midTurn = pausedForHuman || Boolean(res.ctx?.__needsSummarization);
|
|
8757
10397
|
await finalizeTraceSession(traceSession, {
|
|
8758
10398
|
agentRuntime: res.agent || runtime,
|
|
8759
|
-
status: pausedForHuman ? "paused" : midTurn ? "in_progress" : "success"
|
|
10399
|
+
status: pausedForHuman ? "paused" : midTurn ? "in_progress" : "success",
|
|
10400
|
+
// The file says `success` for a cancelled run (it did not fail); the
|
|
10401
|
+
// exported root says `partial`, the old plugin mapping.
|
|
10402
|
+
cancelled: statusFor(res) === "cancelled"
|
|
8760
10403
|
});
|
|
8761
10404
|
if (traceSession && midTurn) {
|
|
8762
10405
|
res.ctx = { ...res.ctx || {}, __traceContinuation: traceContinuationOf(traceSession) };
|
|
@@ -8853,7 +10496,7 @@ function createAgent(opts) {
|
|
|
8853
10496
|
name: toolName,
|
|
8854
10497
|
description: description || `Delegate task to agent ${opts.name || "Agent"}`,
|
|
8855
10498
|
schema,
|
|
8856
|
-
func: async ({ input }) => {
|
|
10499
|
+
func: async ({ input }, context) => {
|
|
8857
10500
|
const ref = delegatedTool._stateRef;
|
|
8858
10501
|
const parentCtx = ref.ctx || {};
|
|
8859
10502
|
const parentMessages = Array.isArray(ref.messages) ? ref.messages : [];
|
|
@@ -8886,6 +10529,33 @@ function createAgent(opts) {
|
|
|
8886
10529
|
input
|
|
8887
10530
|
);
|
|
8888
10531
|
const childCtx = { __delegationDepth: currentDepth + 1 };
|
|
10532
|
+
const parentSession = parentCtx.__traceSession;
|
|
10533
|
+
const traced = isTraceSessionOpen(parentSession);
|
|
10534
|
+
const agentSpanId = generateSpanId();
|
|
10535
|
+
const parentIterationSpanId = traced ? parentSession.currentIterationSpanId : void 0;
|
|
10536
|
+
if (traced && !withDefaults(opts.tracing).enabled) {
|
|
10537
|
+
childCtx.__traceSession = createSubagentTraceScope(parentSession, {
|
|
10538
|
+
agentSpanId,
|
|
10539
|
+
name: opts.name || "agent",
|
|
10540
|
+
mode: "asTool",
|
|
10541
|
+
hitl: false
|
|
10542
|
+
});
|
|
10543
|
+
}
|
|
10544
|
+
const startedAt = Date.now();
|
|
10545
|
+
const recordSpan = (status, extra) => {
|
|
10546
|
+
if (!traced || !isTraceSessionOpen(parentSession)) return;
|
|
10547
|
+
recordSubagentSpan(parentSession, {
|
|
10548
|
+
spanId: agentSpanId,
|
|
10549
|
+
parentSpanId: context?.traceSpanId ?? parentIterationSpanId,
|
|
10550
|
+
name: opts.name || "agent",
|
|
10551
|
+
status,
|
|
10552
|
+
durationMs: Date.now() - startedAt,
|
|
10553
|
+
error: extra.error,
|
|
10554
|
+
info: { name: opts.name || "agent", mode: "asTool", depth: currentDepth + 1, parentToolCallId: context?.toolCallId, status: status === "success" ? "ok" : "error" },
|
|
10555
|
+
task: input,
|
|
10556
|
+
result: extra.result
|
|
10557
|
+
});
|
|
10558
|
+
};
|
|
8889
10559
|
const childConfig = {
|
|
8890
10560
|
onEvent: parentCtx.__onEvent ? (e) => {
|
|
8891
10561
|
if (e?.type === "finalAnswer" || e?.type === "metadata") return;
|
|
@@ -8901,7 +10571,14 @@ function createAgent(opts) {
|
|
|
8901
10571
|
stream: Boolean(parentCtx.__streaming),
|
|
8902
10572
|
cancellationToken: parentCtx.__cancellationToken ?? parentCtx.__abortSignal
|
|
8903
10573
|
};
|
|
8904
|
-
|
|
10574
|
+
let res;
|
|
10575
|
+
try {
|
|
10576
|
+
res = await instance.invoke({ messages: childMessages, ctx: childCtx }, childConfig);
|
|
10577
|
+
} catch (err) {
|
|
10578
|
+
recordSpan("error", { error: err?.message || String(err) });
|
|
10579
|
+
throw err;
|
|
10580
|
+
}
|
|
10581
|
+
recordSpan("success", { result: res.content });
|
|
8905
10582
|
return {
|
|
8906
10583
|
content: res.content,
|
|
8907
10584
|
output: res.output,
|
|
@@ -8978,9 +10655,10 @@ function createAgentNode(opts) {
|
|
|
8978
10655
|
durationMs: durationMs2,
|
|
8979
10656
|
requestBytes: promptBytes,
|
|
8980
10657
|
model: getModelName(runtime.model || opts.model),
|
|
8981
|
-
provider:
|
|
8982
|
-
error:
|
|
8983
|
-
messageList: promptMessages
|
|
10658
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
10659
|
+
error: traceErrorOf(err),
|
|
10660
|
+
messageList: promptMessages,
|
|
10661
|
+
capture: { input: promptMessages }
|
|
8984
10662
|
});
|
|
8985
10663
|
throw err;
|
|
8986
10664
|
}
|
|
@@ -8991,7 +10669,7 @@ function createAgentNode(opts) {
|
|
|
8991
10669
|
const rawUsage = response?.usage || response?.usage_metadata || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage || response?.response_metadata?.usage_metadata || response?.response_metadata?.usageMetadata;
|
|
8992
10670
|
const normalized = normalizeUsage(rawUsage);
|
|
8993
10671
|
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
8994
|
-
const
|
|
10672
|
+
const facts = traceResponseFacts(runtime.model || opts.model, response, rawUsage);
|
|
8995
10673
|
const durationMs = Date.now() - start;
|
|
8996
10674
|
const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
|
|
8997
10675
|
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
@@ -9008,8 +10686,9 @@ function createAgentNode(opts) {
|
|
|
9008
10686
|
requestBytes: promptBytes,
|
|
9009
10687
|
responseBytes,
|
|
9010
10688
|
model: modelName,
|
|
9011
|
-
|
|
9012
|
-
messageList: messagesWithResponse
|
|
10689
|
+
...facts,
|
|
10690
|
+
messageList: messagesWithResponse,
|
|
10691
|
+
capture: { input: promptMessages, output: response }
|
|
9013
10692
|
});
|
|
9014
10693
|
if (normalized) {
|
|
9015
10694
|
recordUsage(state, modelName, normalized);
|
|
@@ -9660,7 +11339,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9660
11339
|
];
|
|
9661
11340
|
const inputTokensEstimate = countApproxTokens(summaryPrompt.map((m) => m.content).join("\n"));
|
|
9662
11341
|
const modelName = getModelName(model);
|
|
9663
|
-
const providerName =
|
|
11342
|
+
const providerName = providerHintOf(model);
|
|
9664
11343
|
const tracingEnabled = Boolean(opts.tracing?.enabled);
|
|
9665
11344
|
let ctxWithDeferredTrace;
|
|
9666
11345
|
const traceSummarization = (event) => {
|
|
@@ -9691,6 +11370,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9691
11370
|
let reasoningTokensActual;
|
|
9692
11371
|
let fallback = false;
|
|
9693
11372
|
let summarizerError;
|
|
11373
|
+
let responseFacts;
|
|
9694
11374
|
const directivesSection = () => ({
|
|
9695
11375
|
kind: "metadata",
|
|
9696
11376
|
label: "User directives",
|
|
@@ -9732,6 +11412,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9732
11412
|
summaryText = renderStructuredSummary(structuredSummary);
|
|
9733
11413
|
const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
9734
11414
|
const normalized = normalizeUsage(rawUsage);
|
|
11415
|
+
responseFacts = traceResponseFacts(model, response, rawUsage);
|
|
9735
11416
|
if (normalized) {
|
|
9736
11417
|
inputTokensActual = normalized.prompt_tokens;
|
|
9737
11418
|
outputTokensActual = normalized.completion_tokens;
|
|
@@ -9768,7 +11449,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9768
11449
|
...droppedDirectives.length > 0 ? { droppedDirectives } : {}
|
|
9769
11450
|
};
|
|
9770
11451
|
onEvent?.(errorEvent);
|
|
9771
|
-
summarizerError =
|
|
11452
|
+
summarizerError = traceErrorOf(err);
|
|
9772
11453
|
}
|
|
9773
11454
|
const toolCallIdToAssistantIdx = /* @__PURE__ */ new Map();
|
|
9774
11455
|
messages.forEach((m, idx) => {
|
|
@@ -9924,10 +11605,16 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9924
11605
|
outputTokens: outputTokensActual ?? outputTokensEstimate,
|
|
9925
11606
|
cachedInputTokens,
|
|
9926
11607
|
totalTokens: totalTokensActual,
|
|
9927
|
-
...reasoningTokensActual !== void 0 ? { reasoningTokens: reasoningTokensActual } : {}
|
|
11608
|
+
...reasoningTokensActual !== void 0 ? { reasoningTokens: reasoningTokensActual } : {},
|
|
11609
|
+
// Which counting rules the usage above follows (only when the provider reported it).
|
|
11610
|
+
...inputTokensActual !== void 0 && responseFacts?.usageBasis ? { usageBasis: responseFacts.usageBasis } : {},
|
|
11611
|
+
...inputTokensActual !== void 0 && responseFacts?.cacheWriteTokens ? { cacheWriteTokens: responseFacts.cacheWriteTokens } : {}
|
|
9928
11612
|
},
|
|
11613
|
+
...responseFacts?.responseId ? { responseId: responseFacts.responseId } : {},
|
|
11614
|
+
...responseFacts?.responseModel ? { responseModel: responseFacts.responseModel } : {},
|
|
11615
|
+
...responseFacts?.rawFinishReason ? { rawFinishReason: responseFacts.rawFinishReason } : {},
|
|
9929
11616
|
...modelName ? { model: modelName } : {},
|
|
9930
|
-
...providerName ? { provider: providerName } : {},
|
|
11617
|
+
...responseFacts?.provider ?? providerName ? { provider: responseFacts?.provider ?? providerName } : {},
|
|
9931
11618
|
...summarizerError ? { error: summarizerError } : {},
|
|
9932
11619
|
sections: [
|
|
9933
11620
|
...promptAndOutputSections(),
|
|
@@ -11064,11 +12751,52 @@ function mergeChildUsage(ref, childState, baseline, tag) {
|
|
|
11064
12751
|
async function runChild(spec, input, deps, ref, opts) {
|
|
11065
12752
|
const parentCtx = ref.ctx || {};
|
|
11066
12753
|
const parentOnEvent = parentCtx.__onEvent;
|
|
11067
|
-
const spawnId = `sa_${nanoid.nanoid(6)}`;
|
|
12754
|
+
const spawnId = opts.record?.spawnId ?? `sa_${nanoid.nanoid(6)}`;
|
|
11068
12755
|
const start = Date.now();
|
|
11069
12756
|
const usageTag = { name: spec.name, id: spawnId, mode: spec.mode };
|
|
11070
12757
|
const parentHost = parentCtx.__plugins;
|
|
11071
12758
|
const childDepth = (Number(parentCtx.__delegationDepth) || 0) + 1;
|
|
12759
|
+
const parentSession = parentCtx.__traceSession;
|
|
12760
|
+
const traced = isTraceSessionOpen(parentSession);
|
|
12761
|
+
const sessionStart = traced ? parentSession.startedAt : void 0;
|
|
12762
|
+
const persistedId = opts.record?.agentSpanId;
|
|
12763
|
+
const agentSpanId = typeof persistedId === "string" && /^[0-9a-f]{16}$/.test(persistedId) ? persistedId : generateSpanId();
|
|
12764
|
+
const persistedStart = opts.record?.startedAt;
|
|
12765
|
+
const startValid = typeof persistedStart === "number" && Number.isFinite(persistedStart) && persistedStart > 0 && persistedStart <= start;
|
|
12766
|
+
const runStartedAt = startValid ? Math.min(start, Math.max(persistedStart, sessionStart ?? persistedStart)) : start;
|
|
12767
|
+
const persistedSegments = opts.record?.segments;
|
|
12768
|
+
const segment = (typeof persistedSegments === "number" && Number.isInteger(persistedSegments) && persistedSegments >= 1 && persistedSegments <= 1e3 ? persistedSegments : 0) + 1;
|
|
12769
|
+
const elapsedMs = () => Math.max(0, Date.now() - runStartedAt);
|
|
12770
|
+
const parentIterationSpanId = traced ? parentSession.currentIterationSpanId : void 0;
|
|
12771
|
+
const traceScope = traced ? createSubagentTraceScope(parentSession, { agentSpanId, name: spec.name, spawnId, mode: spec.mode, hitl: opts.allowHITL, iterations: opts.record?.iterations }) : void 0;
|
|
12772
|
+
const recordSegment = (status, info) => {
|
|
12773
|
+
if (!traced || !isTraceSessionOpen(parentSession)) return;
|
|
12774
|
+
recordSubagentSpan(parentSession, {
|
|
12775
|
+
spanId: agentSpanId,
|
|
12776
|
+
// The tool_call span only exists once the tool returns; a paused child
|
|
12777
|
+
// has not returned, so its span hangs off the iteration.
|
|
12778
|
+
parentSpanId: status === "pending" ? parentIterationSpanId : opts.parentSpanId ?? parentIterationSpanId,
|
|
12779
|
+
name: spec.name,
|
|
12780
|
+
status,
|
|
12781
|
+
durationMs: elapsedMs(),
|
|
12782
|
+
error: info.error,
|
|
12783
|
+
info: {
|
|
12784
|
+
id: spawnId,
|
|
12785
|
+
name: spec.name,
|
|
12786
|
+
mode: spec.mode,
|
|
12787
|
+
parallel: opts.parallel,
|
|
12788
|
+
depth: childDepth,
|
|
12789
|
+
parentToolCallId: opts.parentToolCallId,
|
|
12790
|
+
status: info.subagentStatus,
|
|
12791
|
+
// Only a run that paused has more than one segment to tell about.
|
|
12792
|
+
...segment > 1 || status === "pending" ? { segments: segment } : {},
|
|
12793
|
+
...info.note ? { note: info.note } : {},
|
|
12794
|
+
...spec.metadata ? { metadata: spec.metadata } : {}
|
|
12795
|
+
},
|
|
12796
|
+
task: info.input,
|
|
12797
|
+
result: info.content
|
|
12798
|
+
});
|
|
12799
|
+
};
|
|
11072
12800
|
const emitStart = (task) => {
|
|
11073
12801
|
parentOnEvent?.({ type: "subagent", phase: "start", name: spec.name, id: spawnId, mode: spec.mode, parallel: opts.parallel, parentToolCallId: opts.parentToolCallId, input: task });
|
|
11074
12802
|
};
|
|
@@ -11076,6 +12804,15 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11076
12804
|
result2.durationMs ?? (result2.durationMs = Date.now() - start);
|
|
11077
12805
|
deps.registryRef.results.push(result2);
|
|
11078
12806
|
const message = result2.error || result2.note || result2.status;
|
|
12807
|
+
const traceStatus = result2.status === "ok" || result2.status === "incomplete" ? "success" : result2.status === "blocked" ? "skipped" : "error";
|
|
12808
|
+
recordSegment(traceStatus, {
|
|
12809
|
+
subagentStatus: result2.status,
|
|
12810
|
+
input,
|
|
12811
|
+
// `message` falls back to the status itself ("ok"): only a failed or refused run has an error to show.
|
|
12812
|
+
error: traceStatus === "success" ? void 0 : message,
|
|
12813
|
+
note: result2.note,
|
|
12814
|
+
content: result2.content
|
|
12815
|
+
});
|
|
11079
12816
|
parentOnEvent?.({
|
|
11080
12817
|
type: "subagent",
|
|
11081
12818
|
phase: FAILED_STATUSES.has(result2.status) ? "error" : "result",
|
|
@@ -11174,6 +12911,7 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11174
12911
|
ctx: { __delegationDepth: currentDepth + 1 }
|
|
11175
12912
|
};
|
|
11176
12913
|
}
|
|
12914
|
+
if (traceScope) childInput = { ...childInput, ctx: { ...childInput.ctx || {}, __traceSession: traceScope } };
|
|
11177
12915
|
const usageBaseline = childInput.usage?.perRequest?.length ?? 0;
|
|
11178
12916
|
let res;
|
|
11179
12917
|
try {
|
|
@@ -11214,8 +12952,14 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11214
12952
|
input,
|
|
11215
12953
|
childState: cleanChildState(childState),
|
|
11216
12954
|
pendingKind: "approval",
|
|
11217
|
-
pendingId: childEntry.id
|
|
12955
|
+
pendingId: childEntry.id,
|
|
12956
|
+
spawnId,
|
|
12957
|
+
iterations: traceScope ? subagentTraceScopeOf(traceScope)?.iterations : void 0,
|
|
12958
|
+
agentSpanId,
|
|
12959
|
+
startedAt: runStartedAt,
|
|
12960
|
+
segments: segment
|
|
11218
12961
|
};
|
|
12962
|
+
recordSegment("pending", { subagentStatus: "paused", input });
|
|
11219
12963
|
parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
|
|
11220
12964
|
return { kind: "approval", toolCallId: surfaced.toolCallId, approvalId: surfaced.id };
|
|
11221
12965
|
}
|
|
@@ -11237,8 +12981,14 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11237
12981
|
input,
|
|
11238
12982
|
childState: cleanChildState(childState),
|
|
11239
12983
|
pendingKind: "user_question",
|
|
11240
|
-
pendingId: childEntry.id
|
|
12984
|
+
pendingId: childEntry.id,
|
|
12985
|
+
spawnId,
|
|
12986
|
+
iterations: traceScope ? subagentTraceScopeOf(traceScope)?.iterations : void 0,
|
|
12987
|
+
agentSpanId,
|
|
12988
|
+
startedAt: runStartedAt,
|
|
12989
|
+
segments: segment
|
|
11241
12990
|
};
|
|
12991
|
+
recordSegment("pending", { subagentStatus: "paused", input });
|
|
11242
12992
|
parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
|
|
11243
12993
|
return { kind: "user_question", toolCallId: surfaced.toolCallId, id: surfaced.id };
|
|
11244
12994
|
}
|
|
@@ -11342,7 +13092,7 @@ function createDelegateTool(deps) {
|
|
|
11342
13092
|
if (!budget.ok) return refusal(budget.reason);
|
|
11343
13093
|
d.registryRef.spawnedCount += 1;
|
|
11344
13094
|
}
|
|
11345
|
-
return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record }));
|
|
13095
|
+
return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record, parentSpanId: context?.traceSpanId }));
|
|
11346
13096
|
}
|
|
11347
13097
|
});
|
|
11348
13098
|
tool._deps = deps;
|
|
@@ -11387,7 +13137,7 @@ function createSpawnTool(deps) {
|
|
|
11387
13137
|
if (!budget.ok) return refusal(budget.reason);
|
|
11388
13138
|
d.registryRef.spawnedCount += 1;
|
|
11389
13139
|
}
|
|
11390
|
-
return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record }));
|
|
13140
|
+
return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record, parentSpanId: context?.traceSpanId }));
|
|
11391
13141
|
}
|
|
11392
13142
|
});
|
|
11393
13143
|
tool._deps = deps;
|
|
@@ -11470,7 +13220,8 @@ function createParallelTool(deps) {
|
|
|
11470
13220
|
allowHITL: false,
|
|
11471
13221
|
parentToolCallId: `${parentToolCallId}#${i}`,
|
|
11472
13222
|
parallel: true,
|
|
11473
|
-
reserved: true
|
|
13223
|
+
reserved: true,
|
|
13224
|
+
parentSpanId: context?.traceSpanId
|
|
11474
13225
|
});
|
|
11475
13226
|
results[i] = outcome.kind === "result" ? outcome.result : { name: entry.spec.name, mode: entry.spec.mode, status: "error", input: entry.input, error: "Unexpected pause in parallel child." };
|
|
11476
13227
|
}
|
|
@@ -11922,6 +13673,30 @@ ${pluginAppend}`;
|
|
|
11922
13673
|
};
|
|
11923
13674
|
}
|
|
11924
13675
|
}
|
|
13676
|
+
const traceHandoff = {};
|
|
13677
|
+
const noteTraceHandoff = (current) => {
|
|
13678
|
+
traceHandoff.continuation = current.ctx?.__traceContinuation;
|
|
13679
|
+
traceHandoff.events = current.ctx?.[DEFERRED_TRACE_EVENTS_KEY];
|
|
13680
|
+
};
|
|
13681
|
+
const closeDanglingTrace = async (status, error) => {
|
|
13682
|
+
const continuation = traceHandoff.continuation;
|
|
13683
|
+
const events = traceHandoff.events;
|
|
13684
|
+
traceHandoff.continuation = void 0;
|
|
13685
|
+
traceHandoff.events = void 0;
|
|
13686
|
+
if (!continuation) return;
|
|
13687
|
+
try {
|
|
13688
|
+
await closeTraceContinuation(continuation, {
|
|
13689
|
+
tracing: opts.tracing,
|
|
13690
|
+
exporters: pluginHost?.contributions.traceExporters,
|
|
13691
|
+
status,
|
|
13692
|
+
error,
|
|
13693
|
+
agentRuntime: base.__runtime,
|
|
13694
|
+
events
|
|
13695
|
+
});
|
|
13696
|
+
} catch (closeError) {
|
|
13697
|
+
console.warn("[agent-sdk] closing the trace failed:", closeError);
|
|
13698
|
+
}
|
|
13699
|
+
};
|
|
11925
13700
|
try {
|
|
11926
13701
|
const toolSet = buildInvokeToolSet();
|
|
11927
13702
|
const stateRef = toolSet.stateRef;
|
|
@@ -12000,11 +13775,15 @@ ${pluginAppend}`;
|
|
|
12000
13775
|
const result = await trySummarize(state, rawMessages, stateRef);
|
|
12001
13776
|
state = result.state;
|
|
12002
13777
|
rawMessages = result.rawMessages;
|
|
13778
|
+
noteTraceHandoff(state);
|
|
12003
13779
|
if (result.compressed) continue;
|
|
12004
13780
|
}
|
|
12005
13781
|
const modelMessages = buildModelMessages(state, resolved);
|
|
13782
|
+
traceHandoff.continuation = void 0;
|
|
13783
|
+
traceHandoff.events = void 0;
|
|
12006
13784
|
const res = await base.invoke({ ...state, messages: modelMessages }, turnConfig);
|
|
12007
13785
|
lastResult = res;
|
|
13786
|
+
noteTraceHandoff(res.state ?? state);
|
|
12008
13787
|
const currentSummaries = state.summaries;
|
|
12009
13788
|
const currentSummaryRecords = state.summaryRecords;
|
|
12010
13789
|
const currentPlan = state.plan;
|
|
@@ -12031,6 +13810,7 @@ ${pluginAppend}`;
|
|
|
12031
13810
|
const result = await trySummarize(state, rawMessages, stateRef);
|
|
12032
13811
|
state = result.state;
|
|
12033
13812
|
rawMessages = result.rawMessages;
|
|
13813
|
+
noteTraceHandoff(state);
|
|
12034
13814
|
continue;
|
|
12035
13815
|
}
|
|
12036
13816
|
if (state.ctx?.__finalizedDueToStructuredOutput) break;
|
|
@@ -12042,6 +13822,7 @@ ${pluginAppend}`;
|
|
|
12042
13822
|
const result = await trySummarize(state, rawMessages, stateRef);
|
|
12043
13823
|
state = result.state;
|
|
12044
13824
|
rawMessages = result.rawMessages;
|
|
13825
|
+
noteTraceHandoff(state);
|
|
12045
13826
|
if (result.compressed) continue;
|
|
12046
13827
|
}
|
|
12047
13828
|
}
|
|
@@ -12052,6 +13833,7 @@ ${pluginAppend}`;
|
|
|
12052
13833
|
lastResult = res;
|
|
12053
13834
|
}
|
|
12054
13835
|
if (state.ctx?.[DEFERRED_TRACE_EVENTS_KEY]) {
|
|
13836
|
+
traceHandoff.events = state.ctx[DEFERRED_TRACE_EVENTS_KEY];
|
|
12055
13837
|
const ctx = { ...state.ctx || {} };
|
|
12056
13838
|
delete ctx[DEFERRED_TRACE_EVENTS_KEY];
|
|
12057
13839
|
state = { ...state, ctx };
|
|
@@ -12071,8 +13853,12 @@ ${pluginAppend}`;
|
|
|
12071
13853
|
const strippedCtx = { ...endCtx };
|
|
12072
13854
|
delete strippedCtx.__traceContinuation;
|
|
12073
13855
|
lastResult = { ...lastResult, state: { ...lastResult.state, ctx: strippedCtx } };
|
|
13856
|
+
traceHandoff.continuation = endCtx.__traceContinuation;
|
|
13857
|
+
await closeDanglingTrace("success");
|
|
12074
13858
|
}
|
|
12075
13859
|
}
|
|
13860
|
+
traceHandoff.continuation = void 0;
|
|
13861
|
+
traceHandoff.events = void 0;
|
|
12076
13862
|
if (skillsEnabled && lastResult.state) {
|
|
12077
13863
|
const persisted = skillStateFromRegistry(toolSet.skillRegistryRef);
|
|
12078
13864
|
if (persisted) {
|
|
@@ -12118,6 +13904,11 @@ ${pluginAppend}`;
|
|
|
12118
13904
|
await endSession(endStatus, { result: lastResult });
|
|
12119
13905
|
return lastResult;
|
|
12120
13906
|
} catch (err) {
|
|
13907
|
+
await closeDanglingTrace("error", {
|
|
13908
|
+
message: err instanceof Error ? err.message : String(err),
|
|
13909
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
13910
|
+
name: err instanceof Error ? err.name : void 0
|
|
13911
|
+
});
|
|
12121
13912
|
await endSession("error", { error: err instanceof Error ? err : new Error(String(err)) });
|
|
12122
13913
|
throw err;
|
|
12123
13914
|
}
|
|
@@ -13034,7 +14825,7 @@ function isHookImplemented(hook) {
|
|
|
13034
14825
|
// src/plugins/builtin/guardrail.ts
|
|
13035
14826
|
init_content();
|
|
13036
14827
|
var ALLOW = { action: "allow" };
|
|
13037
|
-
var
|
|
14828
|
+
var RETRYABLE_STATUS2 = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
13038
14829
|
var RetryableGuardrailError = class extends Error {
|
|
13039
14830
|
constructor(message) {
|
|
13040
14831
|
super(message);
|
|
@@ -13132,7 +14923,7 @@ function httpGuardrail(options) {
|
|
|
13132
14923
|
} catch {
|
|
13133
14924
|
}
|
|
13134
14925
|
const message = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}${text ? ` - ${text.slice(0, 200)}` : ""}`;
|
|
13135
|
-
if (
|
|
14926
|
+
if (RETRYABLE_STATUS2.has(response.status)) throw new RetryableGuardrailError(message);
|
|
13136
14927
|
throw new Error(message);
|
|
13137
14928
|
}
|
|
13138
14929
|
return response.json();
|
|
@@ -13239,9 +15030,9 @@ function createGuardrailPlugin(options) {
|
|
|
13239
15030
|
});
|
|
13240
15031
|
const resolved = verdict ?? ALLOW;
|
|
13241
15032
|
if (resolved.raw?.disabled === true) {
|
|
13242
|
-
const
|
|
13243
|
-
if (!
|
|
13244
|
-
|
|
15033
|
+
const warned2 = (_b = ctx.store).__disabledWarned ?? (_b.__disabledWarned = /* @__PURE__ */ new Set());
|
|
15034
|
+
if (!warned2.has(request.phase)) {
|
|
15035
|
+
warned2.add(request.phase);
|
|
13245
15036
|
ctx.logger.warn(
|
|
13246
15037
|
`guardrail reports it is not active for the "${request.phase}" surface; nothing is being enforced there`
|
|
13247
15038
|
);
|
|
@@ -13738,7 +15529,7 @@ function safeJson(value) {
|
|
|
13738
15529
|
function matches(pattern, toolName) {
|
|
13739
15530
|
return typeof pattern === "string" ? pattern === toolName : pattern.test(toolName);
|
|
13740
15531
|
}
|
|
13741
|
-
function
|
|
15532
|
+
function asObject2(args) {
|
|
13742
15533
|
return args && typeof args === "object" ? args : {};
|
|
13743
15534
|
}
|
|
13744
15535
|
function toolPolicy(config = {}) {
|
|
@@ -13759,7 +15550,7 @@ function toolPolicy(config = {}) {
|
|
|
13759
15550
|
hooks: {
|
|
13760
15551
|
preToolUse: ({ toolName, args }, ctx) => {
|
|
13761
15552
|
var _a;
|
|
13762
|
-
const argObject =
|
|
15553
|
+
const argObject = asObject2(args);
|
|
13763
15554
|
const isControlPlane = CONTROL_PLANE_TOOL_NAMES.includes(toolName);
|
|
13764
15555
|
const allowListApplies = !isControlPlane || config.governControlPlaneTools === true;
|
|
13765
15556
|
if (config.allowOnly && allowListApplies && !config.allowOnly.some((pattern) => matches(pattern, toolName))) {
|
|
@@ -13821,7 +15612,7 @@ function pathSandbox(config) {
|
|
|
13821
15612
|
hooks: {
|
|
13822
15613
|
preToolUse: ({ toolName, args }) => {
|
|
13823
15614
|
if (config.tools && !config.tools.some((pattern) => matches(pattern, toolName))) return void 0;
|
|
13824
|
-
const argObject =
|
|
15615
|
+
const argObject = asObject2(args);
|
|
13825
15616
|
for (const key of argNames) {
|
|
13826
15617
|
const value = argObject[key];
|
|
13827
15618
|
if (typeof value !== "string" || value.length === 0) continue;
|
|
@@ -14589,7 +16380,7 @@ function mcp(config) {
|
|
|
14589
16380
|
}
|
|
14590
16381
|
|
|
14591
16382
|
// src/plugins/builtin/rateLimit.ts
|
|
14592
|
-
function
|
|
16383
|
+
function sleep2(ms, signal) {
|
|
14593
16384
|
return new Promise((resolve) => {
|
|
14594
16385
|
let timer;
|
|
14595
16386
|
const done = () => {
|
|
@@ -14646,7 +16437,7 @@ function rateLimit(config = {}) {
|
|
|
14646
16437
|
while (!attempt.ok) {
|
|
14647
16438
|
const remaining = deadline - Date.now();
|
|
14648
16439
|
if (!Number.isFinite(attempt.waitMs) || attempt.waitMs > remaining) break;
|
|
14649
|
-
await
|
|
16440
|
+
await sleep2(Math.max(1, attempt.waitMs), ctx.signal);
|
|
14650
16441
|
if (ctx.signal?.aborted) break;
|
|
14651
16442
|
attempt = consume(applicable);
|
|
14652
16443
|
}
|
|
@@ -15742,18 +17533,21 @@ function langfuseTracing(config = {}) {
|
|
|
15742
17533
|
}
|
|
15743
17534
|
|
|
15744
17535
|
// src/plugins/builtin/otel.ts
|
|
15745
|
-
function
|
|
15746
|
-
if (
|
|
15747
|
-
if (status === "error") return "error";
|
|
15748
|
-
return status === "paused" ? "in_progress" : "partial";
|
|
15749
|
-
}
|
|
15750
|
-
function otelTracing(config) {
|
|
15751
|
-
const endpoint = config.endpoint?.trim();
|
|
15752
|
-
if (!endpoint) {
|
|
17536
|
+
function otelTracing(config = {}) {
|
|
17537
|
+
if (config.endpoint !== void 0 && !config.endpoint.trim()) {
|
|
15753
17538
|
throw new Error("[agent-sdk] otelTracing requires a non-empty `endpoint`.");
|
|
15754
17539
|
}
|
|
17540
|
+
const name = config.name ?? "otel-tracing";
|
|
17541
|
+
let exporter;
|
|
17542
|
+
try {
|
|
17543
|
+
exporter = createOtlpExporter({ ...config, endpoint: config.endpoint?.trim(), name });
|
|
17544
|
+
} catch {
|
|
17545
|
+
throw new Error(
|
|
17546
|
+
"[agent-sdk] otelTracing requires a non-empty `endpoint` (or OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT in the environment)."
|
|
17547
|
+
);
|
|
17548
|
+
}
|
|
15755
17549
|
return {
|
|
15756
|
-
name
|
|
17550
|
+
name,
|
|
15757
17551
|
// Registers only the `sessionEnd` observer, and observers run concurrently,
|
|
15758
17552
|
// so this number orders nothing at runtime. It is set above checkpointing
|
|
15759
17553
|
// (900) to record intent: this plugin is the last thing interested in the
|
|
@@ -15761,67 +17555,41 @@ function otelTracing(config) {
|
|
|
15761
17555
|
priority: 950,
|
|
15762
17556
|
// Observability. A dropped export is a reporting gap, never a safety hole.
|
|
15763
17557
|
failureMode: "open",
|
|
17558
|
+
traceExporters: [exporter],
|
|
15764
17559
|
hooks: {
|
|
15765
|
-
sessionEnd: async (
|
|
17560
|
+
sessionEnd: async (_event, ctx) => {
|
|
15766
17561
|
const state = ctx.state;
|
|
15767
17562
|
const session = state.ctx?.__traceSession;
|
|
17563
|
+
if (isSubagentTraceScope(session)) return;
|
|
15768
17564
|
if (!session) {
|
|
15769
17565
|
const message = "otelTracing exported nothing: the agent has no trace session. Enable the SDK's tracing runtime with `tracing: { enabled: true }` \u2014 the plugin exports the session the runtime records, it does not record one itself.";
|
|
15770
17566
|
ctx.logger.warn(message);
|
|
15771
17567
|
ctx.emit({ type: "metadata", otelTracing: { exported: false, reason: message } });
|
|
15772
17568
|
return;
|
|
15773
17569
|
}
|
|
15774
|
-
const
|
|
15775
|
-
const
|
|
15776
|
-
|
|
15777
|
-
const
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
// `service.name` is read off `agent.name` inside the conversion, so
|
|
15786
|
-
// the override is applied here rather than by editing spans after.
|
|
15787
|
-
agent: {
|
|
15788
|
-
...session.agentInfo ?? {},
|
|
15789
|
-
name: config.serviceName ?? session.agentInfo?.name ?? session.configAgentName ?? ctx.agentName
|
|
15790
|
-
},
|
|
15791
|
-
metadata: session.configMetadata,
|
|
15792
|
-
// Carried only to satisfy the type: `traceSessionToOtlp` reads the
|
|
15793
|
-
// events, summary and identifiers, never the sink snapshot.
|
|
15794
|
-
config: { enabled: true, logData: session.resolvedConfig.logData, sink: { type: "otlp", endpoint } },
|
|
15795
|
-
summary: session.summary,
|
|
15796
|
-
events: session.events,
|
|
15797
|
-
status: toSessionStatus(status),
|
|
15798
|
-
errors
|
|
15799
|
-
};
|
|
15800
|
-
try {
|
|
15801
|
-
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
15802
|
-
if (!fetchFn) {
|
|
15803
|
-
ctx.logger.warn("otelTracing needs fetch to be available in this runtime; export skipped.");
|
|
15804
|
-
return;
|
|
15805
|
-
}
|
|
15806
|
-
const response = await fetchFn(endpoint, {
|
|
15807
|
-
method: "POST",
|
|
15808
|
-
headers: { "content-type": "application/json", ...config.headers ?? {} },
|
|
15809
|
-
body: JSON.stringify(traceSessionToOtlp(payload)),
|
|
15810
|
-
// The run is over, but a host that cancelled it should not be made
|
|
15811
|
-
// to wait on a collector that is refusing to answer.
|
|
15812
|
-
signal: ctx.signal
|
|
15813
|
-
});
|
|
15814
|
-
if (!response.ok) {
|
|
15815
|
-
ctx.logger.warn(`otelTracing export returned HTTP ${response.status}.`);
|
|
15816
|
-
return;
|
|
15817
|
-
}
|
|
15818
|
-
ctx.emit({
|
|
15819
|
-
type: "metadata",
|
|
15820
|
-
otelTracing: { exported: true, endpoint, spans: session.events.length + 1 }
|
|
15821
|
-
});
|
|
15822
|
-
} catch (err) {
|
|
15823
|
-
ctx.logger.warn("otelTracing export failed:", err instanceof Error ? err.message : err);
|
|
17570
|
+
const reports = (session.exportReports ?? []).filter((report2) => !report2.sink && report2.exporter === name);
|
|
17571
|
+
const report = reports[reports.length - 1];
|
|
17572
|
+
if (!report) return;
|
|
17573
|
+
const { result } = report;
|
|
17574
|
+
if (!result.ok) {
|
|
17575
|
+
ctx.logger.warn(`otelTracing export failed: ${result.error ?? "unknown error"}`);
|
|
17576
|
+
return;
|
|
17577
|
+
}
|
|
17578
|
+
if (result.skipped) {
|
|
17579
|
+
ctx.emit({ type: "metadata", otelTracing: { exported: false, reason: result.reason ?? "nothing to export" } });
|
|
17580
|
+
return;
|
|
15824
17581
|
}
|
|
17582
|
+
ctx.emit({
|
|
17583
|
+
type: "metadata",
|
|
17584
|
+
otelTracing: {
|
|
17585
|
+
exported: true,
|
|
17586
|
+
endpoint: report.endpoint,
|
|
17587
|
+
spans: result.spans,
|
|
17588
|
+
terminal: report.terminal,
|
|
17589
|
+
// A 200 that refused some spans: the collector's count and message.
|
|
17590
|
+
...result.partialSuccess ? { rejectedSpans: result.partialSuccess.rejectedSpans, ...result.partialSuccess.message ? { rejectionMessage: result.partialSuccess.message } : {} } : {}
|
|
17591
|
+
}
|
|
17592
|
+
});
|
|
15825
17593
|
}
|
|
15826
17594
|
}
|
|
15827
17595
|
};
|
|
@@ -18857,9 +20625,9 @@ function mapAnthropicStopReason(reason) {
|
|
|
18857
20625
|
return "stop";
|
|
18858
20626
|
}
|
|
18859
20627
|
}
|
|
18860
|
-
function safeJsonParse(
|
|
20628
|
+
function safeJsonParse(str2) {
|
|
18861
20629
|
try {
|
|
18862
|
-
return JSON.parse(
|
|
20630
|
+
return JSON.parse(str2);
|
|
18863
20631
|
} catch {
|
|
18864
20632
|
return {};
|
|
18865
20633
|
}
|
|
@@ -19729,9 +21497,9 @@ function mediaTypeToFormat(mediaType) {
|
|
|
19729
21497
|
};
|
|
19730
21498
|
return map[mediaType] ?? "png";
|
|
19731
21499
|
}
|
|
19732
|
-
function safeJsonParse2(
|
|
21500
|
+
function safeJsonParse2(str2) {
|
|
19733
21501
|
try {
|
|
19734
|
-
return JSON.parse(
|
|
21502
|
+
return JSON.parse(str2);
|
|
19735
21503
|
} catch {
|
|
19736
21504
|
return {};
|
|
19737
21505
|
}
|
|
@@ -20128,10 +21896,13 @@ var VertexProvider = class extends BaseProvider {
|
|
|
20128
21896
|
textParts.push(part.text);
|
|
20129
21897
|
}
|
|
20130
21898
|
} else if (part.functionCall) {
|
|
21899
|
+
const suppliedId = typeof part.functionCall.id === "string" && part.functionCall.id ? part.functionCall.id : void 0;
|
|
21900
|
+
const position = toolCallIdx++;
|
|
20131
21901
|
toolCalls.push({
|
|
20132
|
-
id: `call_${
|
|
21902
|
+
id: suppliedId ?? `call_${position}`,
|
|
20133
21903
|
name: part.functionCall.name,
|
|
20134
21904
|
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
21905
|
+
...suppliedId ? {} : { idSynthesized: true },
|
|
20135
21906
|
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
20136
21907
|
});
|
|
20137
21908
|
}
|
|
@@ -20171,12 +21942,15 @@ var VertexProvider = class extends BaseProvider {
|
|
|
20171
21942
|
}
|
|
20172
21943
|
} else if (part.functionCall) {
|
|
20173
21944
|
if (!delta.toolCalls) delta.toolCalls = [];
|
|
21945
|
+
const suppliedId = typeof part.functionCall.id === "string" && part.functionCall.id ? part.functionCall.id : void 0;
|
|
21946
|
+
const position = counter.next++;
|
|
20174
21947
|
delta.toolCalls.push({
|
|
20175
21948
|
// Unique across the whole stream: the adapter merges chunks by id.
|
|
20176
|
-
id: `call_${
|
|
20177
|
-
index:
|
|
21949
|
+
id: suppliedId ?? `call_${position}`,
|
|
21950
|
+
index: position,
|
|
20178
21951
|
name: part.functionCall.name,
|
|
20179
21952
|
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
21953
|
+
...suppliedId ? {} : { idSynthesized: true },
|
|
20180
21954
|
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
20181
21955
|
});
|
|
20182
21956
|
}
|
|
@@ -20229,12 +22003,12 @@ function mapGeminiFinishReason(reason) {
|
|
|
20229
22003
|
return "stop";
|
|
20230
22004
|
}
|
|
20231
22005
|
}
|
|
20232
|
-
function base64url(
|
|
20233
|
-
return Buffer.from(
|
|
22006
|
+
function base64url(str2) {
|
|
22007
|
+
return Buffer.from(str2).toString("base64url");
|
|
20234
22008
|
}
|
|
20235
|
-
function safeJsonParse3(
|
|
22009
|
+
function safeJsonParse3(str2) {
|
|
20236
22010
|
try {
|
|
20237
|
-
return JSON.parse(
|
|
22011
|
+
return JSON.parse(str2);
|
|
20238
22012
|
} catch {
|
|
20239
22013
|
return {};
|
|
20240
22014
|
}
|
|
@@ -20279,6 +22053,7 @@ exports.DEFAULT_SUBAGENT_TOOL_NAMES = DEFAULT_SUBAGENT_TOOL_NAMES;
|
|
|
20279
22053
|
exports.DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS = DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS;
|
|
20280
22054
|
exports.DELEGATION_TOOL_NAMES = DELEGATION_TOOL_NAMES;
|
|
20281
22055
|
exports.DedupTracker = DedupTracker;
|
|
22056
|
+
exports.GENAI_SEMCONV_COMMIT = GENAI_SEMCONV_COMMIT;
|
|
20282
22057
|
exports.GuardrailPhase = GuardrailPhase;
|
|
20283
22058
|
exports.HOOK_CONTRACT_VERSION = HOOK_CONTRACT_VERSION;
|
|
20284
22059
|
exports.HOOK_NAMES = HOOK_NAMES;
|
|
@@ -20319,6 +22094,7 @@ exports.canSpawn = canSpawn;
|
|
|
20319
22094
|
exports.captureSnapshot = captureSnapshot;
|
|
20320
22095
|
exports.checkpointing = checkpointing;
|
|
20321
22096
|
exports.clearLearnedModelRules = clearLearnedModelRules;
|
|
22097
|
+
exports.closeTraceContinuation = closeTraceContinuation;
|
|
20322
22098
|
exports.codePresenceRule = codePresenceRule;
|
|
20323
22099
|
exports.coerceToolArgs = coerceToolArgs;
|
|
20324
22100
|
exports.cognipeerGuardrail = cognipeerGuardrail;
|
|
@@ -20353,6 +22129,7 @@ exports.createJsonGuardrail = createJsonGuardrail;
|
|
|
20353
22129
|
exports.createManageTodoListAliasTool = createManageTodoListAliasTool;
|
|
20354
22130
|
exports.createManageTodoTool = createManageTodoTool;
|
|
20355
22131
|
exports.createOpenSkillTool = createOpenSkillTool;
|
|
22132
|
+
exports.createOtlpExporter = createOtlpExporter;
|
|
20356
22133
|
exports.createParallelTool = createParallelTool;
|
|
20357
22134
|
exports.createPluginHost = createPluginHost;
|
|
20358
22135
|
exports.createProvider = createProvider;
|
|
@@ -20389,6 +22166,8 @@ exports.extractMessageText = extractMessageText;
|
|
|
20389
22166
|
exports.fileCheckpointStore = fileCheckpointStore;
|
|
20390
22167
|
exports.fileSink = fileSink;
|
|
20391
22168
|
exports.findSubagent = findSubagent;
|
|
22169
|
+
exports.foldSupersededSpans = foldSupersededSpans;
|
|
22170
|
+
exports.formatTraceparent = formatTraceparent;
|
|
20392
22171
|
exports.formatZodError = formatZodError;
|
|
20393
22172
|
exports.fromLangchainModel = fromLangchainModel;
|
|
20394
22173
|
exports.fromLangchainTools = fromLangchainTools;
|
|
@@ -20436,6 +22215,7 @@ exports.outputGuard = outputGuard;
|
|
|
20436
22215
|
exports.parseApprovalDecision = parseApprovalDecision;
|
|
20437
22216
|
exports.parseModelError = parseModelError;
|
|
20438
22217
|
exports.parseSkillFrontmatter = parseSkillFrontmatter;
|
|
22218
|
+
exports.parseTraceparent = parseTraceparent;
|
|
20439
22219
|
exports.pathSandbox = pathSandbox;
|
|
20440
22220
|
exports.piiRedaction = piiRedaction;
|
|
20441
22221
|
exports.pluginCapabilities = pluginCapabilities;
|
|
@@ -20490,6 +22270,7 @@ exports.toolPolicy = toolPolicy;
|
|
|
20490
22270
|
exports.traceContinuationOf = traceContinuationOf;
|
|
20491
22271
|
exports.traceSectionsFromMessages = traceSectionsFromMessages;
|
|
20492
22272
|
exports.traceSessionToOtlp = traceSessionToOtlp;
|
|
22273
|
+
exports.traceparentOf = traceparentOf;
|
|
20493
22274
|
exports.validateReasoningConfig = validateReasoningConfig;
|
|
20494
22275
|
exports.validateToolArgs = validateToolArgs;
|
|
20495
22276
|
exports.webhookApproval = webhookApproval;
|