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