@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.mjs
CHANGED
|
@@ -6,6 +6,8 @@ import path from 'path';
|
|
|
6
6
|
import { Buffer as Buffer$1 } from 'buffer';
|
|
7
7
|
import { nanoid } from 'nanoid';
|
|
8
8
|
import crypto, { createHash, randomUUID, createHmac } from 'crypto';
|
|
9
|
+
import { gzip } from 'zlib';
|
|
10
|
+
import { promisify } from 'util';
|
|
9
11
|
import AjvModule from 'ajv';
|
|
10
12
|
|
|
11
13
|
var __defProp = Object.defineProperty;
|
|
@@ -1221,9 +1223,1398 @@ function splitUsage(usage) {
|
|
|
1221
1223
|
}
|
|
1222
1224
|
return { own, subagent, ownCalls: ownEntries.length, subagentCalls: subagentEntries.length, ownEntries, subagentEntries };
|
|
1223
1225
|
}
|
|
1226
|
+
function cacheWriteTokensOf(raw) {
|
|
1227
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
1228
|
+
const details = raw.prompt_tokens_details || raw.promptTokensDetails || raw.input_token_details || raw.inputTokenDetails || {};
|
|
1229
|
+
const candidates = [
|
|
1230
|
+
details.cache_write_tokens,
|
|
1231
|
+
details.cacheWriteTokens,
|
|
1232
|
+
details.cache_creation,
|
|
1233
|
+
raw.cache_write_tokens,
|
|
1234
|
+
raw.cacheWriteTokens,
|
|
1235
|
+
raw.cache_creation_input_tokens,
|
|
1236
|
+
raw.cacheCreationInputTokens,
|
|
1237
|
+
raw.cacheWriteInputTokens,
|
|
1238
|
+
raw.cacheWriteInputTokenCount
|
|
1239
|
+
];
|
|
1240
|
+
for (const value of candidates) {
|
|
1241
|
+
const n = Number(value);
|
|
1242
|
+
if (Number.isFinite(n) && n > 0) return n;
|
|
1243
|
+
}
|
|
1244
|
+
return void 0;
|
|
1245
|
+
}
|
|
1224
1246
|
|
|
1225
1247
|
// src/utils/tracing.ts
|
|
1226
1248
|
init_content();
|
|
1249
|
+
|
|
1250
|
+
// src/version.ts
|
|
1251
|
+
var SDK_VERSION = "0.18.0";
|
|
1252
|
+
|
|
1253
|
+
// src/utils/otlp/content.ts
|
|
1254
|
+
init_content();
|
|
1255
|
+
|
|
1256
|
+
// src/utils/otlp/semconv.ts
|
|
1257
|
+
var GENAI_SEMCONV_COMMIT = "547934a";
|
|
1258
|
+
var ATTR = {
|
|
1259
|
+
operationName: "gen_ai.operation.name",
|
|
1260
|
+
providerName: "gen_ai.provider.name",
|
|
1261
|
+
requestModel: "gen_ai.request.model",
|
|
1262
|
+
responseModel: "gen_ai.response.model",
|
|
1263
|
+
responseId: "gen_ai.response.id",
|
|
1264
|
+
finishReasons: "gen_ai.response.finish_reasons",
|
|
1265
|
+
requestStream: "gen_ai.request.stream",
|
|
1266
|
+
outputType: "gen_ai.output.type",
|
|
1267
|
+
conversationId: "gen_ai.conversation.id",
|
|
1268
|
+
agentName: "gen_ai.agent.name",
|
|
1269
|
+
agentVersion: "gen_ai.agent.version",
|
|
1270
|
+
toolName: "gen_ai.tool.name",
|
|
1271
|
+
toolCallId: "gen_ai.tool.call.id",
|
|
1272
|
+
toolType: "gen_ai.tool.type",
|
|
1273
|
+
usageInput: "gen_ai.usage.input_tokens",
|
|
1274
|
+
usageOutput: "gen_ai.usage.output_tokens",
|
|
1275
|
+
usageCacheRead: "gen_ai.usage.cache_read.input_tokens",
|
|
1276
|
+
usageCacheWrite: "gen_ai.usage.cache_write.input_tokens",
|
|
1277
|
+
usageReasoning: "gen_ai.usage.reasoning.output_tokens",
|
|
1278
|
+
errorType: "error.type",
|
|
1279
|
+
// Content (opt-in).
|
|
1280
|
+
systemInstructions: "gen_ai.system_instructions",
|
|
1281
|
+
inputMessages: "gen_ai.input.messages",
|
|
1282
|
+
outputMessages: "gen_ai.output.messages",
|
|
1283
|
+
toolDefinitions: "gen_ai.tool.definitions",
|
|
1284
|
+
toolCallArguments: "gen_ai.tool.call.arguments",
|
|
1285
|
+
toolCallResult: "gen_ai.tool.call.result"
|
|
1286
|
+
};
|
|
1287
|
+
var OPERATION = {
|
|
1288
|
+
chat: "chat",
|
|
1289
|
+
executeTool: "execute_tool",
|
|
1290
|
+
invokeAgent: "invoke_agent"
|
|
1291
|
+
};
|
|
1292
|
+
var PROVIDERS = {
|
|
1293
|
+
openai: "openai",
|
|
1294
|
+
chatopenai: "openai",
|
|
1295
|
+
azure: "azure.ai.openai",
|
|
1296
|
+
azureopenai: "azure.ai.openai",
|
|
1297
|
+
azurechatopenai: "azure.ai.openai",
|
|
1298
|
+
azureaiopenai: "azure.ai.openai",
|
|
1299
|
+
azureaiinference: "azure.ai.inference",
|
|
1300
|
+
anthropic: "anthropic",
|
|
1301
|
+
chatanthropic: "anthropic",
|
|
1302
|
+
bedrock: "aws.bedrock",
|
|
1303
|
+
awsbedrock: "aws.bedrock",
|
|
1304
|
+
chatbedrock: "aws.bedrock",
|
|
1305
|
+
chatbedrockconverse: "aws.bedrock",
|
|
1306
|
+
vertex: "gcp.vertex_ai",
|
|
1307
|
+
vertexai: "gcp.vertex_ai",
|
|
1308
|
+
gcpvertexai: "gcp.vertex_ai",
|
|
1309
|
+
chatvertexai: "gcp.vertex_ai",
|
|
1310
|
+
gemini: "gcp.gemini",
|
|
1311
|
+
gcpgemini: "gcp.gemini",
|
|
1312
|
+
chatgooglegenerativeai: "gcp.gemini",
|
|
1313
|
+
// Gemini API or Vertex: the name alone does not say which.
|
|
1314
|
+
google: "gcp.gen_ai",
|
|
1315
|
+
gcpgenai: "gcp.gen_ai",
|
|
1316
|
+
mistral: "mistral",
|
|
1317
|
+
mistralai: "mistral",
|
|
1318
|
+
chatmistralai: "mistral",
|
|
1319
|
+
groq: "groq",
|
|
1320
|
+
chatgroq: "groq",
|
|
1321
|
+
deepseek: "deepseek",
|
|
1322
|
+
chatdeepseek: "deepseek",
|
|
1323
|
+
cohere: "cohere",
|
|
1324
|
+
chatcohere: "cohere",
|
|
1325
|
+
xai: "x_ai",
|
|
1326
|
+
chatxai: "x_ai",
|
|
1327
|
+
perplexity: "perplexity",
|
|
1328
|
+
chatperplexity: "perplexity",
|
|
1329
|
+
watsonx: "ibm.watsonx.ai",
|
|
1330
|
+
ibmwatsonxai: "ibm.watsonx.ai"
|
|
1331
|
+
};
|
|
1332
|
+
function genAiProviderName(hint) {
|
|
1333
|
+
if (!hint) return void 0;
|
|
1334
|
+
const key = hint.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1335
|
+
return key ? PROVIDERS[key] : void 0;
|
|
1336
|
+
}
|
|
1337
|
+
function errorTypeOf(error) {
|
|
1338
|
+
if (!error) return "_OTHER";
|
|
1339
|
+
if (typeof error.type === "string" && error.type.length > 0) return error.type;
|
|
1340
|
+
if (typeof error.stack === "string") {
|
|
1341
|
+
const match = /^\s*([A-Za-z_$][\w$.]*)\s*(?::|$)/m.exec(error.stack.split("\n", 1)[0] ?? "");
|
|
1342
|
+
if (match) return match[1];
|
|
1343
|
+
}
|
|
1344
|
+
return "_OTHER";
|
|
1345
|
+
}
|
|
1346
|
+
function genAiUsageOf(event) {
|
|
1347
|
+
const num2 = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
|
|
1348
|
+
const input = num2(event.inputTokens);
|
|
1349
|
+
const output = num2(event.outputTokens);
|
|
1350
|
+
const cacheRead = num2(event.cachedInputTokens);
|
|
1351
|
+
const cacheWrite = num2(event.cacheWriteTokens);
|
|
1352
|
+
const reasoning = num2(event.reasoningTokens);
|
|
1353
|
+
if (input + output + cacheRead + cacheWrite + reasoning + num2(event.totalTokens) === 0) return void 0;
|
|
1354
|
+
const basis = event.usageBasis ?? {};
|
|
1355
|
+
return {
|
|
1356
|
+
input: basis.inputExcludesCache ? input + cacheRead + cacheWrite : input,
|
|
1357
|
+
output: basis.outputExcludesReasoning ? output + reasoning : output,
|
|
1358
|
+
...cacheRead > 0 ? { cacheRead } : {},
|
|
1359
|
+
...cacheWrite > 0 ? { cacheWrite } : {},
|
|
1360
|
+
...reasoning > 0 ? { reasoning } : {}
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// src/utils/otlp/content.ts
|
|
1365
|
+
var CAPTURE = Symbol.for("cognipeer.agent-sdk.traceCapture");
|
|
1366
|
+
var DEFAULTS = {
|
|
1367
|
+
maxStringChars: 4096,
|
|
1368
|
+
maxMessages: 32,
|
|
1369
|
+
maxAttributeBytes: 32768
|
|
1370
|
+
};
|
|
1371
|
+
var FIELDS = ["system", "input", "output", "tools", "toolArgs", "toolResults", "sections"];
|
|
1372
|
+
function resolveContentOptions(content) {
|
|
1373
|
+
const given = typeof content === "object" && content !== null ? content : {};
|
|
1374
|
+
const enabled = typeof content === "boolean" ? content : given.enabled === true;
|
|
1375
|
+
const positive = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : fallback;
|
|
1376
|
+
return {
|
|
1377
|
+
enabled,
|
|
1378
|
+
include: Array.isArray(given.include) ? given.include.filter((field) => FIELDS.includes(field)) : [...FIELDS],
|
|
1379
|
+
maxStringChars: positive(given.maxStringChars, DEFAULTS.maxStringChars),
|
|
1380
|
+
maxMessages: positive(given.maxMessages, DEFAULTS.maxMessages),
|
|
1381
|
+
maxAttributeBytes: positive(given.maxAttributeBytes, DEFAULTS.maxAttributeBytes),
|
|
1382
|
+
redact: typeof given.redact === "function" ? given.redact : void 0,
|
|
1383
|
+
encoding: given.encoding === "structured" ? "structured" : "json"
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1387
|
+
function plain(value) {
|
|
1388
|
+
if (value === void 0) return void 0;
|
|
1389
|
+
try {
|
|
1390
|
+
const text = JSON.stringify(value);
|
|
1391
|
+
return text === void 0 ? void 0 : JSON.parse(text);
|
|
1392
|
+
} catch {
|
|
1393
|
+
return void 0;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
var TRUNCATED_MARKER = /\.\.\.\[truncated (\d+) chars\]$/;
|
|
1397
|
+
function truncateText(text, max) {
|
|
1398
|
+
const earlier = TRUNCATED_MARKER.exec(text);
|
|
1399
|
+
const body = earlier ? text.slice(0, earlier.index) : text;
|
|
1400
|
+
if (body.length <= max) return text;
|
|
1401
|
+
const lost = body.length - max + (earlier ? Number(earlier[1]) : 0);
|
|
1402
|
+
return `${body.slice(0, max)}...[truncated ${lost} chars]`;
|
|
1403
|
+
}
|
|
1404
|
+
function capStrings(value, max) {
|
|
1405
|
+
if (typeof value === "string") return truncateText(value, max);
|
|
1406
|
+
if (Array.isArray(value)) return value.map((item) => capStrings(item, max));
|
|
1407
|
+
if (isRecord2(value)) {
|
|
1408
|
+
const out = {};
|
|
1409
|
+
for (const [key, item] of Object.entries(value)) out[key] = capStrings(item, max);
|
|
1410
|
+
return out;
|
|
1411
|
+
}
|
|
1412
|
+
return value;
|
|
1413
|
+
}
|
|
1414
|
+
function asObject(value) {
|
|
1415
|
+
let parsed = value;
|
|
1416
|
+
if (typeof value === "string") {
|
|
1417
|
+
try {
|
|
1418
|
+
parsed = JSON.parse(value);
|
|
1419
|
+
} catch {
|
|
1420
|
+
parsed = value;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
const copy = plain(parsed);
|
|
1424
|
+
if (copy === void 0) return void 0;
|
|
1425
|
+
return isRecord2(copy) ? copy : { value: copy };
|
|
1426
|
+
}
|
|
1427
|
+
var REASONING_PART_TYPES = /* @__PURE__ */ new Set(["thinking", "redacted_thinking", "reasoning", "reasoning_content"]);
|
|
1428
|
+
function textOf(content) {
|
|
1429
|
+
if (content == null) return "";
|
|
1430
|
+
if (typeof content === "string") return content;
|
|
1431
|
+
if (!Array.isArray(content)) return contentPartToText(content, () => "");
|
|
1432
|
+
return content.filter((part) => !(isRecord2(part) && REASONING_PART_TYPES.has(String(part.type)))).map((part) => contentPartToText(part, () => "")).filter((text) => text.length > 0).join("\n");
|
|
1433
|
+
}
|
|
1434
|
+
function toolCallPartsOf(message) {
|
|
1435
|
+
const calls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
|
|
1436
|
+
const parts = [];
|
|
1437
|
+
for (const call of calls) {
|
|
1438
|
+
if (!isRecord2(call)) continue;
|
|
1439
|
+
const name = call.name ?? call.function?.name;
|
|
1440
|
+
if (typeof name !== "string" || !name) continue;
|
|
1441
|
+
const args = call.args ?? call.arguments ?? call.function?.arguments;
|
|
1442
|
+
const coerced = asObject(args ?? {});
|
|
1443
|
+
const id = typeof call.id === "string" && call.id && !call.idSynthesized ? call.id : void 0;
|
|
1444
|
+
parts.push({ type: "tool_call", ...id ? { id } : {}, name, arguments: coerced ?? {} });
|
|
1445
|
+
}
|
|
1446
|
+
return parts;
|
|
1447
|
+
}
|
|
1448
|
+
function messageOf(raw) {
|
|
1449
|
+
if (!isRecord2(raw)) return void 0;
|
|
1450
|
+
const role = typeof raw.role === "string" ? raw.role : "user";
|
|
1451
|
+
const parts = [];
|
|
1452
|
+
if (role === "tool") {
|
|
1453
|
+
const text2 = textOf(raw.content);
|
|
1454
|
+
const parsed = (() => {
|
|
1455
|
+
try {
|
|
1456
|
+
return JSON.parse(text2);
|
|
1457
|
+
} catch {
|
|
1458
|
+
return text2;
|
|
1459
|
+
}
|
|
1460
|
+
})();
|
|
1461
|
+
parts.push({
|
|
1462
|
+
type: "tool_call_response",
|
|
1463
|
+
...typeof raw.tool_call_id === "string" && raw.tool_call_id ? { id: raw.tool_call_id } : {},
|
|
1464
|
+
response: plain(parsed) ?? text2
|
|
1465
|
+
});
|
|
1466
|
+
return { role, parts, ...typeof raw.name === "string" && raw.name ? { name: raw.name } : {} };
|
|
1467
|
+
}
|
|
1468
|
+
const text = textOf(raw.content);
|
|
1469
|
+
if (text) parts.push({ type: "text", content: text });
|
|
1470
|
+
if (role === "assistant") parts.push(...toolCallPartsOf(raw));
|
|
1471
|
+
if (parts.length === 0 && role !== "assistant") parts.push({ type: "text", content: "" });
|
|
1472
|
+
return { role, parts };
|
|
1473
|
+
}
|
|
1474
|
+
function buildCapturedContent(source, limits) {
|
|
1475
|
+
const out = {};
|
|
1476
|
+
if (Array.isArray(source.input)) {
|
|
1477
|
+
const system = [];
|
|
1478
|
+
const messages = [];
|
|
1479
|
+
for (const raw of source.input) {
|
|
1480
|
+
const message = messageOf(raw);
|
|
1481
|
+
if (!message) continue;
|
|
1482
|
+
if (message.role === "system") {
|
|
1483
|
+
const content = message.parts.map((part) => part.type === "text" ? part.content : "").join("\n");
|
|
1484
|
+
if (content) system.push({ type: "text", content });
|
|
1485
|
+
} else {
|
|
1486
|
+
messages.push(message);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
if (system.length > 0) out.system = capStrings(system, limits.maxStringChars);
|
|
1490
|
+
const recent = messages.slice(-limits.maxMessages);
|
|
1491
|
+
out.input = capStrings(recent, limits.maxStringChars);
|
|
1492
|
+
}
|
|
1493
|
+
if (source.output !== void 0 && source.output !== null) {
|
|
1494
|
+
const message = messageOf({ ...isRecord2(source.output) ? source.output : { content: String(source.output) }, role: "assistant" });
|
|
1495
|
+
if (message) out.output = capStrings(message, limits.maxStringChars);
|
|
1496
|
+
}
|
|
1497
|
+
if (Array.isArray(source.toolDefinitions) && source.toolDefinitions.length > 0) {
|
|
1498
|
+
out.tools = capStrings(
|
|
1499
|
+
source.toolDefinitions.filter((tool) => tool && typeof tool.name === "string").map((tool) => ({
|
|
1500
|
+
type: "function",
|
|
1501
|
+
name: tool.name,
|
|
1502
|
+
...tool.description ? { description: tool.description } : {},
|
|
1503
|
+
...tool.parameters !== void 0 ? { parameters: plain(tool.parameters) } : {}
|
|
1504
|
+
})),
|
|
1505
|
+
limits.maxStringChars
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
if (source.toolArguments !== void 0) {
|
|
1509
|
+
const args = asObject(source.toolArguments);
|
|
1510
|
+
if (args !== void 0) out.toolArgs = capStrings(args, limits.maxStringChars);
|
|
1511
|
+
}
|
|
1512
|
+
if (source.hasToolResult || source.toolResult !== void 0) {
|
|
1513
|
+
const result = asObject(source.toolResult);
|
|
1514
|
+
if (result !== void 0) out.toolResults = capStrings(result, limits.maxStringChars);
|
|
1515
|
+
}
|
|
1516
|
+
return out;
|
|
1517
|
+
}
|
|
1518
|
+
function capturedContentOf(event) {
|
|
1519
|
+
return event?.[CAPTURE];
|
|
1520
|
+
}
|
|
1521
|
+
function attachCapturedContent(record, content) {
|
|
1522
|
+
Object.defineProperty(record, CAPTURE, { value: content, enumerable: false, configurable: true, writable: true });
|
|
1523
|
+
}
|
|
1524
|
+
var SEPARATE_SYSTEM = /* @__PURE__ */ new Set(["anthropic", "aws.bedrock", "gcp.vertex_ai", "gcp.gemini"]);
|
|
1525
|
+
function toAnyValue(value) {
|
|
1526
|
+
if (value === null || value === void 0) return void 0;
|
|
1527
|
+
if (typeof value === "string") return { stringValue: value };
|
|
1528
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
1529
|
+
if (typeof value === "number") {
|
|
1530
|
+
if (!Number.isFinite(value)) return void 0;
|
|
1531
|
+
return Number.isInteger(value) && Number.isSafeInteger(value) ? { intValue: String(value) } : { doubleValue: value };
|
|
1532
|
+
}
|
|
1533
|
+
if (Array.isArray(value)) {
|
|
1534
|
+
return { arrayValue: { values: value.map((item) => toAnyValue(item) ?? { stringValue: "" }) } };
|
|
1535
|
+
}
|
|
1536
|
+
if (isRecord2(value)) {
|
|
1537
|
+
const values = [];
|
|
1538
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1539
|
+
const any = toAnyValue(item);
|
|
1540
|
+
if (any) values.push({ key, value: any });
|
|
1541
|
+
}
|
|
1542
|
+
return { kvlistValue: { values } };
|
|
1543
|
+
}
|
|
1544
|
+
return void 0;
|
|
1545
|
+
}
|
|
1546
|
+
var byteLength = (text) => Buffer$1.byteLength(text, "utf8");
|
|
1547
|
+
function render(value, field, options, info) {
|
|
1548
|
+
let working = plain(value);
|
|
1549
|
+
if (working === void 0) return void 0;
|
|
1550
|
+
if (options.redact) {
|
|
1551
|
+
try {
|
|
1552
|
+
working = options.redact(plain(working), { field, ...info });
|
|
1553
|
+
} catch {
|
|
1554
|
+
return void 0;
|
|
1555
|
+
}
|
|
1556
|
+
working = plain(working);
|
|
1557
|
+
if (working === void 0 || working === null) return void 0;
|
|
1558
|
+
}
|
|
1559
|
+
working = capStrings(working, options.maxStringChars);
|
|
1560
|
+
if ((field === "input" || field === "system" || field === "sections") && Array.isArray(working) && working.length > options.maxMessages) {
|
|
1561
|
+
working = working.slice(-options.maxMessages);
|
|
1562
|
+
}
|
|
1563
|
+
let text = JSON.stringify(working);
|
|
1564
|
+
if (text === void 0) return void 0;
|
|
1565
|
+
if (byteLength(text) > options.maxAttributeBytes) {
|
|
1566
|
+
if (field === "input" && Array.isArray(working)) {
|
|
1567
|
+
const messages = [...working];
|
|
1568
|
+
while (messages.length > 1 && byteLength(JSON.stringify(messages)) > options.maxAttributeBytes) messages.shift();
|
|
1569
|
+
working = messages;
|
|
1570
|
+
text = JSON.stringify(working);
|
|
1571
|
+
}
|
|
1572
|
+
if (byteLength(text) > options.maxAttributeBytes) {
|
|
1573
|
+
working = { truncated: true };
|
|
1574
|
+
text = JSON.stringify(working);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
return options.encoding === "structured" ? toAnyValue(working) : { stringValue: text };
|
|
1578
|
+
}
|
|
1579
|
+
function contentAttributes(kind, event, provider, options) {
|
|
1580
|
+
if (!options?.enabled) return [];
|
|
1581
|
+
const captured = capturedContentOf(event);
|
|
1582
|
+
if (!captured) return [];
|
|
1583
|
+
const include = new Set(options.include);
|
|
1584
|
+
const info = {
|
|
1585
|
+
eventType: event.type,
|
|
1586
|
+
...event.spanId ? { spanId: event.spanId } : {},
|
|
1587
|
+
...kind === "execute_tool" && event.actor?.name ? { toolName: event.actor.name } : {},
|
|
1588
|
+
...event.model ? { model: event.model } : {}
|
|
1589
|
+
};
|
|
1590
|
+
const attrs = [];
|
|
1591
|
+
const add = (key, value) => {
|
|
1592
|
+
if (value) attrs.push({ key, value });
|
|
1593
|
+
};
|
|
1594
|
+
if (kind === "chat") {
|
|
1595
|
+
const separate = provider !== void 0 && SEPARATE_SYSTEM.has(provider);
|
|
1596
|
+
const system = captured.system ?? [];
|
|
1597
|
+
if (separate) {
|
|
1598
|
+
if (include.has("system") && system.length > 0) add(ATTR.systemInstructions, render(system, "system", options, info));
|
|
1599
|
+
if (include.has("input") && captured.input) add(ATTR.inputMessages, render(captured.input, "input", options, info));
|
|
1600
|
+
} else if (include.has("input") && (captured.input || system.length > 0)) {
|
|
1601
|
+
const messages = captured.input ?? [];
|
|
1602
|
+
const capped = messages.slice(-options.maxMessages);
|
|
1603
|
+
const withSystem = system.length > 0 ? [{ role: "system", parts: system }, ...capped] : capped;
|
|
1604
|
+
add(ATTR.inputMessages, render(withSystem, "input", { ...options, maxMessages: options.maxMessages + 1 }, info));
|
|
1605
|
+
}
|
|
1606
|
+
if (include.has("output") && captured.output) {
|
|
1607
|
+
const reason = event.rawFinishReason ?? event.finishReason;
|
|
1608
|
+
const finish = reason === "tool_calls" ? "tool_call" : reason;
|
|
1609
|
+
add(ATTR.outputMessages, render([{ ...captured.output, ...finish ? { finish_reason: finish } : {} }], "output", options, info));
|
|
1610
|
+
}
|
|
1611
|
+
if (include.has("tools") && captured.tools) add(ATTR.toolDefinitions, render(captured.tools, "tools", options, info));
|
|
1612
|
+
} else {
|
|
1613
|
+
if (include.has("toolArgs") && captured.toolArgs !== void 0) add(ATTR.toolCallArguments, render(captured.toolArgs, "toolArgs", options, info));
|
|
1614
|
+
if (include.has("toolResults") && captured.toolResults !== void 0) add(ATTR.toolCallResult, render(captured.toolResults, "toolResults", options, info));
|
|
1615
|
+
}
|
|
1616
|
+
return attrs;
|
|
1617
|
+
}
|
|
1618
|
+
function sectionsAttribute(sections, event, options) {
|
|
1619
|
+
if (!sections || sections.length === 0) return void 0;
|
|
1620
|
+
const identity2 = sections.filter((section) => section.identity === true);
|
|
1621
|
+
const payload = sections.filter((section) => section.identity !== true);
|
|
1622
|
+
let kept = [];
|
|
1623
|
+
if (options?.enabled && options.include.includes("sections") && payload.length > 0) {
|
|
1624
|
+
kept = redactedSections(payload, options, event);
|
|
1625
|
+
}
|
|
1626
|
+
const max = options?.maxAttributeBytes ?? DEFAULTS.maxAttributeBytes;
|
|
1627
|
+
const encode = (list) => {
|
|
1628
|
+
try {
|
|
1629
|
+
return JSON.stringify(list);
|
|
1630
|
+
} catch {
|
|
1631
|
+
return void 0;
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
let text = encode([...identity2, ...kept]);
|
|
1635
|
+
while (text !== void 0 && kept.length > 0 && byteLength(text) > max) {
|
|
1636
|
+
kept.shift();
|
|
1637
|
+
text = encode([...identity2, ...kept]);
|
|
1638
|
+
}
|
|
1639
|
+
if (text === void 0) {
|
|
1640
|
+
text = encode(identity2);
|
|
1641
|
+
}
|
|
1642
|
+
if (text === void 0 || text === "[]") return void 0;
|
|
1643
|
+
return { key: "cognipeer.sections", value: { stringValue: text } };
|
|
1644
|
+
}
|
|
1645
|
+
function redactedSections(payload, options, event) {
|
|
1646
|
+
let working = plain(payload);
|
|
1647
|
+
if (working === void 0) return [];
|
|
1648
|
+
if (options.redact) {
|
|
1649
|
+
try {
|
|
1650
|
+
working = plain(options.redact(plain(working), {
|
|
1651
|
+
field: "sections",
|
|
1652
|
+
eventType: event.type,
|
|
1653
|
+
...event.spanId ? { spanId: event.spanId } : {},
|
|
1654
|
+
...event.model ? { model: event.model } : {}
|
|
1655
|
+
}));
|
|
1656
|
+
} catch {
|
|
1657
|
+
return [];
|
|
1658
|
+
}
|
|
1659
|
+
if (!Array.isArray(working)) return [];
|
|
1660
|
+
}
|
|
1661
|
+
const capped = capStrings(working, options.maxStringChars);
|
|
1662
|
+
return Array.isArray(capped) ? capped.slice(-options.maxMessages) : [];
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// src/utils/otlp/convert.ts
|
|
1666
|
+
var SCOPE_NAME = "cognipeer-agent-sdk";
|
|
1667
|
+
var SPAN_KIND_INTERNAL = 1;
|
|
1668
|
+
var SPAN_KIND_CLIENT = 3;
|
|
1669
|
+
var FLAG_HAS_PARENT = 256;
|
|
1670
|
+
var FLAG_REMOTE_PARENT = 512;
|
|
1671
|
+
var MAX_STATUS_MESSAGE = 1024;
|
|
1672
|
+
var str = (key, value) => value != null && value !== "" ? { key, value: { stringValue: value } } : null;
|
|
1673
|
+
var strAllowEmpty = (key, value) => value != null ? { key, value: { stringValue: value } } : null;
|
|
1674
|
+
var int = (key, value) => typeof value === "number" && Number.isFinite(value) ? { key, value: { intValue: String(Math.trunc(value)) } } : null;
|
|
1675
|
+
var dbl = (key, value) => typeof value === "number" && Number.isFinite(value) ? { key, value: { doubleValue: value } } : null;
|
|
1676
|
+
var bool = (key, value) => typeof value === "boolean" ? { key, value: { boolValue: value } } : null;
|
|
1677
|
+
var strArray = (key, values) => ({
|
|
1678
|
+
key,
|
|
1679
|
+
value: { arrayValue: { values: values.map((value) => ({ stringValue: value })) } }
|
|
1680
|
+
});
|
|
1681
|
+
var compact = (list) => list.filter((entry) => Boolean(entry));
|
|
1682
|
+
function msToNs(ms) {
|
|
1683
|
+
const whole = Math.floor(ms);
|
|
1684
|
+
return BigInt(whole) * 1000000n + BigInt(Math.round((ms - whole) * 1e6));
|
|
1685
|
+
}
|
|
1686
|
+
function parseMs(iso) {
|
|
1687
|
+
if (!iso) return void 0;
|
|
1688
|
+
const value = Date.parse(iso);
|
|
1689
|
+
return Number.isNaN(value) ? void 0 : value;
|
|
1690
|
+
}
|
|
1691
|
+
function durationNs(durationMs) {
|
|
1692
|
+
return typeof durationMs === "number" && Number.isFinite(durationMs) && durationMs > 0 ? msToNs(durationMs) : 0n;
|
|
1693
|
+
}
|
|
1694
|
+
function classify(event) {
|
|
1695
|
+
if (event.type === "ai_call" || event.type === "summarization") {
|
|
1696
|
+
if (event.skipReason === "cancelled") return "chat";
|
|
1697
|
+
if (event.skipReason || event.status === "skipped") return "plain";
|
|
1698
|
+
return "chat";
|
|
1699
|
+
}
|
|
1700
|
+
if (event.type === "tool_call") {
|
|
1701
|
+
const source = event.debug?.shortCircuitSource;
|
|
1702
|
+
if (event.skipReason || event.status === "skipped" || source === "cache" || source === "plugin") return "plain";
|
|
1703
|
+
if (event.status === "pending") return "plain";
|
|
1704
|
+
return "execute_tool";
|
|
1705
|
+
}
|
|
1706
|
+
if (event.type === "span" && event.actor?.role === "subagent") return "invoke_agent";
|
|
1707
|
+
return "plain";
|
|
1708
|
+
}
|
|
1709
|
+
var knownModel = (model) => model && model !== "unknown-model" && model !== "unknown_model" ? model : void 0;
|
|
1710
|
+
function toolNameOf(event) {
|
|
1711
|
+
if (event.actor?.name) return event.actor.name;
|
|
1712
|
+
const label = event.label.replace(/\s#\d+$/, "");
|
|
1713
|
+
const dash = label.indexOf(" - ");
|
|
1714
|
+
return dash >= 0 ? label.slice(dash + 3) : void 0;
|
|
1715
|
+
}
|
|
1716
|
+
var stripSequence = (label) => label.replace(/\s#\d+$/, "");
|
|
1717
|
+
function cappedMessage(message) {
|
|
1718
|
+
const text = message && message.length > 0 ? message : "Unknown error";
|
|
1719
|
+
return text.length > MAX_STATUS_MESSAGE ? text.slice(0, MAX_STATUS_MESSAGE) : text;
|
|
1720
|
+
}
|
|
1721
|
+
function exceptionEvent(timeNs, error) {
|
|
1722
|
+
return {
|
|
1723
|
+
timeUnixNano: timeNs.toString(),
|
|
1724
|
+
name: "exception",
|
|
1725
|
+
attributes: compact([
|
|
1726
|
+
str("exception.type", errorTypeOf(error)),
|
|
1727
|
+
strAllowEmpty("exception.message", error.message ?? "Unknown error"),
|
|
1728
|
+
str("exception.stacktrace", error.stack)
|
|
1729
|
+
])
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
function sessionToOtlp(file, options) {
|
|
1733
|
+
const useCognipeer = options.semconv !== "gen_ai";
|
|
1734
|
+
const useGenAi = options.semconv !== "cognipeer";
|
|
1735
|
+
const traceId = file.traceId || generateTraceId();
|
|
1736
|
+
const rootSpanId = file.rootSpanId || generateSpanId();
|
|
1737
|
+
const parent = options.parent;
|
|
1738
|
+
const traceState = parent?.traceState || void 0;
|
|
1739
|
+
const traceFlags = (typeof parent?.flags === "number" ? parent.flags : 1) & 255;
|
|
1740
|
+
const flags = traceFlags | FLAG_HAS_PARENT;
|
|
1741
|
+
const rootFlags = parent?.remote ? flags | FLAG_REMOTE_PARENT : flags;
|
|
1742
|
+
const agentName = file.agent?.name;
|
|
1743
|
+
const everyEvent = file.events;
|
|
1744
|
+
const exportedEvents = foldSupersededSpans(everyEvent).filter(
|
|
1745
|
+
(event) => options.terminal || !(event.type === "span" && event.status === "pending")
|
|
1746
|
+
);
|
|
1747
|
+
const startMs = parseMs(file.startedAt);
|
|
1748
|
+
const nodes = exportedEvents.map((event) => {
|
|
1749
|
+
const endMs = parseMs(event.timestamp) ?? startMs ?? Date.now();
|
|
1750
|
+
const endNs = msToNs(endMs);
|
|
1751
|
+
let startNs = endNs - durationNs(event.durationMs);
|
|
1752
|
+
if (startNs < 0n) startNs = 0n;
|
|
1753
|
+
return {
|
|
1754
|
+
event,
|
|
1755
|
+
spanId: event.spanId || generateSpanId(),
|
|
1756
|
+
parentId: event.parentSpanId || rootSpanId,
|
|
1757
|
+
startNs,
|
|
1758
|
+
endNs
|
|
1759
|
+
};
|
|
1760
|
+
});
|
|
1761
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
1762
|
+
for (const node of nodes) {
|
|
1763
|
+
const list = childrenOf.get(node.parentId);
|
|
1764
|
+
if (list) list.push(node);
|
|
1765
|
+
else childrenOf.set(node.parentId, [node]);
|
|
1766
|
+
}
|
|
1767
|
+
const settled = /* @__PURE__ */ new Set();
|
|
1768
|
+
const inProgress = /* @__PURE__ */ new Set();
|
|
1769
|
+
const widen = (node) => {
|
|
1770
|
+
if (settled.has(node) || inProgress.has(node)) return;
|
|
1771
|
+
inProgress.add(node);
|
|
1772
|
+
for (const child of childrenOf.get(node.spanId) ?? []) {
|
|
1773
|
+
if (child === node) continue;
|
|
1774
|
+
widen(child);
|
|
1775
|
+
if (child.startNs < node.startNs) node.startNs = child.startNs;
|
|
1776
|
+
if (child.endNs > node.endNs) node.endNs = child.endNs;
|
|
1777
|
+
}
|
|
1778
|
+
inProgress.delete(node);
|
|
1779
|
+
settled.add(node);
|
|
1780
|
+
};
|
|
1781
|
+
for (const node of nodes) widen(node);
|
|
1782
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1783
|
+
for (const event of everyEvent) if (event.spanId) byId.set(event.spanId, event);
|
|
1784
|
+
const agentOf = (event) => {
|
|
1785
|
+
let cursor = event;
|
|
1786
|
+
for (let hops = 0; cursor && hops < 64; hops++) {
|
|
1787
|
+
if (cursor !== event && cursor.type === "span" && cursor.actor?.role === "subagent") return cursor.actor.name;
|
|
1788
|
+
cursor = cursor.parentSpanId ? byId.get(cursor.parentSpanId) : void 0;
|
|
1789
|
+
}
|
|
1790
|
+
return agentName;
|
|
1791
|
+
};
|
|
1792
|
+
const spans = [];
|
|
1793
|
+
const sessionErrors = (file.errors ?? []).filter((error) => error.eventId === "session");
|
|
1794
|
+
if (options.terminal) {
|
|
1795
|
+
const earliestChild = nodes.reduce(
|
|
1796
|
+
(earliest, node) => earliest === void 0 || node.startNs < earliest ? node.startNs : earliest,
|
|
1797
|
+
void 0
|
|
1798
|
+
);
|
|
1799
|
+
let rootStart = startMs !== void 0 ? msToNs(startMs) : earliestChild ?? msToNs(Date.now());
|
|
1800
|
+
let rootEnd = msToNs(parseMs(file.endedAt) ?? (startMs !== void 0 ? startMs + (file.durationMs ?? 0) : Date.now()));
|
|
1801
|
+
for (const node of childrenOf.get(rootSpanId) ?? []) {
|
|
1802
|
+
if (node.startNs < rootStart) rootStart = node.startNs;
|
|
1803
|
+
if (node.endNs > rootEnd) rootEnd = node.endNs;
|
|
1804
|
+
}
|
|
1805
|
+
if (rootEnd < rootStart) rootEnd = rootStart;
|
|
1806
|
+
const rootName = useGenAi ? agentName ? `${OPERATION.invokeAgent} ${agentName}` : OPERATION.invokeAgent : `agent_session: ${agentName || "agent"}`;
|
|
1807
|
+
const summary = file.summary;
|
|
1808
|
+
const cumulativeEvents = summary?.eventCounts ? Object.values(summary.eventCounts).reduce((total, count) => total + (Number(count) || 0), 0) : file.events.length;
|
|
1809
|
+
const attributes = [];
|
|
1810
|
+
if (useCognipeer) {
|
|
1811
|
+
attributes.push(
|
|
1812
|
+
...compact([
|
|
1813
|
+
strAllowEmpty("cognipeer.session.status", options.cancelled ? "partial" : file.status),
|
|
1814
|
+
dbl("cognipeer.session.duration_ms", file.durationMs),
|
|
1815
|
+
int("cognipeer.session.total_input_tokens", summary?.totalInputTokens),
|
|
1816
|
+
int("cognipeer.session.total_output_tokens", summary?.totalOutputTokens),
|
|
1817
|
+
int("cognipeer.session.total_cached_input_tokens", summary?.totalCachedInputTokens),
|
|
1818
|
+
int("cognipeer.session.total_bytes_in", summary?.totalBytesIn),
|
|
1819
|
+
int("cognipeer.session.total_bytes_out", summary?.totalBytesOut),
|
|
1820
|
+
int("cognipeer.session.event_count", cumulativeEvents)
|
|
1821
|
+
])
|
|
1822
|
+
);
|
|
1823
|
+
for (const [key, count] of Object.entries(summary?.eventCounts ?? {})) {
|
|
1824
|
+
attributes.push({ key: `cognipeer.session.event_count.${key}`, value: { intValue: String(count) } });
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
if (useGenAi) {
|
|
1828
|
+
attributes.push(
|
|
1829
|
+
...compact([
|
|
1830
|
+
str(ATTR.operationName, OPERATION.invokeAgent),
|
|
1831
|
+
str(ATTR.agentName, agentName),
|
|
1832
|
+
str(ATTR.agentVersion, file.agent?.version),
|
|
1833
|
+
str(ATTR.requestModel, knownModel(file.agent?.model)),
|
|
1834
|
+
str(ATTR.conversationId, file.threadId)
|
|
1835
|
+
])
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
const root = {
|
|
1839
|
+
traceId,
|
|
1840
|
+
spanId: rootSpanId,
|
|
1841
|
+
parentSpanId: parent?.spanId ?? "",
|
|
1842
|
+
...traceState ? { traceState } : {},
|
|
1843
|
+
flags: rootFlags,
|
|
1844
|
+
name: rootName,
|
|
1845
|
+
kind: SPAN_KIND_INTERNAL,
|
|
1846
|
+
startTimeUnixNano: rootStart.toString(),
|
|
1847
|
+
endTimeUnixNano: rootEnd.toString(),
|
|
1848
|
+
attributes,
|
|
1849
|
+
status: { code: 0 }
|
|
1850
|
+
};
|
|
1851
|
+
if (sessionErrors.length > 0) {
|
|
1852
|
+
root.status = {
|
|
1853
|
+
code: 2,
|
|
1854
|
+
message: cappedMessage(sessionErrors.map((error) => error.message).join("; "))
|
|
1855
|
+
};
|
|
1856
|
+
if (useGenAi) root.attributes.push({ key: ATTR.errorType, value: { stringValue: errorTypeOf({ type: sessionErrors[0].errorName, stack: sessionErrors[0].stack }) } });
|
|
1857
|
+
root.events = sessionErrors.map((error) => {
|
|
1858
|
+
const at = parseMs(error.timestamp);
|
|
1859
|
+
return exceptionEvent(at !== void 0 ? msToNs(at) : rootEnd, {
|
|
1860
|
+
message: error.message,
|
|
1861
|
+
stack: error.stack,
|
|
1862
|
+
type: error.errorName
|
|
1863
|
+
});
|
|
1864
|
+
});
|
|
1865
|
+
}
|
|
1866
|
+
spans.push(root);
|
|
1867
|
+
}
|
|
1868
|
+
for (const node of nodes) {
|
|
1869
|
+
const event = node.event;
|
|
1870
|
+
const kind = classify(event);
|
|
1871
|
+
const failed = event.status === "error";
|
|
1872
|
+
const cancelledChat = kind === "chat" && event.skipReason === "cancelled";
|
|
1873
|
+
const attributes = [];
|
|
1874
|
+
if (useCognipeer) {
|
|
1875
|
+
attributes.push(
|
|
1876
|
+
...compact([
|
|
1877
|
+
strAllowEmpty("cognipeer.event.type", event.type),
|
|
1878
|
+
strAllowEmpty("cognipeer.event.label", event.label),
|
|
1879
|
+
int("cognipeer.event.sequence", event.sequence),
|
|
1880
|
+
strAllowEmpty("cognipeer.actor.scope", event.actor?.scope),
|
|
1881
|
+
strAllowEmpty("cognipeer.actor.name", event.actor?.name),
|
|
1882
|
+
strAllowEmpty("cognipeer.actor.role", event.actor?.role),
|
|
1883
|
+
strAllowEmpty("cognipeer.model", event.model),
|
|
1884
|
+
int("cognipeer.tokens.reasoning", event.reasoningTokens),
|
|
1885
|
+
strAllowEmpty("cognipeer.finish_reason", event.finishReason),
|
|
1886
|
+
strAllowEmpty("cognipeer.provider", event.provider),
|
|
1887
|
+
strAllowEmpty("cognipeer.tool.details", event.toolDetails ? JSON.stringify(event.toolDetails) : void 0),
|
|
1888
|
+
int("cognipeer.tokens.input", event.inputTokens),
|
|
1889
|
+
int("cognipeer.tokens.output", event.outputTokens),
|
|
1890
|
+
int("cognipeer.tokens.total", event.totalTokens),
|
|
1891
|
+
int("cognipeer.tokens.cached_input", event.cachedInputTokens),
|
|
1892
|
+
int("cognipeer.bytes.request", event.requestBytes),
|
|
1893
|
+
int("cognipeer.bytes.response", event.responseBytes),
|
|
1894
|
+
strAllowEmpty("cognipeer.tool.execution_id", event.toolExecutionId),
|
|
1895
|
+
strAllowEmpty("cognipeer.retry_of", event.retryOf),
|
|
1896
|
+
strAllowEmpty("cognipeer.event.id", event.id)
|
|
1897
|
+
])
|
|
1898
|
+
);
|
|
1899
|
+
const sectionsAttr = sectionsAttribute(event.data?.sections, event, options.content);
|
|
1900
|
+
if (sectionsAttr) attributes.push(sectionsAttr);
|
|
1901
|
+
attributes.push({ key: "cognipeer.event.status", value: { stringValue: event.status } });
|
|
1902
|
+
}
|
|
1903
|
+
let name = event.label || event.type;
|
|
1904
|
+
let spanKind = SPAN_KIND_INTERNAL;
|
|
1905
|
+
if (kind === "chat") spanKind = SPAN_KIND_CLIENT;
|
|
1906
|
+
if (useGenAi) {
|
|
1907
|
+
const conversation = str(ATTR.conversationId, file.threadId);
|
|
1908
|
+
if (kind === "chat") {
|
|
1909
|
+
const model = knownModel(event.model);
|
|
1910
|
+
name = model ? `${OPERATION.chat} ${model}` : OPERATION.chat;
|
|
1911
|
+
attributes.push(
|
|
1912
|
+
...compact([
|
|
1913
|
+
str(ATTR.operationName, OPERATION.chat),
|
|
1914
|
+
str(ATTR.providerName, genAiProviderName(event.provider)),
|
|
1915
|
+
str(ATTR.requestModel, model),
|
|
1916
|
+
str(ATTR.responseModel, event.responseModel),
|
|
1917
|
+
str(ATTR.responseId, event.responseId),
|
|
1918
|
+
bool(ATTR.requestStream, event.streaming),
|
|
1919
|
+
str(ATTR.outputType, event.outputType)
|
|
1920
|
+
])
|
|
1921
|
+
);
|
|
1922
|
+
if (failed || cancelledChat) {
|
|
1923
|
+
attributes.push(strArray(ATTR.finishReasons, ["error"]));
|
|
1924
|
+
} else {
|
|
1925
|
+
const reason = event.rawFinishReason ?? event.finishReason;
|
|
1926
|
+
if (reason) attributes.push(strArray(ATTR.finishReasons, [reason]));
|
|
1927
|
+
}
|
|
1928
|
+
const usageAllowed = !failed && !cancelledChat && (event.type !== "summarization" || event.debug?.usageFromModel === true);
|
|
1929
|
+
const usage = usageAllowed ? genAiUsageOf(event) : void 0;
|
|
1930
|
+
if (usage) {
|
|
1931
|
+
attributes.push(
|
|
1932
|
+
...compact([
|
|
1933
|
+
int(ATTR.usageInput, usage.input),
|
|
1934
|
+
int(ATTR.usageOutput, usage.output),
|
|
1935
|
+
int(ATTR.usageCacheRead, usage.cacheRead),
|
|
1936
|
+
int(ATTR.usageCacheWrite, usage.cacheWrite),
|
|
1937
|
+
int(ATTR.usageReasoning, usage.reasoning)
|
|
1938
|
+
])
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
if (conversation) attributes.push(conversation);
|
|
1942
|
+
attributes.push(...contentAttributes("chat", event, genAiProviderName(event.provider), options.content));
|
|
1943
|
+
} else if (kind === "execute_tool") {
|
|
1944
|
+
const tool = toolNameOf(event);
|
|
1945
|
+
name = tool ? `${OPERATION.executeTool} ${tool}` : OPERATION.executeTool;
|
|
1946
|
+
attributes.push(
|
|
1947
|
+
...compact([
|
|
1948
|
+
str(ATTR.operationName, OPERATION.executeTool),
|
|
1949
|
+
str(ATTR.toolName, tool),
|
|
1950
|
+
str(ATTR.toolCallId, event.toolCallId),
|
|
1951
|
+
str(ATTR.toolType, "function"),
|
|
1952
|
+
str(ATTR.agentName, agentOf(event)),
|
|
1953
|
+
conversation
|
|
1954
|
+
])
|
|
1955
|
+
);
|
|
1956
|
+
attributes.push(...contentAttributes("execute_tool", event, void 0, options.content));
|
|
1957
|
+
} else if (kind === "invoke_agent") {
|
|
1958
|
+
const child = event.actor?.name;
|
|
1959
|
+
name = child ? `${OPERATION.invokeAgent} ${child}` : OPERATION.invokeAgent;
|
|
1960
|
+
attributes.push(...compact([str(ATTR.operationName, OPERATION.invokeAgent), str(ATTR.agentName, child), conversation]));
|
|
1961
|
+
} else {
|
|
1962
|
+
name = stripSequence(name);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
const span = {
|
|
1966
|
+
traceId: event.traceId || traceId,
|
|
1967
|
+
spanId: node.spanId,
|
|
1968
|
+
parentSpanId: node.parentId,
|
|
1969
|
+
...traceState ? { traceState } : {},
|
|
1970
|
+
flags,
|
|
1971
|
+
name,
|
|
1972
|
+
kind: spanKind,
|
|
1973
|
+
startTimeUnixNano: node.startNs.toString(),
|
|
1974
|
+
endTimeUnixNano: node.endNs.toString(),
|
|
1975
|
+
attributes,
|
|
1976
|
+
status: { code: 0 }
|
|
1977
|
+
};
|
|
1978
|
+
if (failed) {
|
|
1979
|
+
const error = event.error ?? { message: "Unknown error" };
|
|
1980
|
+
span.status = { code: 2, message: cappedMessage(error.message) };
|
|
1981
|
+
if (useGenAi) attributes.push({ key: ATTR.errorType, value: { stringValue: errorTypeOf(error) } });
|
|
1982
|
+
span.events = [exceptionEvent(node.endNs, error)];
|
|
1983
|
+
}
|
|
1984
|
+
spans.push(span);
|
|
1985
|
+
}
|
|
1986
|
+
return {
|
|
1987
|
+
resourceSpans: [
|
|
1988
|
+
{
|
|
1989
|
+
resource: { attributes: resourceAttributesOf(file, options, useCognipeer) },
|
|
1990
|
+
scopeSpans: [{ scope: { name: SCOPE_NAME, version: SDK_VERSION }, spans }]
|
|
1991
|
+
}
|
|
1992
|
+
]
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
function resourceAttributesOf(file, options, useCognipeer) {
|
|
1996
|
+
const custom = options.resourceAttributes ?? {};
|
|
1997
|
+
const serviceName = options.serviceName || custom["service.name"] || file.agent?.name || "cognipeer-agent";
|
|
1998
|
+
const attributes = compact([
|
|
1999
|
+
str("service.name", serviceName),
|
|
2000
|
+
str("service.version", file.agent?.version)
|
|
2001
|
+
]);
|
|
2002
|
+
if (useCognipeer) {
|
|
2003
|
+
attributes.push(
|
|
2004
|
+
...compact([
|
|
2005
|
+
str("cognipeer.session.id", file.sessionId),
|
|
2006
|
+
str("cognipeer.thread.id", file.threadId),
|
|
2007
|
+
str("cognipeer.agent.model", file.agent?.model),
|
|
2008
|
+
str("cognipeer.agent.provider", file.agent?.provider),
|
|
2009
|
+
...Object.entries(file.metadata ?? {}).map(([key, value]) => str(`cognipeer.metadata.${key}`, value))
|
|
2010
|
+
])
|
|
2011
|
+
);
|
|
2012
|
+
}
|
|
2013
|
+
attributes.push(
|
|
2014
|
+
...compact([
|
|
2015
|
+
str("telemetry.sdk.name", SCOPE_NAME),
|
|
2016
|
+
str("telemetry.sdk.language", "nodejs"),
|
|
2017
|
+
str("telemetry.sdk.version", SDK_VERSION)
|
|
2018
|
+
])
|
|
2019
|
+
);
|
|
2020
|
+
for (const [key, value] of Object.entries(custom)) {
|
|
2021
|
+
if (key === "service.name") continue;
|
|
2022
|
+
const index = attributes.findIndex((attr) => attr.key === key);
|
|
2023
|
+
const entry = str(key, value);
|
|
2024
|
+
if (!entry) continue;
|
|
2025
|
+
if (index >= 0) attributes[index] = entry;
|
|
2026
|
+
else attributes.push(entry);
|
|
2027
|
+
}
|
|
2028
|
+
return attributes;
|
|
2029
|
+
}
|
|
2030
|
+
function countSpans(request) {
|
|
2031
|
+
let total = 0;
|
|
2032
|
+
for (const rs of request.resourceSpans) for (const ss of rs.scopeSpans) total += ss.spans.length;
|
|
2033
|
+
return total;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
// src/utils/otlp/env.ts
|
|
2037
|
+
var warned = /* @__PURE__ */ new Set();
|
|
2038
|
+
function warnOnce(message) {
|
|
2039
|
+
if (warned.has(message)) return;
|
|
2040
|
+
warned.add(message);
|
|
2041
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") console.warn(message);
|
|
2042
|
+
}
|
|
2043
|
+
function pick(env, ...names) {
|
|
2044
|
+
for (const name of names) {
|
|
2045
|
+
const value = env[name];
|
|
2046
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
2047
|
+
}
|
|
2048
|
+
return void 0;
|
|
2049
|
+
}
|
|
2050
|
+
function decode(value) {
|
|
2051
|
+
try {
|
|
2052
|
+
return decodeURIComponent(value);
|
|
2053
|
+
} catch {
|
|
2054
|
+
return value;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
function parseKeyValueList(raw) {
|
|
2058
|
+
const out = {};
|
|
2059
|
+
if (!raw) return out;
|
|
2060
|
+
for (const part of raw.split(",")) {
|
|
2061
|
+
const index = part.indexOf("=");
|
|
2062
|
+
if (index <= 0) continue;
|
|
2063
|
+
const key = part.slice(0, index).trim();
|
|
2064
|
+
if (!key) continue;
|
|
2065
|
+
out[key] = decode(part.slice(index + 1).trim());
|
|
2066
|
+
}
|
|
2067
|
+
return out;
|
|
2068
|
+
}
|
|
2069
|
+
function tracesEndpointFrom(base) {
|
|
2070
|
+
return `${base.replace(/\/+$/, "")}/v1/traces`;
|
|
2071
|
+
}
|
|
2072
|
+
function protocolFrom(raw, fallback) {
|
|
2073
|
+
if (!raw) return fallback;
|
|
2074
|
+
const value = raw.toLowerCase();
|
|
2075
|
+
if (value === "http/protobuf" || value === "http/json") return value;
|
|
2076
|
+
warnOnce(
|
|
2077
|
+
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}.`
|
|
2078
|
+
);
|
|
2079
|
+
return fallback;
|
|
2080
|
+
}
|
|
2081
|
+
function resolveOtlpEnv(env, explicit) {
|
|
2082
|
+
const explicitEndpoint = typeof explicit.endpoint === "string" ? explicit.endpoint.trim() : "";
|
|
2083
|
+
const envDriven = explicitEndpoint.length === 0;
|
|
2084
|
+
const resourceAttributes = parseKeyValueList(pick(env, "OTEL_RESOURCE_ATTRIBUTES"));
|
|
2085
|
+
const serviceName = pick(env, "OTEL_SERVICE_NAME");
|
|
2086
|
+
if (!envDriven) {
|
|
2087
|
+
return {
|
|
2088
|
+
envDriven,
|
|
2089
|
+
endpoint: explicitEndpoint,
|
|
2090
|
+
headers: { ...explicit.headers ?? {} },
|
|
2091
|
+
protocol: explicit.protocol ?? "http/json",
|
|
2092
|
+
compression: explicit.compression ?? "none",
|
|
2093
|
+
timeoutMs: explicit.timeoutMs,
|
|
2094
|
+
serviceName,
|
|
2095
|
+
resourceAttributes,
|
|
2096
|
+
disabled: false
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
const tracesEndpoint = pick(env, "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT");
|
|
2100
|
+
const baseEndpoint = pick(env, "OTEL_EXPORTER_OTLP_ENDPOINT");
|
|
2101
|
+
const endpoint = tracesEndpoint ?? (baseEndpoint ? tracesEndpointFrom(baseEndpoint) : void 0);
|
|
2102
|
+
const envHeaders = {
|
|
2103
|
+
...parseKeyValueList(pick(env, "OTEL_EXPORTER_OTLP_HEADERS")),
|
|
2104
|
+
...parseKeyValueList(pick(env, "OTEL_EXPORTER_OTLP_TRACES_HEADERS"))
|
|
2105
|
+
};
|
|
2106
|
+
const timeoutRaw = pick(env, "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT", "OTEL_EXPORTER_OTLP_TIMEOUT");
|
|
2107
|
+
const timeout = timeoutRaw !== void 0 ? Number(timeoutRaw) : void 0;
|
|
2108
|
+
const compressionRaw = pick(env, "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION", "OTEL_EXPORTER_OTLP_COMPRESSION")?.toLowerCase();
|
|
2109
|
+
return {
|
|
2110
|
+
envDriven,
|
|
2111
|
+
endpoint,
|
|
2112
|
+
headers: { ...envHeaders, ...explicit.headers ?? {} },
|
|
2113
|
+
protocol: explicit.protocol ?? protocolFrom(pick(env, "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL", "OTEL_EXPORTER_OTLP_PROTOCOL"), "http/protobuf"),
|
|
2114
|
+
compression: explicit.compression ?? (compressionRaw === "gzip" ? "gzip" : "none"),
|
|
2115
|
+
timeoutMs: explicit.timeoutMs ?? (timeout !== void 0 && Number.isFinite(timeout) && timeout > 0 ? timeout : void 0),
|
|
2116
|
+
serviceName,
|
|
2117
|
+
resourceAttributes,
|
|
2118
|
+
disabled: pick(env, "OTEL_SDK_DISABLED")?.toLowerCase() === "true" || pick(env, "OTEL_TRACES_EXPORTER")?.toLowerCase() === "none"
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
function currentEnv() {
|
|
2122
|
+
return typeof process !== "undefined" && process.env ? process.env : {};
|
|
2123
|
+
}
|
|
2124
|
+
var WIRE_VARINT = 0;
|
|
2125
|
+
var WIRE_FIXED64 = 1;
|
|
2126
|
+
var WIRE_LEN = 2;
|
|
2127
|
+
var WIRE_FIXED32 = 5;
|
|
2128
|
+
var textEncoder = new TextEncoder();
|
|
2129
|
+
var Writer = class {
|
|
2130
|
+
constructor() {
|
|
2131
|
+
this.buf = new Uint8Array(128);
|
|
2132
|
+
this.len = 0;
|
|
2133
|
+
this.view = new DataView(this.buf.buffer);
|
|
2134
|
+
}
|
|
2135
|
+
ensure(extra) {
|
|
2136
|
+
if (this.len + extra <= this.buf.length) return;
|
|
2137
|
+
let size = this.buf.length * 2;
|
|
2138
|
+
while (size < this.len + extra) size *= 2;
|
|
2139
|
+
const next = new Uint8Array(size);
|
|
2140
|
+
next.set(this.buf.subarray(0, this.len));
|
|
2141
|
+
this.buf = next;
|
|
2142
|
+
this.view = new DataView(next.buffer);
|
|
2143
|
+
}
|
|
2144
|
+
byte(value) {
|
|
2145
|
+
this.ensure(1);
|
|
2146
|
+
this.buf[this.len++] = value;
|
|
2147
|
+
}
|
|
2148
|
+
varint(value) {
|
|
2149
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
|
|
2150
|
+
let n2 = value;
|
|
2151
|
+
while (n2 >= 128) {
|
|
2152
|
+
this.byte(n2 % 128 | 128);
|
|
2153
|
+
n2 = Math.floor(n2 / 128);
|
|
2154
|
+
}
|
|
2155
|
+
this.byte(n2);
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
let n = BigInt.asUintN(64, BigInt(value));
|
|
2159
|
+
while (n >= 128n) {
|
|
2160
|
+
this.byte(Number(n & 127n) | 128);
|
|
2161
|
+
n >>= 7n;
|
|
2162
|
+
}
|
|
2163
|
+
this.byte(Number(n));
|
|
2164
|
+
}
|
|
2165
|
+
tag(field, wire) {
|
|
2166
|
+
this.varint(field * 8 + wire);
|
|
2167
|
+
}
|
|
2168
|
+
raw(bytes) {
|
|
2169
|
+
this.ensure(bytes.length);
|
|
2170
|
+
this.buf.set(bytes, this.len);
|
|
2171
|
+
this.len += bytes.length;
|
|
2172
|
+
}
|
|
2173
|
+
fixed64(value) {
|
|
2174
|
+
this.ensure(8);
|
|
2175
|
+
this.view.setBigUint64(this.len, BigInt.asUintN(64, value), true);
|
|
2176
|
+
this.len += 8;
|
|
2177
|
+
}
|
|
2178
|
+
fixed32(value) {
|
|
2179
|
+
this.ensure(4);
|
|
2180
|
+
this.view.setUint32(this.len, value >>> 0, true);
|
|
2181
|
+
this.len += 4;
|
|
2182
|
+
}
|
|
2183
|
+
double(value) {
|
|
2184
|
+
this.ensure(8);
|
|
2185
|
+
this.view.setFloat64(this.len, value, true);
|
|
2186
|
+
this.len += 8;
|
|
2187
|
+
}
|
|
2188
|
+
finish() {
|
|
2189
|
+
return this.buf.slice(0, this.len);
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
function lenField(w, field, bytes) {
|
|
2193
|
+
w.tag(field, WIRE_LEN);
|
|
2194
|
+
w.varint(bytes.length);
|
|
2195
|
+
w.raw(bytes);
|
|
2196
|
+
}
|
|
2197
|
+
function stringField(w, field, value) {
|
|
2198
|
+
if (!value) return;
|
|
2199
|
+
lenField(w, field, textEncoder.encode(value));
|
|
2200
|
+
}
|
|
2201
|
+
function hexBytes(hex, bytes) {
|
|
2202
|
+
if (!hex) return void 0;
|
|
2203
|
+
const out = new Uint8Array(bytes);
|
|
2204
|
+
for (let i = 0; i < bytes; i++) {
|
|
2205
|
+
const pair = hex.slice(i * 2, i * 2 + 2);
|
|
2206
|
+
const value = /^[0-9a-fA-F]{2}$/.test(pair) ? parseInt(pair, 16) : 0;
|
|
2207
|
+
out[i] = value;
|
|
2208
|
+
}
|
|
2209
|
+
return out;
|
|
2210
|
+
}
|
|
2211
|
+
function base64Bytes(value) {
|
|
2212
|
+
return new Uint8Array(Buffer$1.from(value, "base64"));
|
|
2213
|
+
}
|
|
2214
|
+
function encodeAnyValue(value) {
|
|
2215
|
+
const w = new Writer();
|
|
2216
|
+
if (value.stringValue !== void 0) {
|
|
2217
|
+
lenField(w, 1, textEncoder.encode(value.stringValue));
|
|
2218
|
+
} else if (value.boolValue !== void 0) {
|
|
2219
|
+
w.tag(2, WIRE_VARINT);
|
|
2220
|
+
w.varint(value.boolValue ? 1 : 0);
|
|
2221
|
+
} else if (value.intValue !== void 0) {
|
|
2222
|
+
w.tag(3, WIRE_VARINT);
|
|
2223
|
+
w.varint(BigInt(value.intValue));
|
|
2224
|
+
} else if (value.doubleValue !== void 0) {
|
|
2225
|
+
w.tag(4, WIRE_FIXED64);
|
|
2226
|
+
w.double(value.doubleValue);
|
|
2227
|
+
} else if (value.arrayValue !== void 0) {
|
|
2228
|
+
const inner = new Writer();
|
|
2229
|
+
for (const item of value.arrayValue.values) lenField(inner, 1, encodeAnyValue(item));
|
|
2230
|
+
lenField(w, 5, inner.finish());
|
|
2231
|
+
} else if (value.kvlistValue !== void 0) {
|
|
2232
|
+
const inner = new Writer();
|
|
2233
|
+
for (const kv of value.kvlistValue.values) lenField(inner, 1, encodeKeyValue(kv));
|
|
2234
|
+
lenField(w, 6, inner.finish());
|
|
2235
|
+
} else if (value.bytesValue !== void 0) {
|
|
2236
|
+
lenField(w, 7, base64Bytes(value.bytesValue));
|
|
2237
|
+
}
|
|
2238
|
+
return w.finish();
|
|
2239
|
+
}
|
|
2240
|
+
function encodeKeyValue(kv) {
|
|
2241
|
+
const w = new Writer();
|
|
2242
|
+
stringField(w, 1, kv.key);
|
|
2243
|
+
lenField(w, 2, encodeAnyValue(kv.value));
|
|
2244
|
+
return w.finish();
|
|
2245
|
+
}
|
|
2246
|
+
function encodeSpanEvent(event) {
|
|
2247
|
+
const w = new Writer();
|
|
2248
|
+
w.tag(1, WIRE_FIXED64);
|
|
2249
|
+
w.fixed64(BigInt(event.timeUnixNano));
|
|
2250
|
+
stringField(w, 2, event.name);
|
|
2251
|
+
for (const attr of event.attributes) lenField(w, 3, encodeKeyValue(attr));
|
|
2252
|
+
return w.finish();
|
|
2253
|
+
}
|
|
2254
|
+
function encodeSpan(span) {
|
|
2255
|
+
const w = new Writer();
|
|
2256
|
+
const traceId = hexBytes(span.traceId, 16);
|
|
2257
|
+
if (traceId) lenField(w, 1, traceId);
|
|
2258
|
+
const spanId = hexBytes(span.spanId, 8);
|
|
2259
|
+
if (spanId) lenField(w, 2, spanId);
|
|
2260
|
+
stringField(w, 3, span.traceState);
|
|
2261
|
+
const parent = hexBytes(span.parentSpanId, 8);
|
|
2262
|
+
if (parent) lenField(w, 4, parent);
|
|
2263
|
+
stringField(w, 5, span.name);
|
|
2264
|
+
if (span.kind) {
|
|
2265
|
+
w.tag(6, WIRE_VARINT);
|
|
2266
|
+
w.varint(span.kind);
|
|
2267
|
+
}
|
|
2268
|
+
w.tag(7, WIRE_FIXED64);
|
|
2269
|
+
w.fixed64(BigInt(span.startTimeUnixNano));
|
|
2270
|
+
w.tag(8, WIRE_FIXED64);
|
|
2271
|
+
w.fixed64(BigInt(span.endTimeUnixNano));
|
|
2272
|
+
for (const attr of span.attributes) lenField(w, 9, encodeKeyValue(attr));
|
|
2273
|
+
for (const event of span.events ?? []) lenField(w, 11, encodeSpanEvent(event));
|
|
2274
|
+
const status = new Writer();
|
|
2275
|
+
stringField(status, 2, span.status.message);
|
|
2276
|
+
if (span.status.code) {
|
|
2277
|
+
status.tag(3, WIRE_VARINT);
|
|
2278
|
+
status.varint(span.status.code);
|
|
2279
|
+
}
|
|
2280
|
+
lenField(w, 15, status.finish());
|
|
2281
|
+
if (span.flags) {
|
|
2282
|
+
w.tag(16, WIRE_FIXED32);
|
|
2283
|
+
w.fixed32(span.flags);
|
|
2284
|
+
}
|
|
2285
|
+
return w.finish();
|
|
2286
|
+
}
|
|
2287
|
+
function encodeExportTraceServiceRequest(request) {
|
|
2288
|
+
const w = new Writer();
|
|
2289
|
+
for (const rs of request.resourceSpans) {
|
|
2290
|
+
const resourceSpans = new Writer();
|
|
2291
|
+
const resource = new Writer();
|
|
2292
|
+
for (const attr of rs.resource.attributes) lenField(resource, 1, encodeKeyValue(attr));
|
|
2293
|
+
lenField(resourceSpans, 1, resource.finish());
|
|
2294
|
+
for (const ss of rs.scopeSpans) {
|
|
2295
|
+
const scopeSpans = new Writer();
|
|
2296
|
+
const scope = new Writer();
|
|
2297
|
+
stringField(scope, 1, ss.scope.name);
|
|
2298
|
+
stringField(scope, 2, ss.scope.version);
|
|
2299
|
+
lenField(scopeSpans, 1, scope.finish());
|
|
2300
|
+
for (const span of ss.spans) lenField(scopeSpans, 2, encodeSpan(span));
|
|
2301
|
+
lenField(resourceSpans, 2, scopeSpans.finish());
|
|
2302
|
+
}
|
|
2303
|
+
stringField(resourceSpans, 3, rs.schemaUrl);
|
|
2304
|
+
lenField(w, 1, resourceSpans.finish());
|
|
2305
|
+
}
|
|
2306
|
+
return w.finish();
|
|
2307
|
+
}
|
|
2308
|
+
var Reader = class {
|
|
2309
|
+
constructor(bytes) {
|
|
2310
|
+
this.bytes = bytes;
|
|
2311
|
+
this.pos = 0;
|
|
2312
|
+
}
|
|
2313
|
+
get done() {
|
|
2314
|
+
return this.pos >= this.bytes.length;
|
|
2315
|
+
}
|
|
2316
|
+
varint() {
|
|
2317
|
+
let result = 0n;
|
|
2318
|
+
let shift = 0n;
|
|
2319
|
+
for (; ; ) {
|
|
2320
|
+
if (this.pos >= this.bytes.length) throw new Error("truncated varint");
|
|
2321
|
+
const byte = this.bytes[this.pos++];
|
|
2322
|
+
result |= BigInt(byte & 127) << shift;
|
|
2323
|
+
if ((byte & 128) === 0) return result;
|
|
2324
|
+
shift += 7n;
|
|
2325
|
+
if (shift > 70n) throw new Error("varint too long");
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
slice(length) {
|
|
2329
|
+
if (this.pos + length > this.bytes.length) throw new Error("truncated field");
|
|
2330
|
+
const out = this.bytes.subarray(this.pos, this.pos + length);
|
|
2331
|
+
this.pos += length;
|
|
2332
|
+
return out;
|
|
2333
|
+
}
|
|
2334
|
+
skip(wire) {
|
|
2335
|
+
if (wire === WIRE_VARINT) this.varint();
|
|
2336
|
+
else if (wire === WIRE_FIXED64) this.slice(8);
|
|
2337
|
+
else if (wire === WIRE_FIXED32) this.slice(4);
|
|
2338
|
+
else if (wire === WIRE_LEN) this.slice(Number(this.varint()));
|
|
2339
|
+
else throw new Error(`unsupported wire type ${wire}`);
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
function decodeExportTraceServiceResponse(bytes) {
|
|
2343
|
+
const top = new Reader(bytes);
|
|
2344
|
+
let result;
|
|
2345
|
+
while (!top.done) {
|
|
2346
|
+
const key = Number(top.varint());
|
|
2347
|
+
const field = key >>> 3;
|
|
2348
|
+
const wire = key & 7;
|
|
2349
|
+
if (field === 1 && wire === WIRE_LEN) {
|
|
2350
|
+
const inner = new Reader(top.slice(Number(top.varint())));
|
|
2351
|
+
let rejected = 0n;
|
|
2352
|
+
let message;
|
|
2353
|
+
while (!inner.done) {
|
|
2354
|
+
const innerKey = Number(inner.varint());
|
|
2355
|
+
const innerField = innerKey >>> 3;
|
|
2356
|
+
const innerWire = innerKey & 7;
|
|
2357
|
+
if (innerField === 1 && innerWire === WIRE_VARINT) rejected = BigInt.asIntN(64, inner.varint());
|
|
2358
|
+
else if (innerField === 2 && innerWire === WIRE_LEN) message = new TextDecoder().decode(inner.slice(Number(inner.varint())));
|
|
2359
|
+
else inner.skip(innerWire);
|
|
2360
|
+
}
|
|
2361
|
+
result = { rejectedSpans: Number(rejected), ...message ? { message } : {} };
|
|
2362
|
+
} else {
|
|
2363
|
+
top.skip(wire);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
return result;
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
// src/utils/otlp/exporter.ts
|
|
2370
|
+
var gzipAsync = promisify(gzip);
|
|
2371
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
2372
|
+
var RETRY_DEFAULTS = {
|
|
2373
|
+
maxAttempts: 3,
|
|
2374
|
+
initialDelayMs: 250,
|
|
2375
|
+
maxDelayMs: 4e3,
|
|
2376
|
+
maxElapsedMs: 25e3
|
|
2377
|
+
};
|
|
2378
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
2379
|
+
function retryPolicy(retry) {
|
|
2380
|
+
if (retry === false) return { ...RETRY_DEFAULTS, maxAttempts: 1 };
|
|
2381
|
+
const merged = { ...RETRY_DEFAULTS, ...retry ?? {} };
|
|
2382
|
+
return { ...merged, maxAttempts: Math.max(1, Math.floor(merged.maxAttempts)) };
|
|
2383
|
+
}
|
|
2384
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2385
|
+
function retryAfterMs(response) {
|
|
2386
|
+
let raw;
|
|
2387
|
+
try {
|
|
2388
|
+
raw = response?.headers?.get?.("retry-after");
|
|
2389
|
+
} catch {
|
|
2390
|
+
return void 0;
|
|
2391
|
+
}
|
|
2392
|
+
if (typeof raw !== "string" || raw.trim() === "") return void 0;
|
|
2393
|
+
const seconds = Number(raw);
|
|
2394
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
2395
|
+
const date = Date.parse(raw);
|
|
2396
|
+
return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
|
|
2397
|
+
}
|
|
2398
|
+
async function attemptOnce(fetchFn, url, init, timeoutMs, protocol) {
|
|
2399
|
+
const controller = new AbortController();
|
|
2400
|
+
let timer;
|
|
2401
|
+
const timeout = new Promise((_, reject) => {
|
|
2402
|
+
timer = setTimeout(() => {
|
|
2403
|
+
controller.abort();
|
|
2404
|
+
reject(new Error(`timed out after ${timeoutMs} ms`));
|
|
2405
|
+
}, timeoutMs);
|
|
2406
|
+
});
|
|
2407
|
+
try {
|
|
2408
|
+
const pending = fetchFn(url, { ...init, signal: controller.signal });
|
|
2409
|
+
Promise.resolve(pending).catch(() => void 0);
|
|
2410
|
+
const response = await Promise.race([pending, timeout]);
|
|
2411
|
+
const status = typeof response?.status === "number" ? response.status : response?.ok ? 200 : 0;
|
|
2412
|
+
const ok = typeof response?.ok === "boolean" ? response.ok : status >= 200 && status < 300;
|
|
2413
|
+
if (ok) {
|
|
2414
|
+
const lateBody = timeout.catch(() => void 0);
|
|
2415
|
+
const partialSuccess = await Promise.race([readPartialSuccess(response, protocol), lateBody]);
|
|
2416
|
+
return { kind: "ok", status, ...partialSuccess ? { partialSuccess } : {} };
|
|
2417
|
+
}
|
|
2418
|
+
let body = "";
|
|
2419
|
+
try {
|
|
2420
|
+
if (typeof response?.text === "function") body = String(await response.text());
|
|
2421
|
+
} catch {
|
|
2422
|
+
}
|
|
2423
|
+
const statusText = typeof response?.statusText === "string" && response.statusText ? ` ${response.statusText}` : "";
|
|
2424
|
+
return {
|
|
2425
|
+
kind: "http",
|
|
2426
|
+
status,
|
|
2427
|
+
message: `HTTP ${status}${statusText}${body ? ` - ${body.slice(0, 200)}` : ""}`,
|
|
2428
|
+
retryable: RETRYABLE_STATUS.has(status),
|
|
2429
|
+
retryAfter: retryAfterMs(response)
|
|
2430
|
+
};
|
|
2431
|
+
} catch (err) {
|
|
2432
|
+
return { kind: "network", message: err instanceof Error ? err.message : String(err) };
|
|
2433
|
+
} finally {
|
|
2434
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
async function readPartialSuccess(response, protocol) {
|
|
2438
|
+
try {
|
|
2439
|
+
if (protocol === "http/protobuf") {
|
|
2440
|
+
if (typeof response?.arrayBuffer !== "function") return void 0;
|
|
2441
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
2442
|
+
if (bytes.length === 0) return void 0;
|
|
2443
|
+
const decoded = decodeExportTraceServiceResponse(bytes);
|
|
2444
|
+
return decoded && (decoded.rejectedSpans > 0 || decoded.message) ? decoded : void 0;
|
|
2445
|
+
}
|
|
2446
|
+
if (typeof response?.text !== "function") return void 0;
|
|
2447
|
+
const text = String(await response.text());
|
|
2448
|
+
if (!text.trim()) return void 0;
|
|
2449
|
+
const partial = JSON.parse(text)?.partialSuccess;
|
|
2450
|
+
if (!partial || typeof partial !== "object") return void 0;
|
|
2451
|
+
const rejectedSpans = Number(partial.rejectedSpans ?? 0);
|
|
2452
|
+
const message = typeof partial.errorMessage === "string" && partial.errorMessage ? partial.errorMessage : void 0;
|
|
2453
|
+
if (!(rejectedSpans > 0) && !message) return void 0;
|
|
2454
|
+
return { rejectedSpans: Number.isFinite(rejectedSpans) ? rejectedSpans : 0, ...message ? { message } : {} };
|
|
2455
|
+
} catch {
|
|
2456
|
+
return void 0;
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
function createOtlpExporter(options = {}) {
|
|
2460
|
+
const env = resolveOtlpEnv(currentEnv(), options);
|
|
2461
|
+
if (!env.endpoint && !env.disabled) {
|
|
2462
|
+
throw new Error(
|
|
2463
|
+
"[agent-sdk] OTLP export needs an `endpoint` (or OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT in the environment)."
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
const semconv = options.semconv ?? "both";
|
|
2467
|
+
const protocol = env.protocol;
|
|
2468
|
+
const compression = env.compression;
|
|
2469
|
+
const timeoutMs = env.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2470
|
+
const policy = retryPolicy(options.retry);
|
|
2471
|
+
const serviceName = options.serviceName ?? env.serviceName;
|
|
2472
|
+
const resourceAttributes = { ...env.resourceAttributes, ...options.resourceAttributes ?? {} };
|
|
2473
|
+
const endpoint = env.endpoint ?? "";
|
|
2474
|
+
const content = resolveContentOptions(options.content);
|
|
2475
|
+
return {
|
|
2476
|
+
name: options.name ?? "otlp",
|
|
2477
|
+
endpoint,
|
|
2478
|
+
semconv,
|
|
2479
|
+
protocol,
|
|
2480
|
+
wantsContent: content.enabled,
|
|
2481
|
+
contentOptions: content,
|
|
2482
|
+
async exportSession(file, run) {
|
|
2483
|
+
try {
|
|
2484
|
+
if (env.disabled) {
|
|
2485
|
+
return { ok: true, skipped: true, reason: "disabled by the environment (OTEL_SDK_DISABLED / OTEL_TRACES_EXPORTER)", attempts: 0, spans: 0, bytes: 0 };
|
|
2486
|
+
}
|
|
2487
|
+
const convertOptions = {
|
|
2488
|
+
semconv,
|
|
2489
|
+
serviceName,
|
|
2490
|
+
resourceAttributes,
|
|
2491
|
+
terminal: run.terminal,
|
|
2492
|
+
cancelled: run.cancelled,
|
|
2493
|
+
parent: run.parent,
|
|
2494
|
+
content
|
|
2495
|
+
};
|
|
2496
|
+
const request = sessionToOtlp(file, convertOptions);
|
|
2497
|
+
const spans = countSpans(request);
|
|
2498
|
+
if (spans === 0) return { ok: true, skipped: true, reason: "no spans to export", attempts: 0, spans: 0, bytes: 0 };
|
|
2499
|
+
const fetchFn = options.fetch ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0);
|
|
2500
|
+
if (!fetchFn) return { ok: false, attempts: 0, spans, bytes: 0, error: "OTLP export requires fetch to be available in this runtime." };
|
|
2501
|
+
let body = protocol === "http/protobuf" ? encodeExportTraceServiceRequest(request) : JSON.stringify(request);
|
|
2502
|
+
const headers = {
|
|
2503
|
+
"content-type": protocol === "http/protobuf" ? "application/x-protobuf" : "application/json"
|
|
2504
|
+
};
|
|
2505
|
+
if (compression === "gzip") {
|
|
2506
|
+
body = await gzipAsync(typeof body === "string" ? Buffer$1.from(body, "utf8") : body);
|
|
2507
|
+
headers["content-encoding"] = "gzip";
|
|
2508
|
+
}
|
|
2509
|
+
Object.assign(headers, env.headers);
|
|
2510
|
+
const bytes = typeof body === "string" ? Buffer$1.byteLength(body, "utf8") : body.length;
|
|
2511
|
+
const started = Date.now();
|
|
2512
|
+
let attempts = 0;
|
|
2513
|
+
let lastError = "export failed";
|
|
2514
|
+
let lastStatus;
|
|
2515
|
+
for (; ; ) {
|
|
2516
|
+
attempts += 1;
|
|
2517
|
+
const remaining = policy.maxElapsedMs - (Date.now() - started);
|
|
2518
|
+
const outcome = await attemptOnce(
|
|
2519
|
+
fetchFn,
|
|
2520
|
+
env.endpoint,
|
|
2521
|
+
{ method: "POST", headers, body },
|
|
2522
|
+
Math.max(1, Math.min(timeoutMs, remaining)),
|
|
2523
|
+
protocol
|
|
2524
|
+
);
|
|
2525
|
+
if (outcome.kind === "ok") {
|
|
2526
|
+
return { ok: true, attempts, status: outcome.status, spans, bytes, ...outcome.partialSuccess ? { partialSuccess: outcome.partialSuccess } : {} };
|
|
2527
|
+
}
|
|
2528
|
+
lastError = outcome.message;
|
|
2529
|
+
lastStatus = outcome.kind === "http" ? outcome.status : void 0;
|
|
2530
|
+
const retryable = outcome.kind === "network" || outcome.retryable;
|
|
2531
|
+
if (!retryable || attempts >= policy.maxAttempts) break;
|
|
2532
|
+
const ceiling = Math.min(policy.maxDelayMs, policy.initialDelayMs * 2 ** (attempts - 1));
|
|
2533
|
+
const wait = outcome.kind === "http" && outcome.retryAfter !== void 0 ? Math.min(outcome.retryAfter, policy.maxDelayMs) : Math.random() * ceiling;
|
|
2534
|
+
if (Date.now() - started + wait >= policy.maxElapsedMs) break;
|
|
2535
|
+
await sleep(wait);
|
|
2536
|
+
}
|
|
2537
|
+
return { ok: false, attempts, ...lastStatus !== void 0 ? { status: lastStatus } : {}, spans, bytes, error: lastError };
|
|
2538
|
+
} catch (err) {
|
|
2539
|
+
return { ok: false, attempts: 0, spans: 0, bytes: 0, error: err instanceof Error ? err.message : String(err) };
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
// src/utils/otlp/context.ts
|
|
2546
|
+
var TRACEPARENT = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/;
|
|
2547
|
+
var ALL_ZERO_TRACE = /^0{32}$/;
|
|
2548
|
+
var ALL_ZERO_SPAN = /^0{16}$/;
|
|
2549
|
+
var MAX_TRACESTATE = 512;
|
|
2550
|
+
function parseTraceparent(header) {
|
|
2551
|
+
if (typeof header !== "string") return void 0;
|
|
2552
|
+
const match = TRACEPARENT.exec(header.trim());
|
|
2553
|
+
if (!match) return void 0;
|
|
2554
|
+
const [, version, traceId, spanId, flagsHex, rest] = match;
|
|
2555
|
+
if (version === "ff") return void 0;
|
|
2556
|
+
if (version === "00" && rest) return void 0;
|
|
2557
|
+
if (ALL_ZERO_TRACE.test(traceId) || ALL_ZERO_SPAN.test(spanId)) return void 0;
|
|
2558
|
+
const flags = parseInt(flagsHex, 16);
|
|
2559
|
+
return { traceId, spanId, flags, sampled: (flags & 1) === 1 };
|
|
2560
|
+
}
|
|
2561
|
+
function formatTraceparent(parts) {
|
|
2562
|
+
const flags = typeof parts.flags === "number" ? parts.flags & 255 : parts.sampled === false ? 0 : 1;
|
|
2563
|
+
return `00-${parts.traceId}-${parts.spanId}-${flags.toString(16).padStart(2, "0")}`;
|
|
2564
|
+
}
|
|
2565
|
+
function traceparentOf(ctx) {
|
|
2566
|
+
if (!ctx?.traceId || !ctx.traceSpanId) return void 0;
|
|
2567
|
+
return formatTraceparent({ traceId: ctx.traceId, spanId: ctx.traceSpanId, flags: ctx.traceFlags ?? 1 });
|
|
2568
|
+
}
|
|
2569
|
+
function cleanTraceState(value) {
|
|
2570
|
+
if (typeof value !== "string") return void 0;
|
|
2571
|
+
const trimmed = value.trim();
|
|
2572
|
+
if (!trimmed || trimmed.length > MAX_TRACESTATE || !/^[\x20-\x7e]+$/.test(trimmed)) return void 0;
|
|
2573
|
+
return trimmed;
|
|
2574
|
+
}
|
|
2575
|
+
function resolveTraceParent(input) {
|
|
2576
|
+
if (input === void 0 || input === null) return void 0;
|
|
2577
|
+
const header = typeof input === "string" ? input : input?.traceparent;
|
|
2578
|
+
const parsed = parseTraceparent(header);
|
|
2579
|
+
if (!parsed) {
|
|
2580
|
+
warnOnce("[agent-sdk] Ignoring an invalid W3C traceparent; the trace starts a new root.");
|
|
2581
|
+
return void 0;
|
|
2582
|
+
}
|
|
2583
|
+
const traceState = typeof input === "object" ? cleanTraceState(input.tracestate) : void 0;
|
|
2584
|
+
return {
|
|
2585
|
+
traceId: parsed.traceId,
|
|
2586
|
+
spanId: parsed.spanId,
|
|
2587
|
+
flags: parsed.flags,
|
|
2588
|
+
sampled: parsed.sampled,
|
|
2589
|
+
remote: true,
|
|
2590
|
+
...traceState ? { traceState } : {}
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
function persistedParentOf(parent) {
|
|
2594
|
+
if (!parent) return void 0;
|
|
2595
|
+
return { spanId: parent.spanId, flags: parent.flags, ...parent.traceState ? { traceState: parent.traceState } : {} };
|
|
2596
|
+
}
|
|
2597
|
+
function readPersistedParent(value) {
|
|
2598
|
+
if (!value || typeof value !== "object") return void 0;
|
|
2599
|
+
const raw = value;
|
|
2600
|
+
if (typeof raw.spanId !== "string" || !/^[0-9a-f]{16}$/.test(raw.spanId) || ALL_ZERO_SPAN.test(raw.spanId)) return void 0;
|
|
2601
|
+
const flags = Number(raw.flags);
|
|
2602
|
+
if (!Number.isInteger(flags) || flags < 0 || flags > 255) return void 0;
|
|
2603
|
+
const traceState = cleanTraceState(raw.traceState);
|
|
2604
|
+
return { spanId: raw.spanId, flags, ...traceState ? { traceState } : {} };
|
|
2605
|
+
}
|
|
2606
|
+
function restoreParent(persisted, traceId) {
|
|
2607
|
+
return {
|
|
2608
|
+
traceId,
|
|
2609
|
+
spanId: persisted.spanId,
|
|
2610
|
+
flags: persisted.flags,
|
|
2611
|
+
sampled: (persisted.flags & 1) === 1,
|
|
2612
|
+
remote: true,
|
|
2613
|
+
...persisted.traceState ? { traceState: persisted.traceState } : {}
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
// src/utils/tracing.ts
|
|
1227
2618
|
var DEFAULT_COGNIPEER_URL = "https://console.cognipeer.com/api/client/v1/tracing/sessions";
|
|
1228
2619
|
function fileSink(path2) {
|
|
1229
2620
|
return { type: "file", path: path2 };
|
|
@@ -1249,8 +2640,9 @@ function cognipeerSink(first, second) {
|
|
|
1249
2640
|
function httpSink(url, headers) {
|
|
1250
2641
|
return { type: "http", url, headers };
|
|
1251
2642
|
}
|
|
1252
|
-
function otlpSink(
|
|
1253
|
-
return { type: "otlp",
|
|
2643
|
+
function otlpSink(first, headers, options) {
|
|
2644
|
+
if (first !== null && typeof first === "object") return { type: "otlp", ...first };
|
|
2645
|
+
return { type: "otlp", endpoint: first, headers, ...options ?? {} };
|
|
1254
2646
|
}
|
|
1255
2647
|
function resolveLogsBaseDir(customPath, ensureDirectory = true) {
|
|
1256
2648
|
const root = process.cwd();
|
|
@@ -1323,23 +2715,23 @@ function extractMetadata(model, paths) {
|
|
|
1323
2715
|
if (!model) return void 0;
|
|
1324
2716
|
for (const path2 of paths) {
|
|
1325
2717
|
const value = getNestedValue2(model, path2);
|
|
1326
|
-
const
|
|
1327
|
-
if (
|
|
2718
|
+
const str2 = coerceToString(value);
|
|
2719
|
+
if (str2) return str2;
|
|
1328
2720
|
}
|
|
1329
2721
|
const maybeLc = model?._lc;
|
|
1330
2722
|
if (maybeLc) {
|
|
1331
2723
|
for (const path2 of paths) {
|
|
1332
2724
|
const value = getNestedValue2(maybeLc, path2);
|
|
1333
|
-
const
|
|
1334
|
-
if (
|
|
2725
|
+
const str2 = coerceToString(value);
|
|
2726
|
+
if (str2) return str2;
|
|
1335
2727
|
}
|
|
1336
2728
|
}
|
|
1337
2729
|
const maybeClient = model?.client || model?.api || model?.service;
|
|
1338
2730
|
if (maybeClient) {
|
|
1339
2731
|
for (const path2 of paths) {
|
|
1340
2732
|
const value = getNestedValue2(maybeClient, path2);
|
|
1341
|
-
const
|
|
1342
|
-
if (
|
|
2733
|
+
const str2 = coerceToString(value);
|
|
2734
|
+
if (str2) return str2;
|
|
1343
2735
|
}
|
|
1344
2736
|
}
|
|
1345
2737
|
const constructorName = model?.constructor?.name;
|
|
@@ -1370,8 +2762,8 @@ function inferModelFromMessages(messageList) {
|
|
|
1370
2762
|
if (!message) continue;
|
|
1371
2763
|
for (const path2 of messagePaths) {
|
|
1372
2764
|
const value = getNestedValue2(message, path2);
|
|
1373
|
-
const
|
|
1374
|
-
if (
|
|
2765
|
+
const str2 = coerceToString(value);
|
|
2766
|
+
if (str2) return str2;
|
|
1375
2767
|
}
|
|
1376
2768
|
}
|
|
1377
2769
|
return void 0;
|
|
@@ -1389,8 +2781,8 @@ function inferProviderFromMessages(messageList) {
|
|
|
1389
2781
|
if (!message) continue;
|
|
1390
2782
|
for (const path2 of messagePaths) {
|
|
1391
2783
|
const value = getNestedValue2(message, path2);
|
|
1392
|
-
const
|
|
1393
|
-
if (
|
|
2784
|
+
const str2 = coerceToString(value);
|
|
2785
|
+
if (str2) return str2;
|
|
1394
2786
|
}
|
|
1395
2787
|
}
|
|
1396
2788
|
return void 0;
|
|
@@ -1452,12 +2844,18 @@ function resolveSink(sink) {
|
|
|
1452
2844
|
return headers ? { type: "http", url, headers } : { type: "http", url };
|
|
1453
2845
|
}
|
|
1454
2846
|
case "otlp": {
|
|
1455
|
-
const
|
|
1456
|
-
if (
|
|
2847
|
+
const given = candidate.endpoint;
|
|
2848
|
+
if (given !== void 0 && (typeof given !== "string" || given.trim().length === 0)) {
|
|
2849
|
+
throw new Error("otlp sink requires a non-empty endpoint");
|
|
2850
|
+
}
|
|
2851
|
+
let exporter;
|
|
2852
|
+
try {
|
|
2853
|
+
exporter = createOtlpExporter({ ...candidate, endpoint: given?.trim() });
|
|
2854
|
+
} catch {
|
|
1457
2855
|
throw new Error("otlp sink requires a non-empty endpoint");
|
|
1458
2856
|
}
|
|
1459
2857
|
const headers = candidate.headers ? { ...candidate.headers } : void 0;
|
|
1460
|
-
return headers ? { type: "otlp", endpoint, headers } : { type: "otlp", endpoint };
|
|
2858
|
+
return headers ? { type: "otlp", endpoint: exporter.endpoint, headers, exporter } : { type: "otlp", endpoint: exporter.endpoint, exporter };
|
|
1461
2859
|
}
|
|
1462
2860
|
default: {
|
|
1463
2861
|
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
@@ -1467,6 +2865,17 @@ function resolveSink(sink) {
|
|
|
1467
2865
|
}
|
|
1468
2866
|
}
|
|
1469
2867
|
}
|
|
2868
|
+
function withoutUserinfo(endpoint) {
|
|
2869
|
+
try {
|
|
2870
|
+
const url = new URL(endpoint);
|
|
2871
|
+
if (!url.username && !url.password) return endpoint;
|
|
2872
|
+
url.username = "";
|
|
2873
|
+
url.password = "";
|
|
2874
|
+
return url.toString();
|
|
2875
|
+
} catch {
|
|
2876
|
+
return endpoint;
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
1470
2879
|
function snapshotSink(runtime) {
|
|
1471
2880
|
const sink = runtime.resolvedConfig.sink;
|
|
1472
2881
|
switch (sink.type) {
|
|
@@ -1479,7 +2888,7 @@ function snapshotSink(runtime) {
|
|
|
1479
2888
|
case "http":
|
|
1480
2889
|
return { type: "http", url: sink.url };
|
|
1481
2890
|
case "otlp":
|
|
1482
|
-
return { type: "otlp", endpoint: sink.endpoint };
|
|
2891
|
+
return { type: "otlp", endpoint: withoutUserinfo(sink.endpoint) };
|
|
1483
2892
|
default:
|
|
1484
2893
|
return { type: "custom" };
|
|
1485
2894
|
}
|
|
@@ -1497,11 +2906,11 @@ var TRACE_HTTP_RETRYABLE_STATUS = /* @__PURE__ */ new Set([404, 408, 425, 429, 5
|
|
|
1497
2906
|
var TRACE_HTTP_RETRY_BASE_MS = 250;
|
|
1498
2907
|
var TRACE_HTTP_RETRY_MAX_MS = 4e3;
|
|
1499
2908
|
var RetryableHttpError = class extends Error {
|
|
1500
|
-
constructor(status, message,
|
|
2909
|
+
constructor(status, message, retryAfterMs2) {
|
|
1501
2910
|
super(message);
|
|
1502
2911
|
this.name = "RetryableHttpError";
|
|
1503
2912
|
this.status = status;
|
|
1504
|
-
this.retryAfterMs =
|
|
2913
|
+
this.retryAfterMs = retryAfterMs2;
|
|
1505
2914
|
}
|
|
1506
2915
|
};
|
|
1507
2916
|
function traceSleep(ms) {
|
|
@@ -1594,206 +3003,23 @@ async function postStreamingSessionEnd(baseUrl, headers, payload) {
|
|
|
1594
3003
|
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/end`;
|
|
1595
3004
|
await postJsonReliable(url, headers, payload, { retry: true });
|
|
1596
3005
|
}
|
|
1597
|
-
function
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
if (status === "success" || status === "completed") return 1;
|
|
1604
|
-
return 0;
|
|
1605
|
-
}
|
|
1606
|
-
function toOtlpSpanKind(type) {
|
|
1607
|
-
switch (type) {
|
|
1608
|
-
case "ai_call":
|
|
1609
|
-
case "summarization":
|
|
1610
|
-
return 3;
|
|
1611
|
-
// CLIENT — outgoing LLM request (the summarizer is one too)
|
|
1612
|
-
case "tool_call":
|
|
1613
|
-
return 1;
|
|
1614
|
-
// INTERNAL
|
|
1615
|
-
case "agent_iteration":
|
|
1616
|
-
return 1;
|
|
1617
|
-
// INTERNAL
|
|
1618
|
-
default:
|
|
1619
|
-
return 1;
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
function stringAttr(key, val) {
|
|
1623
|
-
return val != null ? { key, value: { stringValue: val } } : null;
|
|
1624
|
-
}
|
|
1625
|
-
function intAttr(key, val) {
|
|
1626
|
-
return val != null && !Number.isNaN(val) ? { key, value: { intValue: String(val) } } : null;
|
|
1627
|
-
}
|
|
1628
|
-
function doubleAttr(key, val) {
|
|
1629
|
-
return val != null && !Number.isNaN(val) ? { key, value: { doubleValue: val } } : null;
|
|
1630
|
-
}
|
|
1631
|
-
function eventToOtlpSpan(event) {
|
|
1632
|
-
const startNano = isoToUnixNano(event.timestamp);
|
|
1633
|
-
const endNano = event.durationMs != null ? `${new Date(new Date(event.timestamp).getTime() + event.durationMs).getTime()}000000` : startNano;
|
|
1634
|
-
const attrs = [
|
|
1635
|
-
stringAttr("cognipeer.event.type", event.type),
|
|
1636
|
-
stringAttr("cognipeer.event.label", event.label),
|
|
1637
|
-
intAttr("cognipeer.event.sequence", event.sequence),
|
|
1638
|
-
stringAttr("cognipeer.actor.scope", event.actor?.scope),
|
|
1639
|
-
stringAttr("cognipeer.actor.name", event.actor?.name),
|
|
1640
|
-
stringAttr("cognipeer.actor.role", event.actor?.role),
|
|
1641
|
-
stringAttr("cognipeer.model", event.model),
|
|
1642
|
-
intAttr("cognipeer.tokens.reasoning", event.reasoningTokens),
|
|
1643
|
-
stringAttr("cognipeer.finish_reason", event.finishReason),
|
|
1644
|
-
stringAttr("cognipeer.provider", event.provider),
|
|
1645
|
-
stringAttr("cognipeer.tool.details", event.toolDetails ? JSON.stringify(event.toolDetails) : void 0),
|
|
1646
|
-
intAttr("cognipeer.tokens.input", event.inputTokens),
|
|
1647
|
-
intAttr("cognipeer.tokens.output", event.outputTokens),
|
|
1648
|
-
intAttr("cognipeer.tokens.total", event.totalTokens),
|
|
1649
|
-
intAttr("cognipeer.tokens.cached_input", event.cachedInputTokens),
|
|
1650
|
-
intAttr("cognipeer.bytes.request", event.requestBytes),
|
|
1651
|
-
intAttr("cognipeer.bytes.response", event.responseBytes),
|
|
1652
|
-
stringAttr("cognipeer.tool.execution_id", event.toolExecutionId),
|
|
1653
|
-
stringAttr("cognipeer.retry_of", event.retryOf),
|
|
1654
|
-
stringAttr("cognipeer.event.id", event.id)
|
|
1655
|
-
].filter(Boolean);
|
|
1656
|
-
if (event.data?.sections && event.data.sections.length > 0) {
|
|
1657
|
-
try {
|
|
1658
|
-
attrs.push({ key: "cognipeer.sections", value: { stringValue: JSON.stringify(event.data.sections) } });
|
|
1659
|
-
} catch {
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
const span = {
|
|
1663
|
-
traceId: event.traceId,
|
|
1664
|
-
spanId: event.spanId,
|
|
1665
|
-
parentSpanId: event.parentSpanId || "",
|
|
1666
|
-
name: event.label || event.type,
|
|
1667
|
-
kind: toOtlpSpanKind(event.type),
|
|
1668
|
-
startTimeUnixNano: startNano,
|
|
1669
|
-
endTimeUnixNano: endNano,
|
|
1670
|
-
attributes: attrs,
|
|
1671
|
-
status: {
|
|
1672
|
-
code: toOtlpStatusCode(event.status),
|
|
1673
|
-
...event.status === "error" && event.error?.message ? { message: event.error.message } : {}
|
|
1674
|
-
}
|
|
1675
|
-
};
|
|
1676
|
-
if (event.error) {
|
|
1677
|
-
span.events = [{
|
|
1678
|
-
timeUnixNano: startNano,
|
|
1679
|
-
name: "exception",
|
|
1680
|
-
attributes: [
|
|
1681
|
-
{ key: "exception.message", value: { stringValue: event.error.message } },
|
|
1682
|
-
...event.error.stack ? [{ key: "exception.stacktrace", value: { stringValue: event.error.stack } }] : []
|
|
1683
|
-
]
|
|
1684
|
-
}];
|
|
1685
|
-
}
|
|
1686
|
-
return span;
|
|
1687
|
-
}
|
|
1688
|
-
function traceSessionToOtlp(session) {
|
|
1689
|
-
const traceId = session.traceId || generateTraceId();
|
|
1690
|
-
const rootSpanId = session.rootSpanId || generateSpanId();
|
|
1691
|
-
const startNano = isoToUnixNano(session.startedAt);
|
|
1692
|
-
const endNano = session.endedAt ? isoToUnixNano(session.endedAt) : startNano;
|
|
1693
|
-
const resourceAttrs = [
|
|
1694
|
-
{ key: "service.name", value: { stringValue: session.agent?.name || "cognipeer-agent" } },
|
|
1695
|
-
stringAttr("service.version", session.agent?.version),
|
|
1696
|
-
stringAttr("cognipeer.session.id", session.sessionId),
|
|
1697
|
-
stringAttr("cognipeer.thread.id", session.threadId),
|
|
1698
|
-
stringAttr("cognipeer.agent.model", session.agent?.model),
|
|
1699
|
-
stringAttr("cognipeer.agent.provider", session.agent?.provider),
|
|
1700
|
-
...Object.entries(session.metadata || {}).map(([key, value]) => stringAttr(`cognipeer.metadata.${key}`, value))
|
|
1701
|
-
].filter(Boolean);
|
|
1702
|
-
const rootAttrs = [
|
|
1703
|
-
stringAttr("cognipeer.session.status", session.status),
|
|
1704
|
-
doubleAttr("cognipeer.session.duration_ms", session.durationMs),
|
|
1705
|
-
intAttr("cognipeer.session.total_input_tokens", session.summary.totalInputTokens),
|
|
1706
|
-
intAttr("cognipeer.session.total_output_tokens", session.summary.totalOutputTokens),
|
|
1707
|
-
intAttr("cognipeer.session.total_cached_input_tokens", session.summary.totalCachedInputTokens),
|
|
1708
|
-
intAttr("cognipeer.session.total_bytes_in", session.summary.totalBytesIn),
|
|
1709
|
-
intAttr("cognipeer.session.total_bytes_out", session.summary.totalBytesOut),
|
|
1710
|
-
intAttr("cognipeer.session.event_count", session.events.length)
|
|
1711
|
-
].filter(Boolean);
|
|
1712
|
-
if (session.summary.eventCounts) {
|
|
1713
|
-
for (const [key, count] of Object.entries(session.summary.eventCounts)) {
|
|
1714
|
-
rootAttrs.push({ key: `cognipeer.session.event_count.${key}`, value: { intValue: String(count) } });
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
const rootSpan = {
|
|
1718
|
-
traceId,
|
|
1719
|
-
spanId: rootSpanId,
|
|
1720
|
-
parentSpanId: "",
|
|
1721
|
-
name: `agent_session: ${session.agent?.name || "agent"}`,
|
|
1722
|
-
kind: 1,
|
|
1723
|
-
// INTERNAL
|
|
1724
|
-
startTimeUnixNano: startNano,
|
|
1725
|
-
endTimeUnixNano: endNano,
|
|
1726
|
-
attributes: rootAttrs,
|
|
1727
|
-
status: {
|
|
1728
|
-
code: toOtlpStatusCode(session.status),
|
|
1729
|
-
...session.status === "error" && session.errors.length > 0 ? { message: session.errors.map((e) => e.message).join("; ") } : {}
|
|
1730
|
-
}
|
|
1731
|
-
};
|
|
1732
|
-
if (session.errors.length > 0) {
|
|
1733
|
-
rootSpan.events = session.errors.map((err) => ({
|
|
1734
|
-
timeUnixNano: err.timestamp ? isoToUnixNano(err.timestamp) : startNano,
|
|
1735
|
-
name: "exception",
|
|
1736
|
-
attributes: [
|
|
1737
|
-
{ key: "exception.message", value: { stringValue: err.message } },
|
|
1738
|
-
...err.stack ? [{ key: "exception.stacktrace", value: { stringValue: err.stack } }] : [],
|
|
1739
|
-
...err.type ? [{ key: "exception.type", value: { stringValue: err.type } }] : []
|
|
1740
|
-
]
|
|
1741
|
-
}));
|
|
1742
|
-
}
|
|
1743
|
-
const childSpans = session.events.map((event) => {
|
|
1744
|
-
const span = eventToOtlpSpan({
|
|
1745
|
-
...event,
|
|
1746
|
-
traceId: event.traceId || traceId,
|
|
1747
|
-
spanId: event.spanId || generateSpanId(),
|
|
1748
|
-
parentSpanId: event.parentSpanId || rootSpanId
|
|
1749
|
-
});
|
|
1750
|
-
return span;
|
|
3006
|
+
function traceSessionToOtlp(session, options = {}) {
|
|
3007
|
+
return sessionToOtlp(session, {
|
|
3008
|
+
semconv: "both",
|
|
3009
|
+
terminal: session.status !== "paused" && session.status !== "in_progress",
|
|
3010
|
+
...options,
|
|
3011
|
+
content: resolveContentOptions(options.content)
|
|
1751
3012
|
});
|
|
1752
|
-
return {
|
|
1753
|
-
resourceSpans: [{
|
|
1754
|
-
resource: { attributes: resourceAttrs },
|
|
1755
|
-
scopeSpans: [{
|
|
1756
|
-
scope: {
|
|
1757
|
-
name: "cognipeer-agent-sdk",
|
|
1758
|
-
version: "1.0.0"
|
|
1759
|
-
},
|
|
1760
|
-
spans: [rootSpan, ...childSpans]
|
|
1761
|
-
}]
|
|
1762
|
-
}]
|
|
1763
|
-
};
|
|
1764
3013
|
}
|
|
1765
|
-
|
|
1766
|
-
const
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
"
|
|
1772
|
-
...
|
|
3014
|
+
function traceErrorOf(err) {
|
|
3015
|
+
const e = err;
|
|
3016
|
+
const message = typeof e?.message === "string" && e.message ? e.message : String(err);
|
|
3017
|
+
const type = err instanceof Error && typeof err.name === "string" && err.name ? err.name : void 0;
|
|
3018
|
+
return {
|
|
3019
|
+
message,
|
|
3020
|
+
...typeof e?.stack === "string" ? { stack: e.stack } : {},
|
|
3021
|
+
...type ? { type } : {}
|
|
1773
3022
|
};
|
|
1774
|
-
try {
|
|
1775
|
-
const response = await fetchFn(endpoint, {
|
|
1776
|
-
method: "POST",
|
|
1777
|
-
headers: finalHeaders,
|
|
1778
|
-
body: JSON.stringify(payload)
|
|
1779
|
-
});
|
|
1780
|
-
if (!response.ok) {
|
|
1781
|
-
let responseText = "";
|
|
1782
|
-
try {
|
|
1783
|
-
responseText = await response.text();
|
|
1784
|
-
} catch {
|
|
1785
|
-
}
|
|
1786
|
-
const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
|
|
1787
|
-
const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
|
|
1788
|
-
throw new Error(`${statusLine}${bodyPreview}`);
|
|
1789
|
-
}
|
|
1790
|
-
} catch (err) {
|
|
1791
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1792
|
-
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
1793
|
-
console.error("[Tracing] OTLP export failed:", errMsg);
|
|
1794
|
-
}
|
|
1795
|
-
throw err;
|
|
1796
|
-
}
|
|
1797
3023
|
}
|
|
1798
3024
|
function createEmptySummary() {
|
|
1799
3025
|
return {
|
|
@@ -1813,10 +3039,16 @@ function generateEventId(sequence) {
|
|
|
1813
3039
|
return `evt_${String(sequence).padStart(4, "0")}_${nanoid(4)}`;
|
|
1814
3040
|
}
|
|
1815
3041
|
function generateTraceId() {
|
|
1816
|
-
|
|
3042
|
+
for (; ; ) {
|
|
3043
|
+
const id = crypto.randomBytes(16).toString("hex");
|
|
3044
|
+
if (/[1-9a-f]/.test(id)) return id;
|
|
3045
|
+
}
|
|
1817
3046
|
}
|
|
1818
3047
|
function generateSpanId() {
|
|
1819
|
-
|
|
3048
|
+
for (; ; ) {
|
|
3049
|
+
const id = crypto.randomBytes(8).toString("hex");
|
|
3050
|
+
if (/[1-9a-f]/.test(id)) return id;
|
|
3051
|
+
}
|
|
1820
3052
|
}
|
|
1821
3053
|
function defaultEventLabel(type) {
|
|
1822
3054
|
switch (type) {
|
|
@@ -2093,9 +3325,64 @@ function readTraceContinuation(value) {
|
|
|
2093
3325
|
nextSequence,
|
|
2094
3326
|
part,
|
|
2095
3327
|
summary,
|
|
2096
|
-
errors: Array.isArray(raw.errors) ? raw.errors : []
|
|
3328
|
+
errors: Array.isArray(raw.errors) ? raw.errors : [],
|
|
3329
|
+
...(() => {
|
|
3330
|
+
const parent = readPersistedParent(raw.parent);
|
|
3331
|
+
return parent ? { parent } : {};
|
|
3332
|
+
})(),
|
|
3333
|
+
...(() => {
|
|
3334
|
+
const pendingSpans = readPendingSpans(raw.pendingSpans);
|
|
3335
|
+
return pendingSpans.length > 0 ? { pendingSpans } : {};
|
|
3336
|
+
})()
|
|
2097
3337
|
};
|
|
2098
3338
|
}
|
|
3339
|
+
var MAX_CARRIED_SPANS = 64;
|
|
3340
|
+
var isSubagentSpanRecord = (event) => event.type === "span" && event.actor?.role === "subagent";
|
|
3341
|
+
function carriedSpanOf(record) {
|
|
3342
|
+
const identity2 = (record.data?.sections ?? []).filter(
|
|
3343
|
+
(section) => section.kind === "metadata" && section.identity === true
|
|
3344
|
+
);
|
|
3345
|
+
return {
|
|
3346
|
+
sessionId: record.sessionId,
|
|
3347
|
+
traceId: record.traceId,
|
|
3348
|
+
spanId: record.spanId,
|
|
3349
|
+
parentSpanId: record.parentSpanId,
|
|
3350
|
+
id: record.id,
|
|
3351
|
+
type: record.type,
|
|
3352
|
+
label: record.label,
|
|
3353
|
+
sequence: record.sequence,
|
|
3354
|
+
timestamp: record.timestamp,
|
|
3355
|
+
actor: record.actor,
|
|
3356
|
+
status: record.status,
|
|
3357
|
+
durationMs: record.durationMs,
|
|
3358
|
+
...identity2.length > 0 ? { data: { sections: identity2 } } : {}
|
|
3359
|
+
};
|
|
3360
|
+
}
|
|
3361
|
+
function readPendingSpans(value) {
|
|
3362
|
+
if (!Array.isArray(value)) return [];
|
|
3363
|
+
const out = [];
|
|
3364
|
+
for (const item of value.slice(0, MAX_CARRIED_SPANS)) {
|
|
3365
|
+
if (!item || typeof item !== "object") continue;
|
|
3366
|
+
const raw = item;
|
|
3367
|
+
if (typeof raw.spanId !== "string" || raw.spanId.length === 0) continue;
|
|
3368
|
+
if (raw.status !== "pending" || !isSubagentSpanRecord(raw)) continue;
|
|
3369
|
+
if (typeof raw.sequence !== "number" || !Number.isInteger(raw.sequence) || raw.sequence < 1) continue;
|
|
3370
|
+
if (typeof raw.timestamp !== "string" || Number.isNaN(Date.parse(raw.timestamp))) continue;
|
|
3371
|
+
if (typeof raw.label !== "string" || typeof raw.id !== "string" || typeof raw.sessionId !== "string") continue;
|
|
3372
|
+
if (raw.parentSpanId !== void 0 && typeof raw.parentSpanId !== "string") continue;
|
|
3373
|
+
if (raw.durationMs !== void 0 && (typeof raw.durationMs !== "number" || !Number.isFinite(raw.durationMs))) continue;
|
|
3374
|
+
out.push(carriedSpanOf(raw));
|
|
3375
|
+
}
|
|
3376
|
+
return out;
|
|
3377
|
+
}
|
|
3378
|
+
function pendingSpansOf(session) {
|
|
3379
|
+
const candidates = [
|
|
3380
|
+
...session.carriedSpans ?? [],
|
|
3381
|
+
...session.events.filter(isSubagentSpanRecord)
|
|
3382
|
+
];
|
|
3383
|
+
if (candidates.length === 0) return [];
|
|
3384
|
+
return foldSupersededSpans(candidates).filter((event) => event.status === "pending").slice(-MAX_CARRIED_SPANS).map(carriedSpanOf);
|
|
3385
|
+
}
|
|
2099
3386
|
function traceContinuationOf(session) {
|
|
2100
3387
|
return {
|
|
2101
3388
|
v: 1,
|
|
@@ -2109,15 +3396,32 @@ function traceContinuationOf(session) {
|
|
|
2109
3396
|
summary: JSON.parse(JSON.stringify(session.summary)),
|
|
2110
3397
|
// Sink failures belong to the part that hit them; carrying them on would
|
|
2111
3398
|
// mark every later part `partial`.
|
|
2112
|
-
errors: session.errors.filter((error) => error.type !== "sink")
|
|
3399
|
+
errors: session.errors.filter((error) => error.type !== "sink"),
|
|
3400
|
+
// Where the root hangs, so the leg that ends the run exports it under the same remote parent.
|
|
3401
|
+
...session.parent ? { parent: persistedParentOf(session.parent) } : {},
|
|
3402
|
+
...(() => {
|
|
3403
|
+
const pendingSpans = pendingSpansOf(session);
|
|
3404
|
+
return pendingSpans.length > 0 ? { pendingSpans } : {};
|
|
3405
|
+
})()
|
|
2113
3406
|
};
|
|
2114
3407
|
}
|
|
2115
|
-
function createTraceSession(opts, continuation) {
|
|
3408
|
+
function createTraceSession(opts, continuation, extras) {
|
|
2116
3409
|
const cfg = withDefaults(opts.tracing);
|
|
2117
3410
|
if (!cfg.enabled) return void 0;
|
|
3411
|
+
let parent;
|
|
3412
|
+
if (continuation) {
|
|
3413
|
+
if (continuation.parent && continuation.traceId) parent = restoreParent(continuation.parent, continuation.traceId);
|
|
3414
|
+
} else {
|
|
3415
|
+
parent = resolveTraceParent(extras?.traceParent ?? opts.tracing?.parent);
|
|
3416
|
+
}
|
|
3417
|
+
const exporters = [...extras?.exporters ?? []];
|
|
3418
|
+
const contentExporters = [
|
|
3419
|
+
...cfg.sink.type === "otlp" ? [cfg.sink.exporter] : [],
|
|
3420
|
+
...exporters
|
|
3421
|
+
].filter((exporter) => exporter.wantsContent);
|
|
2118
3422
|
const providedSessionId = opts.tracing?.sessionId?.trim();
|
|
2119
3423
|
const sessionId = continuation?.sessionId || providedSessionId || generateSessionId();
|
|
2120
|
-
const traceId = continuation?.traceId || generateTraceId();
|
|
3424
|
+
const traceId = continuation?.traceId || parent?.traceId || generateTraceId();
|
|
2121
3425
|
const rootSpanId = continuation?.rootSpanId || generateSpanId();
|
|
2122
3426
|
const runtime = {
|
|
2123
3427
|
sessionId,
|
|
@@ -2136,7 +3440,20 @@ function createTraceSession(opts, continuation) {
|
|
|
2136
3440
|
// again would reset a streaming receiver's copy.
|
|
2137
3441
|
sessionStarted: Boolean(continuation),
|
|
2138
3442
|
sequenceOffset: continuation ? continuation.nextSequence - 1 : 0,
|
|
2139
|
-
part: continuation ? continuation.part + 1 : 1
|
|
3443
|
+
part: continuation ? continuation.part + 1 : 1,
|
|
3444
|
+
...continuation?.pendingSpans?.length ? { carriedSpans: continuation.pendingSpans } : {},
|
|
3445
|
+
...exporters.length ? { exporters } : {},
|
|
3446
|
+
exportReports: [],
|
|
3447
|
+
...parent ? { parent } : {},
|
|
3448
|
+
...contentExporters.length > 0 ? {
|
|
3449
|
+
captureContent: true,
|
|
3450
|
+
captureLimits: {
|
|
3451
|
+
// Headroom over the export cap: a redact hook runs before the cap and must see a
|
|
3452
|
+
// secret whole, even one that straddles the point where the export cuts.
|
|
3453
|
+
maxStringChars: 4 * Math.max(...contentExporters.map((exporter) => exporter.contentOptions?.maxStringChars ?? 4096)),
|
|
3454
|
+
maxMessages: Math.max(...contentExporters.map((exporter) => exporter.contentOptions?.maxMessages ?? 32))
|
|
3455
|
+
}
|
|
3456
|
+
} : {}
|
|
2140
3457
|
};
|
|
2141
3458
|
if (cfg.sink.type === "file") {
|
|
2142
3459
|
const baseDir = cfg.sink.baseDir;
|
|
@@ -2203,7 +3520,7 @@ function recordTraceEvent(session, event) {
|
|
|
2203
3520
|
const baseLabel = event.label?.trim().length ? event.label.trim() : defaultEventLabel(event.type);
|
|
2204
3521
|
const eventLabel = `${baseLabel} #${sequence}`;
|
|
2205
3522
|
const durationMs = event.durationMs !== void 0 ? Number(event.durationMs) : void 0;
|
|
2206
|
-
if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0) {
|
|
3523
|
+
if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0 && event.countDuration !== false && !isSubagentTraceScope(session)) {
|
|
2207
3524
|
session.summary.totalDurationMs += durationMs;
|
|
2208
3525
|
}
|
|
2209
3526
|
const inputTokens = event.inputTokens !== void 0 ? Number(event.inputTokens) : void 0;
|
|
@@ -2252,10 +3569,20 @@ function recordTraceEvent(session, event) {
|
|
|
2252
3569
|
}
|
|
2253
3570
|
}
|
|
2254
3571
|
}
|
|
3572
|
+
if (!session.resolvedConfig.logData && event.sections?.length) {
|
|
3573
|
+
const identity2 = event.sections.filter((section) => section.kind === "metadata" && section.identity === true);
|
|
3574
|
+
if (identity2.length > 0) sections = ensureUniqueSections(id, identity2);
|
|
3575
|
+
}
|
|
3576
|
+
if (event.alwaysSections?.length) {
|
|
3577
|
+
const identity2 = event.alwaysSections.map(
|
|
3578
|
+
(section) => section.kind === "metadata" ? { ...section, identity: true } : section
|
|
3579
|
+
);
|
|
3580
|
+
sections = ensureUniqueSections(id, [...identity2, ...sections ?? []]);
|
|
3581
|
+
}
|
|
2255
3582
|
const resolvedModel = event.model ?? inferModelFromMessages(event.messageList);
|
|
2256
3583
|
const resolvedProvider = event.provider ?? inferProviderFromMessages(event.messageList);
|
|
2257
3584
|
const isAiCall = event.type === "ai_call";
|
|
2258
|
-
const spanId = generateSpanId();
|
|
3585
|
+
const spanId = event.spanId || generateSpanId();
|
|
2259
3586
|
const parentSpanId = event.parentSpanId || session.currentIterationSpanId || session.rootSpanId;
|
|
2260
3587
|
const record = {
|
|
2261
3588
|
sessionId: session.sessionId,
|
|
@@ -2286,6 +3613,16 @@ function recordTraceEvent(session, event) {
|
|
|
2286
3613
|
// different facts, and a zero would erase the difference.
|
|
2287
3614
|
...reasoningTokens !== void 0 && !Number.isNaN(reasoningTokens) ? { reasoningTokens } : {},
|
|
2288
3615
|
...event.finishReason ? { finishReason: event.finishReason } : {},
|
|
3616
|
+
// Provider facts: absent when the provider did not say, never zero or empty.
|
|
3617
|
+
...event.responseId ? { responseId: event.responseId } : {},
|
|
3618
|
+
...event.responseModel ? { responseModel: event.responseModel } : {},
|
|
3619
|
+
...event.rawFinishReason ? { rawFinishReason: event.rawFinishReason } : {},
|
|
3620
|
+
...typeof event.cacheWriteTokens === "number" && event.cacheWriteTokens > 0 ? { cacheWriteTokens: event.cacheWriteTokens } : {},
|
|
3621
|
+
...event.usageBasis && (event.usageBasis.inputExcludesCache || event.usageBasis.outputExcludesReasoning) ? { usageBasis: { ...event.usageBasis } } : {},
|
|
3622
|
+
...event.streaming ? { streaming: true } : {},
|
|
3623
|
+
...event.outputType ? { outputType: event.outputType } : {},
|
|
3624
|
+
...event.toolCallId ? { toolCallId: event.toolCallId } : {},
|
|
3625
|
+
...event.skipReason ? { skipReason: event.skipReason } : {},
|
|
2289
3626
|
requestBytes,
|
|
2290
3627
|
responseBytes,
|
|
2291
3628
|
model: resolvedModel,
|
|
@@ -2307,6 +3644,15 @@ function recordTraceEvent(session, event) {
|
|
|
2307
3644
|
timestamp: timestampIso
|
|
2308
3645
|
});
|
|
2309
3646
|
}
|
|
3647
|
+
if (session.captureContent && event.capture) {
|
|
3648
|
+
try {
|
|
3649
|
+
attachCapturedContent(
|
|
3650
|
+
record,
|
|
3651
|
+
buildCapturedContent(event.capture, session.captureLimits ?? { maxStringChars: 4096, maxMessages: 32 })
|
|
3652
|
+
);
|
|
3653
|
+
} catch {
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
2310
3656
|
session.events.push(record);
|
|
2311
3657
|
const sink = session.resolvedConfig.sink;
|
|
2312
3658
|
if (sink.type === "custom" && typeof sink.onEvent === "function") {
|
|
@@ -2349,6 +3695,69 @@ var DEFERRED_TRACE_EVENTS_KEY = "__deferredTraceEvents";
|
|
|
2349
3695
|
function isTraceSessionOpen(session) {
|
|
2350
3696
|
return Boolean(session) && !session.closed;
|
|
2351
3697
|
}
|
|
3698
|
+
var SUBAGENT_TRACE_SCOPE = Symbol("subagentTraceScope");
|
|
3699
|
+
function createSubagentTraceScope(parent, info) {
|
|
3700
|
+
const scope = { ...info, iterations: info.iterations ?? 0 };
|
|
3701
|
+
let currentIterationSpanId;
|
|
3702
|
+
return new Proxy(parent, {
|
|
3703
|
+
get(target, prop) {
|
|
3704
|
+
if (prop === SUBAGENT_TRACE_SCOPE) return scope;
|
|
3705
|
+
if (prop === "rootSpanId") return scope.agentSpanId;
|
|
3706
|
+
if (prop === "currentIterationSpanId") return currentIterationSpanId;
|
|
3707
|
+
return Reflect.get(target, prop);
|
|
3708
|
+
},
|
|
3709
|
+
set(target, prop, value) {
|
|
3710
|
+
if (prop === "currentIterationSpanId") {
|
|
3711
|
+
currentIterationSpanId = value;
|
|
3712
|
+
return true;
|
|
3713
|
+
}
|
|
3714
|
+
return Reflect.set(target, prop, value);
|
|
3715
|
+
}
|
|
3716
|
+
});
|
|
3717
|
+
}
|
|
3718
|
+
function subagentTraceScopeOf(session) {
|
|
3719
|
+
if (!session) return void 0;
|
|
3720
|
+
return session[SUBAGENT_TRACE_SCOPE];
|
|
3721
|
+
}
|
|
3722
|
+
function canPauseForHuman(session) {
|
|
3723
|
+
return subagentTraceScopeOf(session)?.hitl !== false;
|
|
3724
|
+
}
|
|
3725
|
+
function isSubagentTraceScope(session) {
|
|
3726
|
+
return subagentTraceScopeOf(session) !== void 0;
|
|
3727
|
+
}
|
|
3728
|
+
function recordSubagentSpan(session, span) {
|
|
3729
|
+
const sections = [];
|
|
3730
|
+
if (session.resolvedConfig.logData) {
|
|
3731
|
+
if (span.task !== void 0) sections.push({ kind: "message", label: "Task", role: "user", content: span.task });
|
|
3732
|
+
if (span.result) sections.push({ kind: "message", label: "Result", role: "assistant", content: span.result });
|
|
3733
|
+
}
|
|
3734
|
+
recordTraceEvent(session, {
|
|
3735
|
+
type: "span",
|
|
3736
|
+
spanId: span.spanId,
|
|
3737
|
+
parentSpanId: span.parentSpanId,
|
|
3738
|
+
label: `Sub-agent ${span.name}`,
|
|
3739
|
+
actor: { scope: "agent", name: span.name, role: "subagent" },
|
|
3740
|
+
status: span.status,
|
|
3741
|
+
durationMs: span.durationMs,
|
|
3742
|
+
// The child's own calls and the delegating tool_call already hold this time.
|
|
3743
|
+
countDuration: false,
|
|
3744
|
+
...span.error ? { error: { message: span.error } } : {},
|
|
3745
|
+
// The Console reads which sub-agent ran from here, so it survives logData off.
|
|
3746
|
+
alwaysSections: [{ kind: "metadata", label: "Sub-agent", data: sanitizeTracePayload(span.info) }],
|
|
3747
|
+
sections
|
|
3748
|
+
});
|
|
3749
|
+
}
|
|
3750
|
+
function foldSupersededSpans(events) {
|
|
3751
|
+
const rank = (event, index) => typeof event.sequence === "number" && Number.isFinite(event.sequence) ? event.sequence : index;
|
|
3752
|
+
const winner = /* @__PURE__ */ new Map();
|
|
3753
|
+
for (let i = 0; i < events.length; i++) {
|
|
3754
|
+
const id = events[i].spanId;
|
|
3755
|
+
if (!id) continue;
|
|
3756
|
+
const current = winner.get(id);
|
|
3757
|
+
if (current === void 0 || rank(events[i], i) >= rank(events[current], current)) winner.set(id, i);
|
|
3758
|
+
}
|
|
3759
|
+
return events.filter((event, i) => !(event.spanId && event.status === "pending" && winner.get(event.spanId) !== i));
|
|
3760
|
+
}
|
|
2352
3761
|
function recordOrDeferTraceEvent(ctx, event, options) {
|
|
2353
3762
|
const session = ctx?.__traceSession;
|
|
2354
3763
|
if (isTraceSessionOpen(session)) {
|
|
@@ -2359,7 +3768,8 @@ function recordOrDeferTraceEvent(ctx, event, options) {
|
|
|
2359
3768
|
const held = Array.isArray(ctx?.[DEFERRED_TRACE_EVENTS_KEY]) ? ctx[DEFERRED_TRACE_EVENTS_KEY] : [];
|
|
2360
3769
|
return {
|
|
2361
3770
|
...ctx || {},
|
|
2362
|
-
|
|
3771
|
+
// `capture` (content for exporters) is never parked on ctx, which callers persist.
|
|
3772
|
+
[DEFERRED_TRACE_EVENTS_KEY]: [...held, { ...event, capture: void 0, timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString() }]
|
|
2363
3773
|
};
|
|
2364
3774
|
}
|
|
2365
3775
|
function replayDeferredTraceEvents(session, deferred) {
|
|
@@ -2393,6 +3803,7 @@ async function finalizeTraceSession(session, params = {}) {
|
|
|
2393
3803
|
message: params.error.message || "Unknown error",
|
|
2394
3804
|
stack: params.error.stack,
|
|
2395
3805
|
type: "session",
|
|
3806
|
+
...params.error.name ? { errorName: params.error.name } : {},
|
|
2396
3807
|
timestamp: endedAtIso
|
|
2397
3808
|
});
|
|
2398
3809
|
}
|
|
@@ -2416,24 +3827,62 @@ async function finalizeTraceSession(session, params = {}) {
|
|
|
2416
3827
|
...(session.part ?? 1) > 1 ? { continuation: { part: session.part, firstSequence: (session.sequenceOffset ?? 0) + 1 } } : {}
|
|
2417
3828
|
});
|
|
2418
3829
|
const payloadForSink = buildPayload(initialStatus);
|
|
3830
|
+
const carried = session.carriedSpans ?? [];
|
|
3831
|
+
const exportPayload = carried.length > 0 ? { ...payloadForSink, events: [...carried, ...payloadForSink.events] } : payloadForSink;
|
|
2419
3832
|
let sinkFailed = false;
|
|
2420
3833
|
const sink = session.resolvedConfig.sink;
|
|
2421
3834
|
const isStreamingMode = session.resolvedConfig.mode === "streaming";
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
3835
|
+
const terminal = initialStatus !== "paused" && initialStatus !== "in_progress";
|
|
3836
|
+
const exportTargets = [];
|
|
3837
|
+
if (sink.type === "otlp") exportTargets.push({ exporter: sink.exporter, isSink: true });
|
|
3838
|
+
if (!isSubagentTraceScope(session)) {
|
|
3839
|
+
for (const exporter of session.exporters ?? []) exportTargets.push({ exporter, isSink: false });
|
|
3840
|
+
}
|
|
3841
|
+
const unsampled = session.parent !== void 0 && !session.parent.sampled;
|
|
3842
|
+
if (exportTargets.length > 0) {
|
|
3843
|
+
const results = await Promise.all(
|
|
3844
|
+
exportTargets.map(async ({ exporter }) => {
|
|
3845
|
+
if (unsampled) {
|
|
3846
|
+
return { ok: true, skipped: true, reason: "the upstream traceparent is not sampled (sampled=0)", attempts: 0, spans: 0, bytes: 0 };
|
|
3847
|
+
}
|
|
3848
|
+
try {
|
|
3849
|
+
return await exporter.exportSession(exportPayload, {
|
|
3850
|
+
terminal,
|
|
3851
|
+
cancelled: params.cancelled,
|
|
3852
|
+
parent: session.parent
|
|
3853
|
+
});
|
|
3854
|
+
} catch (err) {
|
|
3855
|
+
return { ok: false, attempts: 0, spans: 0, bytes: 0, error: err instanceof Error ? err.message : String(err) };
|
|
3856
|
+
}
|
|
3857
|
+
})
|
|
3858
|
+
);
|
|
3859
|
+
results.forEach((result, index) => {
|
|
3860
|
+
const { exporter, isSink } = exportTargets[index];
|
|
3861
|
+
(session.exportReports ?? (session.exportReports = [])).push({ exporter: exporter.name, endpoint: exporter.endpoint, sink: isSink, terminal, result });
|
|
3862
|
+
if (result.ok) {
|
|
3863
|
+
const rejected = result.partialSuccess?.rejectedSpans ?? 0;
|
|
3864
|
+
if ((rejected > 0 || result.partialSuccess?.message) && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
3865
|
+
const detail = result.partialSuccess?.message ? `: ${result.partialSuccess.message}` : "";
|
|
3866
|
+
console.warn(`[Tracing] OTLP exporter "${exporter.name}": the collector rejected ${rejected} span(s)${detail}`);
|
|
3867
|
+
}
|
|
3868
|
+
return;
|
|
3869
|
+
}
|
|
3870
|
+
const message = result.error ?? "OTLP export failed";
|
|
3871
|
+
if (isSink) {
|
|
3872
|
+
sinkFailed = true;
|
|
3873
|
+
session.errors.push({ eventId: "sink", message, type: "sink", timestamp: endedAtIso });
|
|
3874
|
+
if (typeof console !== "undefined" && typeof console.error === "function") {
|
|
3875
|
+
console.error("[Tracing] OTLP export failed:", message);
|
|
3876
|
+
}
|
|
3877
|
+
} else if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
3878
|
+
console.warn(`[Tracing] OTLP exporter "${exporter.name}" failed:`, message);
|
|
3879
|
+
}
|
|
3880
|
+
});
|
|
3881
|
+
}
|
|
3882
|
+
if (params.exportOnly) {
|
|
3883
|
+
return buildPayload(payloadForSink.status);
|
|
3884
|
+
}
|
|
3885
|
+
if (sink.type === "cognipeer" || sink.type === "http") {
|
|
2437
3886
|
try {
|
|
2438
3887
|
const headers = sink.type === "cognipeer" ? { Authorization: `Bearer ${sink.apiKey}` } : sink.headers;
|
|
2439
3888
|
if (isStreamingMode && session.sessionStarted) {
|
|
@@ -2529,6 +3978,23 @@ async function finalizeTraceSession(session, params = {}) {
|
|
|
2529
3978
|
}
|
|
2530
3979
|
return finalPayload;
|
|
2531
3980
|
}
|
|
3981
|
+
async function closeTraceContinuation(continuation, params = {}) {
|
|
3982
|
+
const parsed = readTraceContinuation(continuation);
|
|
3983
|
+
if (!parsed) return void 0;
|
|
3984
|
+
const tracing = { ...params.tracing ?? {}, enabled: true };
|
|
3985
|
+
const hasOtlpSink = withDefaults(tracing).sink.type === "otlp";
|
|
3986
|
+
if (!hasOtlpSink && !params.exporters?.length) return void 0;
|
|
3987
|
+
const session = createTraceSession({ tracing }, parsed, { exporters: params.exporters });
|
|
3988
|
+
if (!session) return void 0;
|
|
3989
|
+
replayDeferredTraceEvents(session, params.events);
|
|
3990
|
+
const status = params.status ?? "partial";
|
|
3991
|
+
return finalizeTraceSession(session, {
|
|
3992
|
+
agentRuntime: params.agentRuntime,
|
|
3993
|
+
status,
|
|
3994
|
+
error: status === "error" ? params.error ?? { message: "The run ended in an error before it could be resumed." } : null,
|
|
3995
|
+
exportOnly: true
|
|
3996
|
+
});
|
|
3997
|
+
}
|
|
2532
3998
|
function sanitizeTracePayload(value) {
|
|
2533
3999
|
if (value === void 0) return void 0;
|
|
2534
4000
|
try {
|
|
@@ -2568,6 +4034,72 @@ function estimatePayloadBytes(value) {
|
|
|
2568
4034
|
}
|
|
2569
4035
|
}
|
|
2570
4036
|
}
|
|
4037
|
+
|
|
4038
|
+
// src/providers/wireInfo.ts
|
|
4039
|
+
var WIRE_INFO = Symbol.for("cognipeer.agent-sdk.wireInfo");
|
|
4040
|
+
function usageBasisOf(provider) {
|
|
4041
|
+
switch (provider) {
|
|
4042
|
+
case "anthropic":
|
|
4043
|
+
case "bedrock":
|
|
4044
|
+
return { inputExcludesCache: true };
|
|
4045
|
+
case "vertex":
|
|
4046
|
+
return { outputExcludesReasoning: true };
|
|
4047
|
+
default:
|
|
4048
|
+
return void 0;
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
function attachWireInfo(message, info) {
|
|
4052
|
+
const clean = {};
|
|
4053
|
+
if (info.provider) clean.provider = info.provider;
|
|
4054
|
+
if (info.responseId) clean.responseId = info.responseId;
|
|
4055
|
+
if (info.responseModel) clean.responseModel = info.responseModel;
|
|
4056
|
+
if (info.rawFinishReason) clean.rawFinishReason = info.rawFinishReason;
|
|
4057
|
+
if (info.streaming) clean.streaming = true;
|
|
4058
|
+
const basis = info.usageBasis ?? usageBasisOf(info.provider);
|
|
4059
|
+
if (basis) clean.usageBasis = basis;
|
|
4060
|
+
message[WIRE_INFO] = clean;
|
|
4061
|
+
return message;
|
|
4062
|
+
}
|
|
4063
|
+
function wireInfoOf(message) {
|
|
4064
|
+
if (!message || typeof message !== "object") return void 0;
|
|
4065
|
+
return message[WIRE_INFO];
|
|
4066
|
+
}
|
|
4067
|
+
|
|
4068
|
+
// src/utils/traceFacts.ts
|
|
4069
|
+
var nonEmpty2 = (value) => typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
4070
|
+
var isRunId = (id) => /^(run-|lc_run)/i.test(id);
|
|
4071
|
+
function providerHintOf(model, response) {
|
|
4072
|
+
const named = getProviderName(model);
|
|
4073
|
+
if (named) return named;
|
|
4074
|
+
const fromWire = wireInfoOf(response)?.provider;
|
|
4075
|
+
if (fromWire) return fromWire;
|
|
4076
|
+
try {
|
|
4077
|
+
return nonEmpty2(getModelCapabilities(model).provider);
|
|
4078
|
+
} catch {
|
|
4079
|
+
return void 0;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
function traceResponseFacts(model, response, rawUsage, streaming) {
|
|
4083
|
+
const wire = wireInfoOf(response);
|
|
4084
|
+
const meta = response?.response_metadata ?? {};
|
|
4085
|
+
const message = response;
|
|
4086
|
+
const idCandidate = nonEmpty2(wire?.responseId) ?? nonEmpty2(meta.id) ?? nonEmpty2(message?.id);
|
|
4087
|
+
const responseId = idCandidate && !isRunId(idCandidate) ? idCandidate : void 0;
|
|
4088
|
+
const responseModel = nonEmpty2(wire?.responseModel) ?? nonEmpty2(meta.model_name) ?? nonEmpty2(meta.model) ?? nonEmpty2(meta.modelName);
|
|
4089
|
+
const rawFinishReason = nonEmpty2(wire?.rawFinishReason) ?? nonEmpty2(meta.stop_reason) ?? nonEmpty2(meta.finish_reason) ?? nonEmpty2(meta.finishReason);
|
|
4090
|
+
const cacheWriteTokens = cacheWriteTokensOf(rawUsage);
|
|
4091
|
+
const provider = providerHintOf(model, response);
|
|
4092
|
+
const isStreaming = streaming ?? wire?.streaming;
|
|
4093
|
+
return {
|
|
4094
|
+
...provider ? { provider } : {},
|
|
4095
|
+
...responseId ? { responseId } : {},
|
|
4096
|
+
...responseModel ? { responseModel } : {},
|
|
4097
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
4098
|
+
...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {},
|
|
4099
|
+
...wire?.usageBasis ? { usageBasis: { ...wire.usageBasis } } : {},
|
|
4100
|
+
...isStreaming ? { streaming: true } : {}
|
|
4101
|
+
};
|
|
4102
|
+
}
|
|
2571
4103
|
function toMessageUsage(u) {
|
|
2572
4104
|
return {
|
|
2573
4105
|
prompt_tokens: u.inputTokens,
|
|
@@ -2590,7 +4122,12 @@ function fromNativeProvider(provider, options) {
|
|
|
2590
4122
|
if (link.signal) request.signal = link.signal;
|
|
2591
4123
|
request = await applyTransform(request);
|
|
2592
4124
|
const response = await provider.complete(request);
|
|
2593
|
-
return toBaseChatMessage(response)
|
|
4125
|
+
return attachWireInfo(toBaseChatMessage(response), {
|
|
4126
|
+
provider: provider.providerName,
|
|
4127
|
+
responseId: response.id,
|
|
4128
|
+
responseModel: response.model,
|
|
4129
|
+
rawFinishReason: response.rawFinishReason
|
|
4130
|
+
});
|
|
2594
4131
|
} finally {
|
|
2595
4132
|
link.dispose();
|
|
2596
4133
|
}
|
|
@@ -2609,6 +4146,8 @@ function fromNativeProvider(provider, options) {
|
|
|
2609
4146
|
let reasoningText = "";
|
|
2610
4147
|
let finishReason;
|
|
2611
4148
|
let responseModel;
|
|
4149
|
+
let responseId;
|
|
4150
|
+
let rawFinishReason;
|
|
2612
4151
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
2613
4152
|
for await (const chunk of provider.completeStream(request)) {
|
|
2614
4153
|
if (chunk.delta.content) {
|
|
@@ -2616,6 +4155,8 @@ function fromNativeProvider(provider, options) {
|
|
|
2616
4155
|
yield chunk.delta.content;
|
|
2617
4156
|
}
|
|
2618
4157
|
if (chunk.model) responseModel = chunk.model;
|
|
4158
|
+
if (chunk.id) responseId = chunk.id;
|
|
4159
|
+
if (chunk.rawFinishReason) rawFinishReason = chunk.rawFinishReason;
|
|
2619
4160
|
if (chunk.finishReason) finishReason = chunk.finishReason;
|
|
2620
4161
|
if (chunk.delta.reasoning?.blocks?.length) {
|
|
2621
4162
|
reasoningBlocks = chunk.delta.reasoning.blocks;
|
|
@@ -2637,7 +4178,8 @@ function fromNativeProvider(provider, options) {
|
|
|
2637
4178
|
id: tc.id,
|
|
2638
4179
|
name: tc.name ?? "",
|
|
2639
4180
|
arguments: tc.arguments ?? "",
|
|
2640
|
-
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
4181
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {},
|
|
4182
|
+
...tc.idSynthesized ? { idSynthesized: true } : {}
|
|
2641
4183
|
});
|
|
2642
4184
|
}
|
|
2643
4185
|
}
|
|
@@ -2661,7 +4203,13 @@ function fromNativeProvider(provider, options) {
|
|
|
2661
4203
|
...responseModel ? { model_name: responseModel } : {}
|
|
2662
4204
|
};
|
|
2663
4205
|
}
|
|
2664
|
-
yield finalMessage
|
|
4206
|
+
yield attachWireInfo(finalMessage, {
|
|
4207
|
+
provider: provider.providerName,
|
|
4208
|
+
responseId,
|
|
4209
|
+
responseModel,
|
|
4210
|
+
rawFinishReason,
|
|
4211
|
+
streaming: true
|
|
4212
|
+
});
|
|
2665
4213
|
} finally {
|
|
2666
4214
|
link.dispose();
|
|
2667
4215
|
}
|
|
@@ -3035,7 +4583,8 @@ function toBaseChatMessage(response) {
|
|
|
3035
4583
|
id: tc.id,
|
|
3036
4584
|
type: "function",
|
|
3037
4585
|
function: { name: tc.name, arguments: tc.arguments },
|
|
3038
|
-
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
4586
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {},
|
|
4587
|
+
...tc.idSynthesized ? { idSynthesized: true } : {}
|
|
3039
4588
|
}));
|
|
3040
4589
|
}
|
|
3041
4590
|
if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
|
|
@@ -3057,7 +4606,8 @@ function assembleMessage(content, toolCalls, usage) {
|
|
|
3057
4606
|
id: tc.id,
|
|
3058
4607
|
type: "function",
|
|
3059
4608
|
function: { name: tc.name, arguments: tc.arguments },
|
|
3060
|
-
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
4609
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {},
|
|
4610
|
+
...tc.idSynthesized ? { idSynthesized: true } : {}
|
|
3061
4611
|
}));
|
|
3062
4612
|
}
|
|
3063
4613
|
return msg;
|
|
@@ -3951,7 +5501,7 @@ var CCRStore = class _CCRStore {
|
|
|
3951
5501
|
}
|
|
3952
5502
|
static hashOf(value) {
|
|
3953
5503
|
const serialized = typeof value === "string" ? value : JSON.stringify(value);
|
|
3954
|
-
return createHash("
|
|
5504
|
+
return createHash("sha256").update(serialized).digest("hex").slice(0, 16);
|
|
3955
5505
|
}
|
|
3956
5506
|
};
|
|
3957
5507
|
var DedupTracker = class {
|
|
@@ -3964,7 +5514,7 @@ var DedupTracker = class {
|
|
|
3964
5514
|
* first time it has been seen.
|
|
3965
5515
|
*/
|
|
3966
5516
|
checkAndRegister(content, executionId, toolName) {
|
|
3967
|
-
const hash = createHash("
|
|
5517
|
+
const hash = createHash("sha256").update(content).digest("hex");
|
|
3968
5518
|
const existing = this.seen.get(hash);
|
|
3969
5519
|
if (!existing) {
|
|
3970
5520
|
this.seen.set(hash, { executionId, toolName });
|
|
@@ -4501,7 +6051,7 @@ function createAgentCoreNode(opts) {
|
|
|
4501
6051
|
const actorVersion = runtime.version ?? opts.version;
|
|
4502
6052
|
let traceToolDefinitions;
|
|
4503
6053
|
const computeTraceToolDefinitions = (menu) => {
|
|
4504
|
-
if (!traceSession || !traceSession.resolvedConfig.logData || menu.length === 0) return void 0;
|
|
6054
|
+
if (!traceSession || !(traceSession.resolvedConfig.logData || traceSession.captureContent) || menu.length === 0) return void 0;
|
|
4505
6055
|
try {
|
|
4506
6056
|
const wire = shouldUseStrictToolCalling ? prepareStrictToolMenu(menu).menu : menu;
|
|
4507
6057
|
return wire.map((tool) => {
|
|
@@ -4714,8 +6264,9 @@ ${append}`;
|
|
|
4714
6264
|
// outcome, and an "error" status would flip the whole trace session
|
|
4715
6265
|
// status to error for a run that behaved exactly as configured.
|
|
4716
6266
|
status: "skipped",
|
|
6267
|
+
skipReason: "blocked",
|
|
4717
6268
|
model: getModelName(runtime.model || opts.model),
|
|
4718
|
-
provider:
|
|
6269
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
4719
6270
|
messageList: state.messages
|
|
4720
6271
|
});
|
|
4721
6272
|
return {
|
|
@@ -4744,9 +6295,12 @@ ${append}`;
|
|
|
4744
6295
|
for (const key of ["usage", "usage_metadata", "response_metadata"]) {
|
|
4745
6296
|
if (merged[key] === void 0 && original?.[key] !== void 0) merged[key] = original[key];
|
|
4746
6297
|
}
|
|
6298
|
+
if (wireInfoOf(merged) === void 0 && wireInfoOf(original) !== void 0) merged[WIRE_INFO] = wireInfoOf(original);
|
|
4747
6299
|
return merged;
|
|
4748
6300
|
};
|
|
4749
6301
|
let response;
|
|
6302
|
+
let sentMessages;
|
|
6303
|
+
let streamedCall = false;
|
|
4750
6304
|
let modelAttempt = 0;
|
|
4751
6305
|
const maxModelRetries = host?.maxModelRetries ?? 0;
|
|
4752
6306
|
const finishCancelledTurn = (partialText) => {
|
|
@@ -4760,12 +6314,16 @@ ${append}`;
|
|
|
4760
6314
|
// "skipped", not "error": the call did not fail, the caller ended it —
|
|
4761
6315
|
// and an "error" would flip the whole session to error.
|
|
4762
6316
|
status: "skipped",
|
|
6317
|
+
// The call reached the provider and was hung up on: still a model call, not a skipped one.
|
|
6318
|
+
skipReason: "cancelled",
|
|
6319
|
+
...streamedCall ? { streaming: true } : {},
|
|
4763
6320
|
durationMs: Date.now() - start,
|
|
4764
6321
|
requestBytes: promptBytes,
|
|
4765
6322
|
model: getModelName(runtime.model || opts.model),
|
|
4766
|
-
provider:
|
|
6323
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
4767
6324
|
messageList: state.messages,
|
|
4768
|
-
toolDefinitions: traceToolDefinitions
|
|
6325
|
+
toolDefinitions: traceToolDefinitions,
|
|
6326
|
+
capture: { input: sentMessages ?? wireMessages, toolDefinitions: traceToolDefinitions }
|
|
4769
6327
|
});
|
|
4770
6328
|
onEvent?.({ type: "cancelled", stage: "agent", reason });
|
|
4771
6329
|
onProgress?.({ stage: "agent", message: "Cancelled", detail: { reason } });
|
|
@@ -4781,8 +6339,9 @@ ${append}`;
|
|
|
4781
6339
|
label: "Assistant (plugin short-circuit)",
|
|
4782
6340
|
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
4783
6341
|
status: "skipped",
|
|
6342
|
+
skipReason: "short_circuit",
|
|
4784
6343
|
model: getModelName(runtime.model || opts.model),
|
|
4785
|
-
provider:
|
|
6344
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
4786
6345
|
messageList: state.messages,
|
|
4787
6346
|
toolDefinitions: traceToolDefinitions
|
|
4788
6347
|
});
|
|
@@ -4790,8 +6349,10 @@ ${append}`;
|
|
|
4790
6349
|
let streamedText = "";
|
|
4791
6350
|
try {
|
|
4792
6351
|
const normalizedMessages = normalizeBedrockToolPairing([...wireMessages]);
|
|
6352
|
+
sentMessages = normalizedMessages;
|
|
4793
6353
|
debugToolPairing(normalizedMessages);
|
|
4794
6354
|
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
6355
|
+
streamedCall = true;
|
|
4795
6356
|
let streamedMessage;
|
|
4796
6357
|
let cutByCancel = false;
|
|
4797
6358
|
for await (const chunk of modelWithTools.stream(normalizedMessages, invokeParams)) {
|
|
@@ -4837,12 +6398,14 @@ ${append}`;
|
|
|
4837
6398
|
durationMs: durationMs2,
|
|
4838
6399
|
requestBytes: promptBytes,
|
|
4839
6400
|
model: getModelName(runtime.model || opts.model),
|
|
4840
|
-
provider:
|
|
4841
|
-
error:
|
|
6401
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
6402
|
+
error: traceErrorOf(err),
|
|
6403
|
+
...streamedCall ? { streaming: true } : {},
|
|
4842
6404
|
messageList: state.messages,
|
|
4843
6405
|
toolDefinitions: traceToolDefinitions,
|
|
4844
6406
|
responseFormat: traceResponseFormat,
|
|
4845
|
-
responseFormatStrategy: traceResponseFormatStrategy
|
|
6407
|
+
responseFormatStrategy: traceResponseFormatStrategy,
|
|
6408
|
+
capture: { input: sentMessages ?? wireMessages, toolDefinitions: traceToolDefinitions }
|
|
4846
6409
|
});
|
|
4847
6410
|
throw err;
|
|
4848
6411
|
}
|
|
@@ -4895,6 +6458,8 @@ ${append}`;
|
|
|
4895
6458
|
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
4896
6459
|
const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
|
|
4897
6460
|
const finishReason = response?.response_metadata?.finish_reason ?? response?.response_metadata?.finishReason ?? response?.finishReason;
|
|
6461
|
+
const facts = traceResponseFacts(runtime.model || opts.model, response, rawUsage, streamedCall);
|
|
6462
|
+
const jsonOutput = Boolean(responseFormat) && responseFormat?.response_format?.type !== "text" && responseFormat?.type !== "text";
|
|
4898
6463
|
recordTraceEvent(traceSession, {
|
|
4899
6464
|
type: "ai_call",
|
|
4900
6465
|
label: "Assistant Response",
|
|
@@ -4911,11 +6476,13 @@ ${append}`;
|
|
|
4911
6476
|
requestBytes: promptBytes,
|
|
4912
6477
|
responseBytes,
|
|
4913
6478
|
model: modelName,
|
|
4914
|
-
|
|
6479
|
+
...facts,
|
|
6480
|
+
outputType: jsonOutput ? "json" : "text",
|
|
4915
6481
|
messageList: messagesWithResponse,
|
|
4916
6482
|
toolDefinitions: traceToolDefinitions,
|
|
4917
6483
|
responseFormat: traceResponseFormat,
|
|
4918
|
-
responseFormatStrategy: traceResponseFormatStrategy
|
|
6484
|
+
responseFormatStrategy: traceResponseFormatStrategy,
|
|
6485
|
+
capture: { input: sentMessages ?? wireMessages, output: response, toolDefinitions: traceToolDefinitions }
|
|
4919
6486
|
});
|
|
4920
6487
|
if (normalized) {
|
|
4921
6488
|
recordUsage(state, modelName, normalized);
|
|
@@ -4926,6 +6493,9 @@ ${append}`;
|
|
|
4926
6493
|
|
|
4927
6494
|
// src/utils/traceDecisions.ts
|
|
4928
6495
|
var TRACED_KEY = "__outcomeTraced";
|
|
6496
|
+
function surfacedFromSubagent(entry) {
|
|
6497
|
+
return Boolean(entry.metadata?.__subagent);
|
|
6498
|
+
}
|
|
4929
6499
|
function waitedMs(from, to) {
|
|
4930
6500
|
if (!from || !to) return void 0;
|
|
4931
6501
|
const ms = Date.parse(to) - Date.parse(from);
|
|
@@ -4938,8 +6508,14 @@ function sameJson(a, b) {
|
|
|
4938
6508
|
return false;
|
|
4939
6509
|
}
|
|
4940
6510
|
}
|
|
6511
|
+
var idSection = (label, data) => ({
|
|
6512
|
+
kind: "metadata",
|
|
6513
|
+
label,
|
|
6514
|
+
data,
|
|
6515
|
+
identity: true
|
|
6516
|
+
});
|
|
4941
6517
|
function recordApprovalRequested(session, entry) {
|
|
4942
|
-
if (!session) return;
|
|
6518
|
+
if (!session || surfacedFromSubagent(entry) || !canPauseForHuman(session)) return;
|
|
4943
6519
|
const logData = session.resolvedConfig.logData;
|
|
4944
6520
|
const sections = [
|
|
4945
6521
|
{
|
|
@@ -4963,14 +6539,14 @@ function recordApprovalRequested(session, entry) {
|
|
|
4963
6539
|
timestamp: entry.requestedAt,
|
|
4964
6540
|
status: "pending",
|
|
4965
6541
|
actor: { scope: "agent", name: entry.toolName, role: "approval_request" },
|
|
4966
|
-
sections
|
|
6542
|
+
sections: [...sections, idSection("Approval ids", { approvalId: entry.id, toolCallId: entry.toolCallId, status: "pending", requestedAt: entry.requestedAt })]
|
|
4967
6543
|
});
|
|
4968
6544
|
}
|
|
4969
6545
|
function recordHumanDecisions(session, state) {
|
|
4970
6546
|
if (!session) return;
|
|
4971
6547
|
const logData = session.resolvedConfig.logData;
|
|
4972
6548
|
for (const entry of state.pendingApprovals ?? []) {
|
|
4973
|
-
if (!entry.decidedAt || entry.metadata?.[TRACED_KEY]) continue;
|
|
6549
|
+
if (!entry.decidedAt || entry.metadata?.[TRACED_KEY] || surfacedFromSubagent(entry)) continue;
|
|
4974
6550
|
if (entry.status !== "approved" && entry.status !== "rejected") continue;
|
|
4975
6551
|
const approved = entry.status === "approved";
|
|
4976
6552
|
const edited = approved && entry.approvedArgs !== void 0 && !sameJson(entry.approvedArgs, entry.args);
|
|
@@ -5004,12 +6580,19 @@ function recordHumanDecisions(session, state) {
|
|
|
5004
6580
|
durationMs: waitedMs(entry.requestedAt, entry.decidedAt),
|
|
5005
6581
|
status: "success",
|
|
5006
6582
|
actor: { scope: "human", name: entry.decidedBy || "reviewer", role: "approver" },
|
|
5007
|
-
sections
|
|
6583
|
+
sections: [...sections, idSection("Decision ids", {
|
|
6584
|
+
approvalId: entry.id,
|
|
6585
|
+
toolCallId: entry.toolCallId,
|
|
6586
|
+
decision: entry.status,
|
|
6587
|
+
requestedAt: entry.requestedAt,
|
|
6588
|
+
decidedAt: entry.decidedAt,
|
|
6589
|
+
...waitedMs(entry.requestedAt, entry.decidedAt) !== void 0 ? { waitedMs: waitedMs(entry.requestedAt, entry.decidedAt) } : {}
|
|
6590
|
+
})]
|
|
5008
6591
|
});
|
|
5009
6592
|
entry.metadata = { ...entry.metadata || {}, [TRACED_KEY]: true };
|
|
5010
6593
|
}
|
|
5011
6594
|
for (const entry of state.pendingUserQuestions ?? []) {
|
|
5012
|
-
if (!entry.answeredAt || entry.metadata?.[TRACED_KEY]) continue;
|
|
6595
|
+
if (!entry.answeredAt || entry.metadata?.[TRACED_KEY] || surfacedFromSubagent(entry)) continue;
|
|
5013
6596
|
if (entry.status !== "answered" && entry.status !== "cancelled") continue;
|
|
5014
6597
|
const clientTool = readClientTool(entry);
|
|
5015
6598
|
if (clientTool) {
|
|
@@ -5049,13 +6632,20 @@ function recordHumanDecisions(session, state) {
|
|
|
5049
6632
|
durationMs: waitedMs(entry.requestedAt, entry.answeredAt),
|
|
5050
6633
|
status: cancelled ? "skipped" : "success",
|
|
5051
6634
|
actor: { scope: "human", name: entry.answeredBy || "user", role: "user" },
|
|
5052
|
-
sections
|
|
6635
|
+
sections: [...sections, idSection("Answer ids", {
|
|
6636
|
+
questionId: entry.id,
|
|
6637
|
+
toolCallId: entry.toolCallId,
|
|
6638
|
+
status: entry.status,
|
|
6639
|
+
requestedAt: entry.requestedAt,
|
|
6640
|
+
answeredAt: entry.answeredAt,
|
|
6641
|
+
...waitedMs(entry.requestedAt, entry.answeredAt) !== void 0 ? { waitedMs: waitedMs(entry.requestedAt, entry.answeredAt) } : {}
|
|
6642
|
+
})]
|
|
5053
6643
|
});
|
|
5054
6644
|
entry.metadata = { ...entry.metadata || {}, [TRACED_KEY]: true };
|
|
5055
6645
|
}
|
|
5056
6646
|
}
|
|
5057
6647
|
function recordClientToolRequested(session, entry) {
|
|
5058
|
-
if (!session) return;
|
|
6648
|
+
if (!session || surfacedFromSubagent(entry) || !canPauseForHuman(session)) return;
|
|
5059
6649
|
const clientTool = readClientTool(entry);
|
|
5060
6650
|
if (!clientTool) return;
|
|
5061
6651
|
const sections = [
|
|
@@ -5074,7 +6664,7 @@ function recordClientToolRequested(session, entry) {
|
|
|
5074
6664
|
timestamp: entry.requestedAt,
|
|
5075
6665
|
status: "pending",
|
|
5076
6666
|
actor: { scope: "client", name: clientTool.name, role: "tool" },
|
|
5077
|
-
sections
|
|
6667
|
+
sections: [...sections, idSection("Client tool ids", { questionId: entry.id, toolCallId: entry.toolCallId, status: "pending", requestedAt: entry.requestedAt })]
|
|
5078
6668
|
});
|
|
5079
6669
|
}
|
|
5080
6670
|
function readClientTool(entry) {
|
|
@@ -5121,7 +6711,14 @@ function recordClientToolResult(session, entry, clientTool, toolHistory) {
|
|
|
5121
6711
|
durationMs: waitedMs(entry.requestedAt, entry.answeredAt) ?? ranMs,
|
|
5122
6712
|
status: failed ? "error" : "success",
|
|
5123
6713
|
actor: { scope: "client", name: clientTool.name, role: "tool" },
|
|
5124
|
-
sections
|
|
6714
|
+
sections: [...sections, idSection("Client tool ids", {
|
|
6715
|
+
questionId: entry.id,
|
|
6716
|
+
toolCallId: entry.toolCallId,
|
|
6717
|
+
status: failed ? "error" : "answered",
|
|
6718
|
+
requestedAt: entry.requestedAt,
|
|
6719
|
+
answeredAt: entry.answeredAt,
|
|
6720
|
+
...waitedMs(entry.requestedAt, entry.answeredAt) !== void 0 ? { waitedMs: waitedMs(entry.requestedAt, entry.answeredAt) } : {}
|
|
6721
|
+
})]
|
|
5125
6722
|
});
|
|
5126
6723
|
}
|
|
5127
6724
|
|
|
@@ -5227,9 +6824,11 @@ function normalizeToolCall(call) {
|
|
|
5227
6824
|
return {
|
|
5228
6825
|
id: call.id,
|
|
5229
6826
|
name,
|
|
5230
|
-
args: call.args ?? call.arguments ?? call.input ?? call.function?.arguments ?? call.function_call?.arguments
|
|
6827
|
+
args: call.args ?? call.arguments ?? call.input ?? call.function?.arguments ?? call.function_call?.arguments,
|
|
6828
|
+
...call.idSynthesized === true ? { idSynthesized: true } : {}
|
|
5231
6829
|
};
|
|
5232
6830
|
}
|
|
6831
|
+
var providerToolCallId = (tc) => tc.id && !tc.idSynthesized ? tc.id : void 0;
|
|
5233
6832
|
function normalizeToolSchema(tool, toolName) {
|
|
5234
6833
|
const schema = tool.schema;
|
|
5235
6834
|
if (!schema) return void 0;
|
|
@@ -5487,6 +7086,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
5487
7086
|
label: `Tool Denied - ${toolName}`,
|
|
5488
7087
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5489
7088
|
status: "skipped",
|
|
7089
|
+
skipReason: "denied",
|
|
7090
|
+
toolCallId: providerToolCallId(tc),
|
|
5490
7091
|
toolDetails,
|
|
5491
7092
|
toolExecutionId: toolCallId,
|
|
5492
7093
|
sections: buildToolTraceSections({
|
|
@@ -5558,6 +7159,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
5558
7159
|
label: `Tool Skipped - ${toolName}`,
|
|
5559
7160
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5560
7161
|
status: "skipped",
|
|
7162
|
+
skipReason: "skipped",
|
|
7163
|
+
toolCallId: providerToolCallId(tc),
|
|
5561
7164
|
toolDetails,
|
|
5562
7165
|
toolExecutionId: tc.id,
|
|
5563
7166
|
sections: buildToolTraceSections({
|
|
@@ -5694,10 +7297,13 @@ function createToolsNode(initialTools, opts) {
|
|
|
5694
7297
|
label: `Tool Error - ${toolName}`,
|
|
5695
7298
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5696
7299
|
status: "error",
|
|
7300
|
+
// The tool was not run: an open breaker refused the call.
|
|
7301
|
+
skipReason: "skipped",
|
|
7302
|
+
toolCallId: providerToolCallId(tc),
|
|
5697
7303
|
requestBytes: inputBytes,
|
|
5698
7304
|
toolDetails,
|
|
5699
7305
|
toolExecutionId: toolCallId,
|
|
5700
|
-
error: { message: breakerMsg },
|
|
7306
|
+
error: { message: breakerMsg, type: "circuit_breaker_open" },
|
|
5701
7307
|
sections: buildToolTraceSections({
|
|
5702
7308
|
args,
|
|
5703
7309
|
executionId: toolCallId,
|
|
@@ -5711,6 +7317,7 @@ function createToolsNode(initialTools, opts) {
|
|
|
5711
7317
|
toolCount += 1;
|
|
5712
7318
|
return { status: "error" };
|
|
5713
7319
|
}
|
|
7320
|
+
let traceSpanId;
|
|
5714
7321
|
try {
|
|
5715
7322
|
if (cachedHit !== void 0) {
|
|
5716
7323
|
const executionId2 = nanoid();
|
|
@@ -5756,6 +7363,9 @@ function createToolsNode(initialTools, opts) {
|
|
|
5756
7363
|
type: "tool_call",
|
|
5757
7364
|
label: shortCircuitSource === "plugin" ? `Tool Short-Circuited - ${toolName}` : `Tool Execution - ${toolName}`,
|
|
5758
7365
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
7366
|
+
// Answered from the cache or by a plugin: nothing executed.
|
|
7367
|
+
skipReason: "short_circuit",
|
|
7368
|
+
toolCallId: providerToolCallId(tc),
|
|
5759
7369
|
durationMs: 0,
|
|
5760
7370
|
requestBytes: inputBytes,
|
|
5761
7371
|
responseBytes: outputBytes2,
|
|
@@ -5790,7 +7400,16 @@ function createToolsNode(initialTools, opts) {
|
|
|
5790
7400
|
onEvent?.({ type: "tool_call", phase: "start", name: toolName, id: tc.id, args });
|
|
5791
7401
|
onProgress?.({ stage: "tools", message: `Running tool ${tc.name}` });
|
|
5792
7402
|
const anyTool = tool;
|
|
5793
|
-
|
|
7403
|
+
traceSpanId = traceSession ? generateSpanId() : void 0;
|
|
7404
|
+
const callOptions = {
|
|
7405
|
+
cancellationToken,
|
|
7406
|
+
signal: abortSignal,
|
|
7407
|
+
toolCallId,
|
|
7408
|
+
...traceSpanId ? { traceSpanId } : {},
|
|
7409
|
+
// So the tool can propagate the trace to what it calls (traceparentOf).
|
|
7410
|
+
...traceSpanId && traceSession?.traceId ? { traceId: traceSession.traceId } : {},
|
|
7411
|
+
...traceSpanId && traceSession?.parent ? { traceFlags: traceSession.parent.flags } : {}
|
|
7412
|
+
};
|
|
5794
7413
|
const invokeOnce = async () => {
|
|
5795
7414
|
if (typeof anyTool.func === "function") return anyTool.func(args, callOptions);
|
|
5796
7415
|
if (typeof anyTool.invoke === "function") return anyTool.invoke(args, callOptions);
|
|
@@ -5973,9 +7592,13 @@ function createToolsNode(initialTools, opts) {
|
|
|
5973
7592
|
const outputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedOutput) : void 0;
|
|
5974
7593
|
recordTraceEvent(traceSession, {
|
|
5975
7594
|
type: "tool_call",
|
|
7595
|
+
spanId: traceSpanId,
|
|
5976
7596
|
label: `Tool Execution - ${toolName}`,
|
|
5977
7597
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
5978
|
-
...reportedFailure ? { status: "error", error: { message: reportedFailure } } : {},
|
|
7598
|
+
...reportedFailure ? { status: "error", error: { message: reportedFailure, type: "tool_error" } } : {},
|
|
7599
|
+
toolCallId: providerToolCallId(tc),
|
|
7600
|
+
// `output` is already past postToolUse, so a redaction plugin has applied.
|
|
7601
|
+
capture: reportedFailure ? { toolArguments: args } : { toolArguments: args, toolResult: output, hasToolResult: true },
|
|
5979
7602
|
durationMs,
|
|
5980
7603
|
requestBytes: inputBytes,
|
|
5981
7604
|
responseBytes: outputBytes,
|
|
@@ -6035,15 +7658,18 @@ function createToolsNode(initialTools, opts) {
|
|
|
6035
7658
|
const errorOutput = { message, stack: host?.has("postToolUse") ? void 0 : error?.stack };
|
|
6036
7659
|
recordTraceEvent(traceSession, {
|
|
6037
7660
|
type: "tool_call",
|
|
7661
|
+
spanId: traceSpanId,
|
|
6038
7662
|
label: `Tool Error - ${toolName}`,
|
|
6039
7663
|
actor: { scope: "tool", name: toolName, role: "tool" },
|
|
6040
7664
|
status: "error",
|
|
7665
|
+
toolCallId: providerToolCallId(tc),
|
|
7666
|
+
capture: { toolArguments: args },
|
|
6041
7667
|
durationMs,
|
|
6042
7668
|
requestBytes: inputBytes,
|
|
6043
7669
|
responseBytes: traceSession?.resolvedConfig.logData ? estimatePayloadBytes(errorOutput) : void 0,
|
|
6044
7670
|
toolDetails,
|
|
6045
7671
|
toolExecutionId: executionId,
|
|
6046
|
-
error: { message, stack: host?.has("postToolUse") ? void 0 : error?.stack },
|
|
7672
|
+
error: { ...traceErrorOf(error), message, stack: host?.has("postToolUse") ? void 0 : error?.stack },
|
|
6047
7673
|
sections: buildToolTraceSections({
|
|
6048
7674
|
args: sanitizedArgs,
|
|
6049
7675
|
durationMs,
|
|
@@ -6158,6 +7784,8 @@ function createToolsNode(initialTools, opts) {
|
|
|
6158
7784
|
label: `Tool Skipped - ${tc.name}`,
|
|
6159
7785
|
actor: { scope: "tool", name: tc.name, role: "tool" },
|
|
6160
7786
|
status: "skipped",
|
|
7787
|
+
skipReason: "skipped",
|
|
7788
|
+
toolCallId: providerToolCallId(tc),
|
|
6161
7789
|
toolDetails,
|
|
6162
7790
|
toolExecutionId: tc.id,
|
|
6163
7791
|
sections: buildToolTraceSections({
|
|
@@ -6324,7 +7952,7 @@ function createReflectionNode(opts, resolved) {
|
|
|
6324
7952
|
label: "Reflection error",
|
|
6325
7953
|
actor: { scope: "agent", name: opts.name || "agent", role: "reflection" },
|
|
6326
7954
|
status: "error",
|
|
6327
|
-
error:
|
|
7955
|
+
error: traceErrorOf(err)
|
|
6328
7956
|
});
|
|
6329
7957
|
return {};
|
|
6330
7958
|
}
|
|
@@ -6995,7 +8623,7 @@ function createAskUserQuestionTool(stateRef, config) {
|
|
|
6995
8623
|
questions: entry.questions,
|
|
6996
8624
|
allowFreeText
|
|
6997
8625
|
});
|
|
6998
|
-
recordTraceEvent(ctx.__traceSession, {
|
|
8626
|
+
if (canPauseForHuman(ctx.__traceSession)) recordTraceEvent(ctx.__traceSession, {
|
|
6999
8627
|
type: "user_question",
|
|
7000
8628
|
label: "Question to user",
|
|
7001
8629
|
timestamp: entry.requestedAt,
|
|
@@ -7335,7 +8963,7 @@ function buildSubagentCatalogBlock(subagents, policy, toolNames, opts) {
|
|
|
7335
8963
|
// src/plugins/host.ts
|
|
7336
8964
|
init_content();
|
|
7337
8965
|
var DEFAULT_PRIORITY = 100;
|
|
7338
|
-
var
|
|
8966
|
+
var DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
7339
8967
|
var HOOK_SPECS = {
|
|
7340
8968
|
sessionStart: { kind: "gate", mutable: ["messages"], collect: ["systemPromptAppend"] },
|
|
7341
8969
|
userPromptSubmit: {
|
|
@@ -7440,7 +9068,7 @@ function collectRegistrations(plugin, registrations, into, orderRef) {
|
|
|
7440
9068
|
plugin: plugin.name,
|
|
7441
9069
|
priority: plugin.priority ?? DEFAULT_PRIORITY,
|
|
7442
9070
|
failureMode: plugin.failureMode ?? "open",
|
|
7443
|
-
timeoutMs: plugin.timeoutMs ??
|
|
9071
|
+
timeoutMs: plugin.timeoutMs ?? DEFAULT_TIMEOUT_MS2,
|
|
7444
9072
|
order: orderRef.value++,
|
|
7445
9073
|
handler
|
|
7446
9074
|
});
|
|
@@ -7495,6 +9123,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7495
9123
|
let contributions = {
|
|
7496
9124
|
tools: [],
|
|
7497
9125
|
toolDescriptions: {},
|
|
9126
|
+
traceExporters: [],
|
|
7498
9127
|
guardrails: [],
|
|
7499
9128
|
applySystemPrompt: (base) => base,
|
|
7500
9129
|
applyModelWrappers: (model) => model
|
|
@@ -7503,6 +9132,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7503
9132
|
async function runSetup(setupInput) {
|
|
7504
9133
|
const tools = [];
|
|
7505
9134
|
const toolDescriptions = {};
|
|
9135
|
+
const traceExporters = [];
|
|
7506
9136
|
const guardrails = [];
|
|
7507
9137
|
const promptSteps = [];
|
|
7508
9138
|
const modelWrappers = [];
|
|
@@ -7540,6 +9170,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7540
9170
|
);
|
|
7541
9171
|
}
|
|
7542
9172
|
if (plugin.toolDescriptions) Object.assign(toolDescriptions, plugin.toolDescriptions);
|
|
9173
|
+
if (plugin.traceExporters?.length) traceExporters.push(...plugin.traceExporters.filter(Boolean));
|
|
7543
9174
|
if (plugin.guardrails?.length) guardrails.push(...plugin.guardrails);
|
|
7544
9175
|
if (typeof plugin.wrapModel === "function") {
|
|
7545
9176
|
modelWrappers.push({ plugin: plugin.name, wrap: plugin.wrapModel });
|
|
@@ -7555,6 +9186,7 @@ function createPluginHost(plugins = [], options = {}) {
|
|
|
7555
9186
|
contributions = {
|
|
7556
9187
|
tools,
|
|
7557
9188
|
toolDescriptions,
|
|
9189
|
+
traceExporters,
|
|
7558
9190
|
guardrails,
|
|
7559
9191
|
applySystemPrompt: (base) => promptSteps.reduce((current, step) => {
|
|
7560
9192
|
try {
|
|
@@ -8278,19 +9910,22 @@ function createAgent(opts) {
|
|
|
8278
9910
|
detail: { reason: budget.reason, iteration: iterations }
|
|
8279
9911
|
});
|
|
8280
9912
|
}
|
|
9913
|
+
recordHumanDecisions(state.ctx?.__traceSession, state);
|
|
8281
9914
|
const ctx = { ...state.ctx || {}, __limitBreached: budget.reason };
|
|
8282
9915
|
state = { ...state, ctx };
|
|
8283
9916
|
break;
|
|
8284
9917
|
}
|
|
8285
9918
|
const traceSession = state.ctx?.__traceSession;
|
|
8286
9919
|
if (traceSession) {
|
|
8287
|
-
const
|
|
9920
|
+
const subagentScope = subagentTraceScopeOf(traceSession);
|
|
9921
|
+
const iterationNumber = subagentScope ? ++subagentScope.iterations : (traceSession.summary.eventCounts.agent_iteration ?? 0) - (traceSession.summary.subagentIterations ?? 0) + 1;
|
|
8288
9922
|
const iterEvent = recordTraceEvent(traceSession, {
|
|
8289
9923
|
type: "agent_iteration",
|
|
8290
9924
|
label: `Iteration ${iterationNumber}`,
|
|
8291
9925
|
actor: { scope: "agent", name: opts.name || "agent", role: "orchestrator" },
|
|
8292
9926
|
parentSpanId: traceSession.rootSpanId
|
|
8293
9927
|
});
|
|
9928
|
+
if (subagentScope) traceSession.summary.subagentIterations = (traceSession.summary.subagentIterations ?? 0) + 1;
|
|
8294
9929
|
if (iterEvent) {
|
|
8295
9930
|
traceSession.currentIterationSpanId = iterEvent.spanId;
|
|
8296
9931
|
}
|
|
@@ -8575,7 +10210,10 @@ function createAgent(opts) {
|
|
|
8575
10210
|
}
|
|
8576
10211
|
emit({ type: "progress", ...progress });
|
|
8577
10212
|
};
|
|
8578
|
-
const traceSession = createTraceSession(opts, readTraceContinuation(input.ctx?.__traceContinuation)
|
|
10213
|
+
const traceSession = createTraceSession(opts, readTraceContinuation(input.ctx?.__traceContinuation), {
|
|
10214
|
+
exporters: pluginHost.contributions.traceExporters,
|
|
10215
|
+
traceParent: config?.traceParent
|
|
10216
|
+
});
|
|
8579
10217
|
const ctx = {
|
|
8580
10218
|
...input.ctx || {},
|
|
8581
10219
|
__onEvent: onEvent,
|
|
@@ -8600,7 +10238,9 @@ function createAgent(opts) {
|
|
|
8600
10238
|
const inheritedSession = config?.__pluginSession;
|
|
8601
10239
|
ctx.__runId = inheritedSession?.runId ?? traceSession?.sessionId ?? `run_${nanoid(10)}`;
|
|
8602
10240
|
const stateHolder = inheritedSession?.stateHolder ?? { value: void 0 };
|
|
8603
|
-
const traceRecorder = createPluginTraceRecorder(
|
|
10241
|
+
const traceRecorder = createPluginTraceRecorder(
|
|
10242
|
+
() => traceSession ?? (subagentTraceScopeOf(ctx.__traceSession) ? ctx.__traceSession : void 0)
|
|
10243
|
+
);
|
|
8604
10244
|
const runHost = inheritedSession?.host ?? (pluginHost.hasAny() ? pluginHost.beginRun({
|
|
8605
10245
|
runId: ctx.__runId,
|
|
8606
10246
|
agentName: opts.name,
|
|
@@ -8725,7 +10365,7 @@ function createAgent(opts) {
|
|
|
8725
10365
|
await finalizeTraceSession(traceSession, {
|
|
8726
10366
|
agentRuntime: runtime,
|
|
8727
10367
|
status: "error",
|
|
8728
|
-
error: { message: err?.message, stack: err?.stack }
|
|
10368
|
+
error: { message: err?.message, stack: err?.stack, name: err?.name }
|
|
8729
10369
|
});
|
|
8730
10370
|
await endSession("error", { error: err instanceof Error ? err : new Error(String(err)), state: stateHolder.value });
|
|
8731
10371
|
if (userTokenCounter) {
|
|
@@ -8746,7 +10386,10 @@ function createAgent(opts) {
|
|
|
8746
10386
|
const midTurn = pausedForHuman || Boolean(res.ctx?.__needsSummarization);
|
|
8747
10387
|
await finalizeTraceSession(traceSession, {
|
|
8748
10388
|
agentRuntime: res.agent || runtime,
|
|
8749
|
-
status: pausedForHuman ? "paused" : midTurn ? "in_progress" : "success"
|
|
10389
|
+
status: pausedForHuman ? "paused" : midTurn ? "in_progress" : "success",
|
|
10390
|
+
// The file says `success` for a cancelled run (it did not fail); the
|
|
10391
|
+
// exported root says `partial`, the old plugin mapping.
|
|
10392
|
+
cancelled: statusFor(res) === "cancelled"
|
|
8750
10393
|
});
|
|
8751
10394
|
if (traceSession && midTurn) {
|
|
8752
10395
|
res.ctx = { ...res.ctx || {}, __traceContinuation: traceContinuationOf(traceSession) };
|
|
@@ -8843,7 +10486,7 @@ function createAgent(opts) {
|
|
|
8843
10486
|
name: toolName,
|
|
8844
10487
|
description: description || `Delegate task to agent ${opts.name || "Agent"}`,
|
|
8845
10488
|
schema,
|
|
8846
|
-
func: async ({ input }) => {
|
|
10489
|
+
func: async ({ input }, context) => {
|
|
8847
10490
|
const ref = delegatedTool._stateRef;
|
|
8848
10491
|
const parentCtx = ref.ctx || {};
|
|
8849
10492
|
const parentMessages = Array.isArray(ref.messages) ? ref.messages : [];
|
|
@@ -8876,6 +10519,33 @@ function createAgent(opts) {
|
|
|
8876
10519
|
input
|
|
8877
10520
|
);
|
|
8878
10521
|
const childCtx = { __delegationDepth: currentDepth + 1 };
|
|
10522
|
+
const parentSession = parentCtx.__traceSession;
|
|
10523
|
+
const traced = isTraceSessionOpen(parentSession);
|
|
10524
|
+
const agentSpanId = generateSpanId();
|
|
10525
|
+
const parentIterationSpanId = traced ? parentSession.currentIterationSpanId : void 0;
|
|
10526
|
+
if (traced && !withDefaults(opts.tracing).enabled) {
|
|
10527
|
+
childCtx.__traceSession = createSubagentTraceScope(parentSession, {
|
|
10528
|
+
agentSpanId,
|
|
10529
|
+
name: opts.name || "agent",
|
|
10530
|
+
mode: "asTool",
|
|
10531
|
+
hitl: false
|
|
10532
|
+
});
|
|
10533
|
+
}
|
|
10534
|
+
const startedAt = Date.now();
|
|
10535
|
+
const recordSpan = (status, extra) => {
|
|
10536
|
+
if (!traced || !isTraceSessionOpen(parentSession)) return;
|
|
10537
|
+
recordSubagentSpan(parentSession, {
|
|
10538
|
+
spanId: agentSpanId,
|
|
10539
|
+
parentSpanId: context?.traceSpanId ?? parentIterationSpanId,
|
|
10540
|
+
name: opts.name || "agent",
|
|
10541
|
+
status,
|
|
10542
|
+
durationMs: Date.now() - startedAt,
|
|
10543
|
+
error: extra.error,
|
|
10544
|
+
info: { name: opts.name || "agent", mode: "asTool", depth: currentDepth + 1, parentToolCallId: context?.toolCallId, status: status === "success" ? "ok" : "error" },
|
|
10545
|
+
task: input,
|
|
10546
|
+
result: extra.result
|
|
10547
|
+
});
|
|
10548
|
+
};
|
|
8879
10549
|
const childConfig = {
|
|
8880
10550
|
onEvent: parentCtx.__onEvent ? (e) => {
|
|
8881
10551
|
if (e?.type === "finalAnswer" || e?.type === "metadata") return;
|
|
@@ -8891,7 +10561,14 @@ function createAgent(opts) {
|
|
|
8891
10561
|
stream: Boolean(parentCtx.__streaming),
|
|
8892
10562
|
cancellationToken: parentCtx.__cancellationToken ?? parentCtx.__abortSignal
|
|
8893
10563
|
};
|
|
8894
|
-
|
|
10564
|
+
let res;
|
|
10565
|
+
try {
|
|
10566
|
+
res = await instance.invoke({ messages: childMessages, ctx: childCtx }, childConfig);
|
|
10567
|
+
} catch (err) {
|
|
10568
|
+
recordSpan("error", { error: err?.message || String(err) });
|
|
10569
|
+
throw err;
|
|
10570
|
+
}
|
|
10571
|
+
recordSpan("success", { result: res.content });
|
|
8895
10572
|
return {
|
|
8896
10573
|
content: res.content,
|
|
8897
10574
|
output: res.output,
|
|
@@ -8968,9 +10645,10 @@ function createAgentNode(opts) {
|
|
|
8968
10645
|
durationMs: durationMs2,
|
|
8969
10646
|
requestBytes: promptBytes,
|
|
8970
10647
|
model: getModelName(runtime.model || opts.model),
|
|
8971
|
-
provider:
|
|
8972
|
-
error:
|
|
8973
|
-
messageList: promptMessages
|
|
10648
|
+
provider: providerHintOf(runtime.model || opts.model),
|
|
10649
|
+
error: traceErrorOf(err),
|
|
10650
|
+
messageList: promptMessages,
|
|
10651
|
+
capture: { input: promptMessages }
|
|
8974
10652
|
});
|
|
8975
10653
|
throw err;
|
|
8976
10654
|
}
|
|
@@ -8981,7 +10659,7 @@ function createAgentNode(opts) {
|
|
|
8981
10659
|
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;
|
|
8982
10660
|
const normalized = normalizeUsage(rawUsage);
|
|
8983
10661
|
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
8984
|
-
const
|
|
10662
|
+
const facts = traceResponseFacts(runtime.model || opts.model, response, rawUsage);
|
|
8985
10663
|
const durationMs = Date.now() - start;
|
|
8986
10664
|
const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
|
|
8987
10665
|
const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
|
|
@@ -8998,8 +10676,9 @@ function createAgentNode(opts) {
|
|
|
8998
10676
|
requestBytes: promptBytes,
|
|
8999
10677
|
responseBytes,
|
|
9000
10678
|
model: modelName,
|
|
9001
|
-
|
|
9002
|
-
messageList: messagesWithResponse
|
|
10679
|
+
...facts,
|
|
10680
|
+
messageList: messagesWithResponse,
|
|
10681
|
+
capture: { input: promptMessages, output: response }
|
|
9003
10682
|
});
|
|
9004
10683
|
if (normalized) {
|
|
9005
10684
|
recordUsage(state, modelName, normalized);
|
|
@@ -9650,7 +11329,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9650
11329
|
];
|
|
9651
11330
|
const inputTokensEstimate = countApproxTokens(summaryPrompt.map((m) => m.content).join("\n"));
|
|
9652
11331
|
const modelName = getModelName(model);
|
|
9653
|
-
const providerName =
|
|
11332
|
+
const providerName = providerHintOf(model);
|
|
9654
11333
|
const tracingEnabled = Boolean(opts.tracing?.enabled);
|
|
9655
11334
|
let ctxWithDeferredTrace;
|
|
9656
11335
|
const traceSummarization = (event) => {
|
|
@@ -9681,6 +11360,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9681
11360
|
let reasoningTokensActual;
|
|
9682
11361
|
let fallback = false;
|
|
9683
11362
|
let summarizerError;
|
|
11363
|
+
let responseFacts;
|
|
9684
11364
|
const directivesSection = () => ({
|
|
9685
11365
|
kind: "metadata",
|
|
9686
11366
|
label: "User directives",
|
|
@@ -9722,6 +11402,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9722
11402
|
summaryText = renderStructuredSummary(structuredSummary);
|
|
9723
11403
|
const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
9724
11404
|
const normalized = normalizeUsage(rawUsage);
|
|
11405
|
+
responseFacts = traceResponseFacts(model, response, rawUsage);
|
|
9725
11406
|
if (normalized) {
|
|
9726
11407
|
inputTokensActual = normalized.prompt_tokens;
|
|
9727
11408
|
outputTokensActual = normalized.completion_tokens;
|
|
@@ -9758,7 +11439,7 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9758
11439
|
...droppedDirectives.length > 0 ? { droppedDirectives } : {}
|
|
9759
11440
|
};
|
|
9760
11441
|
onEvent?.(errorEvent);
|
|
9761
|
-
summarizerError =
|
|
11442
|
+
summarizerError = traceErrorOf(err);
|
|
9762
11443
|
}
|
|
9763
11444
|
const toolCallIdToAssistantIdx = /* @__PURE__ */ new Map();
|
|
9764
11445
|
messages.forEach((m, idx) => {
|
|
@@ -9914,10 +11595,16 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
9914
11595
|
outputTokens: outputTokensActual ?? outputTokensEstimate,
|
|
9915
11596
|
cachedInputTokens,
|
|
9916
11597
|
totalTokens: totalTokensActual,
|
|
9917
|
-
...reasoningTokensActual !== void 0 ? { reasoningTokens: reasoningTokensActual } : {}
|
|
11598
|
+
...reasoningTokensActual !== void 0 ? { reasoningTokens: reasoningTokensActual } : {},
|
|
11599
|
+
// Which counting rules the usage above follows (only when the provider reported it).
|
|
11600
|
+
...inputTokensActual !== void 0 && responseFacts?.usageBasis ? { usageBasis: responseFacts.usageBasis } : {},
|
|
11601
|
+
...inputTokensActual !== void 0 && responseFacts?.cacheWriteTokens ? { cacheWriteTokens: responseFacts.cacheWriteTokens } : {}
|
|
9918
11602
|
},
|
|
11603
|
+
...responseFacts?.responseId ? { responseId: responseFacts.responseId } : {},
|
|
11604
|
+
...responseFacts?.responseModel ? { responseModel: responseFacts.responseModel } : {},
|
|
11605
|
+
...responseFacts?.rawFinishReason ? { rawFinishReason: responseFacts.rawFinishReason } : {},
|
|
9919
11606
|
...modelName ? { model: modelName } : {},
|
|
9920
|
-
...providerName ? { provider: providerName } : {},
|
|
11607
|
+
...responseFacts?.provider ?? providerName ? { provider: responseFacts?.provider ?? providerName } : {},
|
|
9921
11608
|
...summarizerError ? { error: summarizerError } : {},
|
|
9922
11609
|
sections: [
|
|
9923
11610
|
...promptAndOutputSections(),
|
|
@@ -11054,11 +12741,52 @@ function mergeChildUsage(ref, childState, baseline, tag) {
|
|
|
11054
12741
|
async function runChild(spec, input, deps, ref, opts) {
|
|
11055
12742
|
const parentCtx = ref.ctx || {};
|
|
11056
12743
|
const parentOnEvent = parentCtx.__onEvent;
|
|
11057
|
-
const spawnId = `sa_${nanoid(6)}`;
|
|
12744
|
+
const spawnId = opts.record?.spawnId ?? `sa_${nanoid(6)}`;
|
|
11058
12745
|
const start = Date.now();
|
|
11059
12746
|
const usageTag = { name: spec.name, id: spawnId, mode: spec.mode };
|
|
11060
12747
|
const parentHost = parentCtx.__plugins;
|
|
11061
12748
|
const childDepth = (Number(parentCtx.__delegationDepth) || 0) + 1;
|
|
12749
|
+
const parentSession = parentCtx.__traceSession;
|
|
12750
|
+
const traced = isTraceSessionOpen(parentSession);
|
|
12751
|
+
const sessionStart = traced ? parentSession.startedAt : void 0;
|
|
12752
|
+
const persistedId = opts.record?.agentSpanId;
|
|
12753
|
+
const agentSpanId = typeof persistedId === "string" && /^[0-9a-f]{16}$/.test(persistedId) ? persistedId : generateSpanId();
|
|
12754
|
+
const persistedStart = opts.record?.startedAt;
|
|
12755
|
+
const startValid = typeof persistedStart === "number" && Number.isFinite(persistedStart) && persistedStart > 0 && persistedStart <= start;
|
|
12756
|
+
const runStartedAt = startValid ? Math.min(start, Math.max(persistedStart, sessionStart ?? persistedStart)) : start;
|
|
12757
|
+
const persistedSegments = opts.record?.segments;
|
|
12758
|
+
const segment = (typeof persistedSegments === "number" && Number.isInteger(persistedSegments) && persistedSegments >= 1 && persistedSegments <= 1e3 ? persistedSegments : 0) + 1;
|
|
12759
|
+
const elapsedMs = () => Math.max(0, Date.now() - runStartedAt);
|
|
12760
|
+
const parentIterationSpanId = traced ? parentSession.currentIterationSpanId : void 0;
|
|
12761
|
+
const traceScope = traced ? createSubagentTraceScope(parentSession, { agentSpanId, name: spec.name, spawnId, mode: spec.mode, hitl: opts.allowHITL, iterations: opts.record?.iterations }) : void 0;
|
|
12762
|
+
const recordSegment = (status, info) => {
|
|
12763
|
+
if (!traced || !isTraceSessionOpen(parentSession)) return;
|
|
12764
|
+
recordSubagentSpan(parentSession, {
|
|
12765
|
+
spanId: agentSpanId,
|
|
12766
|
+
// The tool_call span only exists once the tool returns; a paused child
|
|
12767
|
+
// has not returned, so its span hangs off the iteration.
|
|
12768
|
+
parentSpanId: status === "pending" ? parentIterationSpanId : opts.parentSpanId ?? parentIterationSpanId,
|
|
12769
|
+
name: spec.name,
|
|
12770
|
+
status,
|
|
12771
|
+
durationMs: elapsedMs(),
|
|
12772
|
+
error: info.error,
|
|
12773
|
+
info: {
|
|
12774
|
+
id: spawnId,
|
|
12775
|
+
name: spec.name,
|
|
12776
|
+
mode: spec.mode,
|
|
12777
|
+
parallel: opts.parallel,
|
|
12778
|
+
depth: childDepth,
|
|
12779
|
+
parentToolCallId: opts.parentToolCallId,
|
|
12780
|
+
status: info.subagentStatus,
|
|
12781
|
+
// Only a run that paused has more than one segment to tell about.
|
|
12782
|
+
...segment > 1 || status === "pending" ? { segments: segment } : {},
|
|
12783
|
+
...info.note ? { note: info.note } : {},
|
|
12784
|
+
...spec.metadata ? { metadata: spec.metadata } : {}
|
|
12785
|
+
},
|
|
12786
|
+
task: info.input,
|
|
12787
|
+
result: info.content
|
|
12788
|
+
});
|
|
12789
|
+
};
|
|
11062
12790
|
const emitStart = (task) => {
|
|
11063
12791
|
parentOnEvent?.({ type: "subagent", phase: "start", name: spec.name, id: spawnId, mode: spec.mode, parallel: opts.parallel, parentToolCallId: opts.parentToolCallId, input: task });
|
|
11064
12792
|
};
|
|
@@ -11066,6 +12794,15 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11066
12794
|
result2.durationMs ?? (result2.durationMs = Date.now() - start);
|
|
11067
12795
|
deps.registryRef.results.push(result2);
|
|
11068
12796
|
const message = result2.error || result2.note || result2.status;
|
|
12797
|
+
const traceStatus = result2.status === "ok" || result2.status === "incomplete" ? "success" : result2.status === "blocked" ? "skipped" : "error";
|
|
12798
|
+
recordSegment(traceStatus, {
|
|
12799
|
+
subagentStatus: result2.status,
|
|
12800
|
+
input,
|
|
12801
|
+
// `message` falls back to the status itself ("ok"): only a failed or refused run has an error to show.
|
|
12802
|
+
error: traceStatus === "success" ? void 0 : message,
|
|
12803
|
+
note: result2.note,
|
|
12804
|
+
content: result2.content
|
|
12805
|
+
});
|
|
11069
12806
|
parentOnEvent?.({
|
|
11070
12807
|
type: "subagent",
|
|
11071
12808
|
phase: FAILED_STATUSES.has(result2.status) ? "error" : "result",
|
|
@@ -11164,6 +12901,7 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11164
12901
|
ctx: { __delegationDepth: currentDepth + 1 }
|
|
11165
12902
|
};
|
|
11166
12903
|
}
|
|
12904
|
+
if (traceScope) childInput = { ...childInput, ctx: { ...childInput.ctx || {}, __traceSession: traceScope } };
|
|
11167
12905
|
const usageBaseline = childInput.usage?.perRequest?.length ?? 0;
|
|
11168
12906
|
let res;
|
|
11169
12907
|
try {
|
|
@@ -11204,8 +12942,14 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11204
12942
|
input,
|
|
11205
12943
|
childState: cleanChildState(childState),
|
|
11206
12944
|
pendingKind: "approval",
|
|
11207
|
-
pendingId: childEntry.id
|
|
12945
|
+
pendingId: childEntry.id,
|
|
12946
|
+
spawnId,
|
|
12947
|
+
iterations: traceScope ? subagentTraceScopeOf(traceScope)?.iterations : void 0,
|
|
12948
|
+
agentSpanId,
|
|
12949
|
+
startedAt: runStartedAt,
|
|
12950
|
+
segments: segment
|
|
11208
12951
|
};
|
|
12952
|
+
recordSegment("pending", { subagentStatus: "paused", input });
|
|
11209
12953
|
parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
|
|
11210
12954
|
return { kind: "approval", toolCallId: surfaced.toolCallId, approvalId: surfaced.id };
|
|
11211
12955
|
}
|
|
@@ -11227,8 +12971,14 @@ async function runChild(spec, input, deps, ref, opts) {
|
|
|
11227
12971
|
input,
|
|
11228
12972
|
childState: cleanChildState(childState),
|
|
11229
12973
|
pendingKind: "user_question",
|
|
11230
|
-
pendingId: childEntry.id
|
|
12974
|
+
pendingId: childEntry.id,
|
|
12975
|
+
spawnId,
|
|
12976
|
+
iterations: traceScope ? subagentTraceScopeOf(traceScope)?.iterations : void 0,
|
|
12977
|
+
agentSpanId,
|
|
12978
|
+
startedAt: runStartedAt,
|
|
12979
|
+
segments: segment
|
|
11231
12980
|
};
|
|
12981
|
+
recordSegment("pending", { subagentStatus: "paused", input });
|
|
11232
12982
|
parentOnEvent?.({ type: "subagent", phase: "paused", name: spec.name, id: spawnId, mode: spec.mode, parentToolCallId: opts.parentToolCallId });
|
|
11233
12983
|
return { kind: "user_question", toolCallId: surfaced.toolCallId, id: surfaced.id };
|
|
11234
12984
|
}
|
|
@@ -11332,7 +13082,7 @@ function createDelegateTool(deps) {
|
|
|
11332
13082
|
if (!budget.ok) return refusal(budget.reason);
|
|
11333
13083
|
d.registryRef.spawnedCount += 1;
|
|
11334
13084
|
}
|
|
11335
|
-
return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record }));
|
|
13085
|
+
return toToolReturn(await runChild(spec, record?.input ?? input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record, parentSpanId: context?.traceSpanId }));
|
|
11336
13086
|
}
|
|
11337
13087
|
});
|
|
11338
13088
|
tool._deps = deps;
|
|
@@ -11377,7 +13127,7 @@ function createSpawnTool(deps) {
|
|
|
11377
13127
|
if (!budget.ok) return refusal(budget.reason);
|
|
11378
13128
|
d.registryRef.spawnedCount += 1;
|
|
11379
13129
|
}
|
|
11380
|
-
return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record }));
|
|
13130
|
+
return toToolReturn(await runChild(spec, record?.input ?? args.input, d, ref, { allowHITL: true, parentToolCallId, isResume: !!record, record, reserved: !record, parentSpanId: context?.traceSpanId }));
|
|
11381
13131
|
}
|
|
11382
13132
|
});
|
|
11383
13133
|
tool._deps = deps;
|
|
@@ -11460,7 +13210,8 @@ function createParallelTool(deps) {
|
|
|
11460
13210
|
allowHITL: false,
|
|
11461
13211
|
parentToolCallId: `${parentToolCallId}#${i}`,
|
|
11462
13212
|
parallel: true,
|
|
11463
|
-
reserved: true
|
|
13213
|
+
reserved: true,
|
|
13214
|
+
parentSpanId: context?.traceSpanId
|
|
11464
13215
|
});
|
|
11465
13216
|
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." };
|
|
11466
13217
|
}
|
|
@@ -11912,6 +13663,30 @@ ${pluginAppend}`;
|
|
|
11912
13663
|
};
|
|
11913
13664
|
}
|
|
11914
13665
|
}
|
|
13666
|
+
const traceHandoff = {};
|
|
13667
|
+
const noteTraceHandoff = (current) => {
|
|
13668
|
+
traceHandoff.continuation = current.ctx?.__traceContinuation;
|
|
13669
|
+
traceHandoff.events = current.ctx?.[DEFERRED_TRACE_EVENTS_KEY];
|
|
13670
|
+
};
|
|
13671
|
+
const closeDanglingTrace = async (status, error) => {
|
|
13672
|
+
const continuation = traceHandoff.continuation;
|
|
13673
|
+
const events = traceHandoff.events;
|
|
13674
|
+
traceHandoff.continuation = void 0;
|
|
13675
|
+
traceHandoff.events = void 0;
|
|
13676
|
+
if (!continuation) return;
|
|
13677
|
+
try {
|
|
13678
|
+
await closeTraceContinuation(continuation, {
|
|
13679
|
+
tracing: opts.tracing,
|
|
13680
|
+
exporters: pluginHost?.contributions.traceExporters,
|
|
13681
|
+
status,
|
|
13682
|
+
error,
|
|
13683
|
+
agentRuntime: base.__runtime,
|
|
13684
|
+
events
|
|
13685
|
+
});
|
|
13686
|
+
} catch (closeError) {
|
|
13687
|
+
console.warn("[agent-sdk] closing the trace failed:", closeError);
|
|
13688
|
+
}
|
|
13689
|
+
};
|
|
11915
13690
|
try {
|
|
11916
13691
|
const toolSet = buildInvokeToolSet();
|
|
11917
13692
|
const stateRef = toolSet.stateRef;
|
|
@@ -11990,11 +13765,15 @@ ${pluginAppend}`;
|
|
|
11990
13765
|
const result = await trySummarize(state, rawMessages, stateRef);
|
|
11991
13766
|
state = result.state;
|
|
11992
13767
|
rawMessages = result.rawMessages;
|
|
13768
|
+
noteTraceHandoff(state);
|
|
11993
13769
|
if (result.compressed) continue;
|
|
11994
13770
|
}
|
|
11995
13771
|
const modelMessages = buildModelMessages(state, resolved);
|
|
13772
|
+
traceHandoff.continuation = void 0;
|
|
13773
|
+
traceHandoff.events = void 0;
|
|
11996
13774
|
const res = await base.invoke({ ...state, messages: modelMessages }, turnConfig);
|
|
11997
13775
|
lastResult = res;
|
|
13776
|
+
noteTraceHandoff(res.state ?? state);
|
|
11998
13777
|
const currentSummaries = state.summaries;
|
|
11999
13778
|
const currentSummaryRecords = state.summaryRecords;
|
|
12000
13779
|
const currentPlan = state.plan;
|
|
@@ -12021,6 +13800,7 @@ ${pluginAppend}`;
|
|
|
12021
13800
|
const result = await trySummarize(state, rawMessages, stateRef);
|
|
12022
13801
|
state = result.state;
|
|
12023
13802
|
rawMessages = result.rawMessages;
|
|
13803
|
+
noteTraceHandoff(state);
|
|
12024
13804
|
continue;
|
|
12025
13805
|
}
|
|
12026
13806
|
if (state.ctx?.__finalizedDueToStructuredOutput) break;
|
|
@@ -12032,6 +13812,7 @@ ${pluginAppend}`;
|
|
|
12032
13812
|
const result = await trySummarize(state, rawMessages, stateRef);
|
|
12033
13813
|
state = result.state;
|
|
12034
13814
|
rawMessages = result.rawMessages;
|
|
13815
|
+
noteTraceHandoff(state);
|
|
12035
13816
|
if (result.compressed) continue;
|
|
12036
13817
|
}
|
|
12037
13818
|
}
|
|
@@ -12042,6 +13823,7 @@ ${pluginAppend}`;
|
|
|
12042
13823
|
lastResult = res;
|
|
12043
13824
|
}
|
|
12044
13825
|
if (state.ctx?.[DEFERRED_TRACE_EVENTS_KEY]) {
|
|
13826
|
+
traceHandoff.events = state.ctx[DEFERRED_TRACE_EVENTS_KEY];
|
|
12045
13827
|
const ctx = { ...state.ctx || {} };
|
|
12046
13828
|
delete ctx[DEFERRED_TRACE_EVENTS_KEY];
|
|
12047
13829
|
state = { ...state, ctx };
|
|
@@ -12061,8 +13843,12 @@ ${pluginAppend}`;
|
|
|
12061
13843
|
const strippedCtx = { ...endCtx };
|
|
12062
13844
|
delete strippedCtx.__traceContinuation;
|
|
12063
13845
|
lastResult = { ...lastResult, state: { ...lastResult.state, ctx: strippedCtx } };
|
|
13846
|
+
traceHandoff.continuation = endCtx.__traceContinuation;
|
|
13847
|
+
await closeDanglingTrace("success");
|
|
12064
13848
|
}
|
|
12065
13849
|
}
|
|
13850
|
+
traceHandoff.continuation = void 0;
|
|
13851
|
+
traceHandoff.events = void 0;
|
|
12066
13852
|
if (skillsEnabled && lastResult.state) {
|
|
12067
13853
|
const persisted = skillStateFromRegistry(toolSet.skillRegistryRef);
|
|
12068
13854
|
if (persisted) {
|
|
@@ -12108,6 +13894,11 @@ ${pluginAppend}`;
|
|
|
12108
13894
|
await endSession(endStatus, { result: lastResult });
|
|
12109
13895
|
return lastResult;
|
|
12110
13896
|
} catch (err) {
|
|
13897
|
+
await closeDanglingTrace("error", {
|
|
13898
|
+
message: err instanceof Error ? err.message : String(err),
|
|
13899
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
13900
|
+
name: err instanceof Error ? err.name : void 0
|
|
13901
|
+
});
|
|
12111
13902
|
await endSession("error", { error: err instanceof Error ? err : new Error(String(err)) });
|
|
12112
13903
|
throw err;
|
|
12113
13904
|
}
|
|
@@ -13024,7 +14815,7 @@ function isHookImplemented(hook) {
|
|
|
13024
14815
|
// src/plugins/builtin/guardrail.ts
|
|
13025
14816
|
init_content();
|
|
13026
14817
|
var ALLOW = { action: "allow" };
|
|
13027
|
-
var
|
|
14818
|
+
var RETRYABLE_STATUS2 = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
13028
14819
|
var RetryableGuardrailError = class extends Error {
|
|
13029
14820
|
constructor(message) {
|
|
13030
14821
|
super(message);
|
|
@@ -13122,7 +14913,7 @@ function httpGuardrail(options) {
|
|
|
13122
14913
|
} catch {
|
|
13123
14914
|
}
|
|
13124
14915
|
const message = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}${text ? ` - ${text.slice(0, 200)}` : ""}`;
|
|
13125
|
-
if (
|
|
14916
|
+
if (RETRYABLE_STATUS2.has(response.status)) throw new RetryableGuardrailError(message);
|
|
13126
14917
|
throw new Error(message);
|
|
13127
14918
|
}
|
|
13128
14919
|
return response.json();
|
|
@@ -13229,9 +15020,9 @@ function createGuardrailPlugin(options) {
|
|
|
13229
15020
|
});
|
|
13230
15021
|
const resolved = verdict ?? ALLOW;
|
|
13231
15022
|
if (resolved.raw?.disabled === true) {
|
|
13232
|
-
const
|
|
13233
|
-
if (!
|
|
13234
|
-
|
|
15023
|
+
const warned2 = (_b = ctx.store).__disabledWarned ?? (_b.__disabledWarned = /* @__PURE__ */ new Set());
|
|
15024
|
+
if (!warned2.has(request.phase)) {
|
|
15025
|
+
warned2.add(request.phase);
|
|
13235
15026
|
ctx.logger.warn(
|
|
13236
15027
|
`guardrail reports it is not active for the "${request.phase}" surface; nothing is being enforced there`
|
|
13237
15028
|
);
|
|
@@ -13728,7 +15519,7 @@ function safeJson(value) {
|
|
|
13728
15519
|
function matches(pattern, toolName) {
|
|
13729
15520
|
return typeof pattern === "string" ? pattern === toolName : pattern.test(toolName);
|
|
13730
15521
|
}
|
|
13731
|
-
function
|
|
15522
|
+
function asObject2(args) {
|
|
13732
15523
|
return args && typeof args === "object" ? args : {};
|
|
13733
15524
|
}
|
|
13734
15525
|
function toolPolicy(config = {}) {
|
|
@@ -13749,7 +15540,7 @@ function toolPolicy(config = {}) {
|
|
|
13749
15540
|
hooks: {
|
|
13750
15541
|
preToolUse: ({ toolName, args }, ctx) => {
|
|
13751
15542
|
var _a;
|
|
13752
|
-
const argObject =
|
|
15543
|
+
const argObject = asObject2(args);
|
|
13753
15544
|
const isControlPlane = CONTROL_PLANE_TOOL_NAMES.includes(toolName);
|
|
13754
15545
|
const allowListApplies = !isControlPlane || config.governControlPlaneTools === true;
|
|
13755
15546
|
if (config.allowOnly && allowListApplies && !config.allowOnly.some((pattern) => matches(pattern, toolName))) {
|
|
@@ -13811,7 +15602,7 @@ function pathSandbox(config) {
|
|
|
13811
15602
|
hooks: {
|
|
13812
15603
|
preToolUse: ({ toolName, args }) => {
|
|
13813
15604
|
if (config.tools && !config.tools.some((pattern) => matches(pattern, toolName))) return void 0;
|
|
13814
|
-
const argObject =
|
|
15605
|
+
const argObject = asObject2(args);
|
|
13815
15606
|
for (const key of argNames) {
|
|
13816
15607
|
const value = argObject[key];
|
|
13817
15608
|
if (typeof value !== "string" || value.length === 0) continue;
|
|
@@ -14579,7 +16370,7 @@ function mcp(config) {
|
|
|
14579
16370
|
}
|
|
14580
16371
|
|
|
14581
16372
|
// src/plugins/builtin/rateLimit.ts
|
|
14582
|
-
function
|
|
16373
|
+
function sleep2(ms, signal) {
|
|
14583
16374
|
return new Promise((resolve) => {
|
|
14584
16375
|
let timer;
|
|
14585
16376
|
const done = () => {
|
|
@@ -14636,7 +16427,7 @@ function rateLimit(config = {}) {
|
|
|
14636
16427
|
while (!attempt.ok) {
|
|
14637
16428
|
const remaining = deadline - Date.now();
|
|
14638
16429
|
if (!Number.isFinite(attempt.waitMs) || attempt.waitMs > remaining) break;
|
|
14639
|
-
await
|
|
16430
|
+
await sleep2(Math.max(1, attempt.waitMs), ctx.signal);
|
|
14640
16431
|
if (ctx.signal?.aborted) break;
|
|
14641
16432
|
attempt = consume(applicable);
|
|
14642
16433
|
}
|
|
@@ -15732,18 +17523,21 @@ function langfuseTracing(config = {}) {
|
|
|
15732
17523
|
}
|
|
15733
17524
|
|
|
15734
17525
|
// src/plugins/builtin/otel.ts
|
|
15735
|
-
function
|
|
15736
|
-
if (
|
|
15737
|
-
if (status === "error") return "error";
|
|
15738
|
-
return status === "paused" ? "in_progress" : "partial";
|
|
15739
|
-
}
|
|
15740
|
-
function otelTracing(config) {
|
|
15741
|
-
const endpoint = config.endpoint?.trim();
|
|
15742
|
-
if (!endpoint) {
|
|
17526
|
+
function otelTracing(config = {}) {
|
|
17527
|
+
if (config.endpoint !== void 0 && !config.endpoint.trim()) {
|
|
15743
17528
|
throw new Error("[agent-sdk] otelTracing requires a non-empty `endpoint`.");
|
|
15744
17529
|
}
|
|
17530
|
+
const name = config.name ?? "otel-tracing";
|
|
17531
|
+
let exporter;
|
|
17532
|
+
try {
|
|
17533
|
+
exporter = createOtlpExporter({ ...config, endpoint: config.endpoint?.trim(), name });
|
|
17534
|
+
} catch {
|
|
17535
|
+
throw new Error(
|
|
17536
|
+
"[agent-sdk] otelTracing requires a non-empty `endpoint` (or OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT in the environment)."
|
|
17537
|
+
);
|
|
17538
|
+
}
|
|
15745
17539
|
return {
|
|
15746
|
-
name
|
|
17540
|
+
name,
|
|
15747
17541
|
// Registers only the `sessionEnd` observer, and observers run concurrently,
|
|
15748
17542
|
// so this number orders nothing at runtime. It is set above checkpointing
|
|
15749
17543
|
// (900) to record intent: this plugin is the last thing interested in the
|
|
@@ -15751,67 +17545,41 @@ function otelTracing(config) {
|
|
|
15751
17545
|
priority: 950,
|
|
15752
17546
|
// Observability. A dropped export is a reporting gap, never a safety hole.
|
|
15753
17547
|
failureMode: "open",
|
|
17548
|
+
traceExporters: [exporter],
|
|
15754
17549
|
hooks: {
|
|
15755
|
-
sessionEnd: async (
|
|
17550
|
+
sessionEnd: async (_event, ctx) => {
|
|
15756
17551
|
const state = ctx.state;
|
|
15757
17552
|
const session = state.ctx?.__traceSession;
|
|
17553
|
+
if (isSubagentTraceScope(session)) return;
|
|
15758
17554
|
if (!session) {
|
|
15759
17555
|
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.";
|
|
15760
17556
|
ctx.logger.warn(message);
|
|
15761
17557
|
ctx.emit({ type: "metadata", otelTracing: { exported: false, reason: message } });
|
|
15762
17558
|
return;
|
|
15763
17559
|
}
|
|
15764
|
-
const
|
|
15765
|
-
const
|
|
15766
|
-
|
|
15767
|
-
const
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15775
|
-
// `service.name` is read off `agent.name` inside the conversion, so
|
|
15776
|
-
// the override is applied here rather than by editing spans after.
|
|
15777
|
-
agent: {
|
|
15778
|
-
...session.agentInfo ?? {},
|
|
15779
|
-
name: config.serviceName ?? session.agentInfo?.name ?? session.configAgentName ?? ctx.agentName
|
|
15780
|
-
},
|
|
15781
|
-
metadata: session.configMetadata,
|
|
15782
|
-
// Carried only to satisfy the type: `traceSessionToOtlp` reads the
|
|
15783
|
-
// events, summary and identifiers, never the sink snapshot.
|
|
15784
|
-
config: { enabled: true, logData: session.resolvedConfig.logData, sink: { type: "otlp", endpoint } },
|
|
15785
|
-
summary: session.summary,
|
|
15786
|
-
events: session.events,
|
|
15787
|
-
status: toSessionStatus(status),
|
|
15788
|
-
errors
|
|
15789
|
-
};
|
|
15790
|
-
try {
|
|
15791
|
-
const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
|
|
15792
|
-
if (!fetchFn) {
|
|
15793
|
-
ctx.logger.warn("otelTracing needs fetch to be available in this runtime; export skipped.");
|
|
15794
|
-
return;
|
|
15795
|
-
}
|
|
15796
|
-
const response = await fetchFn(endpoint, {
|
|
15797
|
-
method: "POST",
|
|
15798
|
-
headers: { "content-type": "application/json", ...config.headers ?? {} },
|
|
15799
|
-
body: JSON.stringify(traceSessionToOtlp(payload)),
|
|
15800
|
-
// The run is over, but a host that cancelled it should not be made
|
|
15801
|
-
// to wait on a collector that is refusing to answer.
|
|
15802
|
-
signal: ctx.signal
|
|
15803
|
-
});
|
|
15804
|
-
if (!response.ok) {
|
|
15805
|
-
ctx.logger.warn(`otelTracing export returned HTTP ${response.status}.`);
|
|
15806
|
-
return;
|
|
15807
|
-
}
|
|
15808
|
-
ctx.emit({
|
|
15809
|
-
type: "metadata",
|
|
15810
|
-
otelTracing: { exported: true, endpoint, spans: session.events.length + 1 }
|
|
15811
|
-
});
|
|
15812
|
-
} catch (err) {
|
|
15813
|
-
ctx.logger.warn("otelTracing export failed:", err instanceof Error ? err.message : err);
|
|
17560
|
+
const reports = (session.exportReports ?? []).filter((report2) => !report2.sink && report2.exporter === name);
|
|
17561
|
+
const report = reports[reports.length - 1];
|
|
17562
|
+
if (!report) return;
|
|
17563
|
+
const { result } = report;
|
|
17564
|
+
if (!result.ok) {
|
|
17565
|
+
ctx.logger.warn(`otelTracing export failed: ${result.error ?? "unknown error"}`);
|
|
17566
|
+
return;
|
|
17567
|
+
}
|
|
17568
|
+
if (result.skipped) {
|
|
17569
|
+
ctx.emit({ type: "metadata", otelTracing: { exported: false, reason: result.reason ?? "nothing to export" } });
|
|
17570
|
+
return;
|
|
15814
17571
|
}
|
|
17572
|
+
ctx.emit({
|
|
17573
|
+
type: "metadata",
|
|
17574
|
+
otelTracing: {
|
|
17575
|
+
exported: true,
|
|
17576
|
+
endpoint: report.endpoint,
|
|
17577
|
+
spans: result.spans,
|
|
17578
|
+
terminal: report.terminal,
|
|
17579
|
+
// A 200 that refused some spans: the collector's count and message.
|
|
17580
|
+
...result.partialSuccess ? { rejectedSpans: result.partialSuccess.rejectedSpans, ...result.partialSuccess.message ? { rejectionMessage: result.partialSuccess.message } : {} } : {}
|
|
17581
|
+
}
|
|
17582
|
+
});
|
|
15815
17583
|
}
|
|
15816
17584
|
}
|
|
15817
17585
|
};
|
|
@@ -18847,9 +20615,9 @@ function mapAnthropicStopReason(reason) {
|
|
|
18847
20615
|
return "stop";
|
|
18848
20616
|
}
|
|
18849
20617
|
}
|
|
18850
|
-
function safeJsonParse(
|
|
20618
|
+
function safeJsonParse(str2) {
|
|
18851
20619
|
try {
|
|
18852
|
-
return JSON.parse(
|
|
20620
|
+
return JSON.parse(str2);
|
|
18853
20621
|
} catch {
|
|
18854
20622
|
return {};
|
|
18855
20623
|
}
|
|
@@ -19719,9 +21487,9 @@ function mediaTypeToFormat(mediaType) {
|
|
|
19719
21487
|
};
|
|
19720
21488
|
return map[mediaType] ?? "png";
|
|
19721
21489
|
}
|
|
19722
|
-
function safeJsonParse2(
|
|
21490
|
+
function safeJsonParse2(str2) {
|
|
19723
21491
|
try {
|
|
19724
|
-
return JSON.parse(
|
|
21492
|
+
return JSON.parse(str2);
|
|
19725
21493
|
} catch {
|
|
19726
21494
|
return {};
|
|
19727
21495
|
}
|
|
@@ -20118,10 +21886,13 @@ var VertexProvider = class extends BaseProvider {
|
|
|
20118
21886
|
textParts.push(part.text);
|
|
20119
21887
|
}
|
|
20120
21888
|
} else if (part.functionCall) {
|
|
21889
|
+
const suppliedId = typeof part.functionCall.id === "string" && part.functionCall.id ? part.functionCall.id : void 0;
|
|
21890
|
+
const position = toolCallIdx++;
|
|
20121
21891
|
toolCalls.push({
|
|
20122
|
-
id: `call_${
|
|
21892
|
+
id: suppliedId ?? `call_${position}`,
|
|
20123
21893
|
name: part.functionCall.name,
|
|
20124
21894
|
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
21895
|
+
...suppliedId ? {} : { idSynthesized: true },
|
|
20125
21896
|
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
20126
21897
|
});
|
|
20127
21898
|
}
|
|
@@ -20161,12 +21932,15 @@ var VertexProvider = class extends BaseProvider {
|
|
|
20161
21932
|
}
|
|
20162
21933
|
} else if (part.functionCall) {
|
|
20163
21934
|
if (!delta.toolCalls) delta.toolCalls = [];
|
|
21935
|
+
const suppliedId = typeof part.functionCall.id === "string" && part.functionCall.id ? part.functionCall.id : void 0;
|
|
21936
|
+
const position = counter.next++;
|
|
20164
21937
|
delta.toolCalls.push({
|
|
20165
21938
|
// Unique across the whole stream: the adapter merges chunks by id.
|
|
20166
|
-
id: `call_${
|
|
20167
|
-
index:
|
|
21939
|
+
id: suppliedId ?? `call_${position}`,
|
|
21940
|
+
index: position,
|
|
20168
21941
|
name: part.functionCall.name,
|
|
20169
21942
|
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
21943
|
+
...suppliedId ? {} : { idSynthesized: true },
|
|
20170
21944
|
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
20171
21945
|
});
|
|
20172
21946
|
}
|
|
@@ -20219,12 +21993,12 @@ function mapGeminiFinishReason(reason) {
|
|
|
20219
21993
|
return "stop";
|
|
20220
21994
|
}
|
|
20221
21995
|
}
|
|
20222
|
-
function base64url(
|
|
20223
|
-
return Buffer.from(
|
|
21996
|
+
function base64url(str2) {
|
|
21997
|
+
return Buffer.from(str2).toString("base64url");
|
|
20224
21998
|
}
|
|
20225
|
-
function safeJsonParse3(
|
|
21999
|
+
function safeJsonParse3(str2) {
|
|
20226
22000
|
try {
|
|
20227
|
-
return JSON.parse(
|
|
22001
|
+
return JSON.parse(str2);
|
|
20228
22002
|
} catch {
|
|
20229
22003
|
return {};
|
|
20230
22004
|
}
|
|
@@ -20252,6 +22026,6 @@ function createProvider(config) {
|
|
|
20252
22026
|
}
|
|
20253
22027
|
}
|
|
20254
22028
|
|
|
20255
|
-
export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, LAST_SUMMARIZATION_CALL_KEY, MAX_ADJUSTMENTS, MODEL_RULES, ModelRequestError, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, allowsSampling, appendBoundTools, applyDropParams, asModelRequestError, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, clearLearnedModelRules, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, effortBudget, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getLearnedModelRulePatch, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isTraceSessionOpen, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, listLearnedModelRules, loadSkillsFromDisk, mapConsoleHookVerdict, mapReasoningEffort, mapTextParts, mcp, mediaKindOf, mediaPolicy, mergeRulePatch, modelIdCandidates, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseModelError, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, readTraceContinuation, recordOrDeferTraceEvent, redactText, regexGuardrail, regexRule, rememberModelRulePatch, replaceTextContent, replayDeferredTraceEvents, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveModelRule, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, runWithModelAdjustments, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, supportsAdaptiveThinking, textFromContent, toMessageUsage, toModelResult, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceContinuationOf, traceSectionsFromMessages, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
22029
|
+
export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GENAI_SEMCONV_COMMIT, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, LAST_SUMMARIZATION_CALL_KEY, MAX_ADJUSTMENTS, MODEL_RULES, ModelRequestError, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, allowsSampling, appendBoundTools, applyDropParams, asModelRequestError, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, clearLearnedModelRules, closeTraceContinuation, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createOtlpExporter, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, effortBudget, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, foldSupersededSpans, formatTraceparent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getLearnedModelRulePatch, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isTraceSessionOpen, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, listLearnedModelRules, loadSkillsFromDisk, mapConsoleHookVerdict, mapReasoningEffort, mapTextParts, mcp, mediaKindOf, mediaPolicy, mergeRulePatch, modelIdCandidates, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseModelError, parseSkillFrontmatter, parseTraceparent, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, readTraceContinuation, recordOrDeferTraceEvent, redactText, regexGuardrail, regexRule, rememberModelRulePatch, replaceTextContent, replayDeferredTraceEvents, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveModelRule, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, runWithModelAdjustments, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, supportsAdaptiveThinking, textFromContent, toMessageUsage, toModelResult, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceContinuationOf, traceSectionsFromMessages, traceSessionToOtlp, traceparentOf, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
20256
22030
|
//# sourceMappingURL=index.mjs.map
|
|
20257
22031
|
//# sourceMappingURL=index.mjs.map
|