@cognipeer/agent-sdk 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +311 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -8
- package/dist/index.d.ts +29 -8
- package/dist/index.mjs +311 -176
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -142,39 +142,38 @@ function withTools(model, tools) {
|
|
|
142
142
|
}
|
|
143
143
|
function fromLangchainModel(lcModel) {
|
|
144
144
|
if (!lcModel) throw new Error("fromLangchainModel: model is undefined/null");
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const detail = img.detail;
|
|
163
|
-
return { type: "image_url", image_url: { url: dataUrl, detail } };
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return part;
|
|
145
|
+
const normalizeContent = (content) => {
|
|
146
|
+
if (content == null) return content;
|
|
147
|
+
if (typeof content === "string") return content;
|
|
148
|
+
if (Array.isArray(content)) {
|
|
149
|
+
return content.map((part) => {
|
|
150
|
+
if (!part || typeof part !== "object") return part;
|
|
151
|
+
if (part.type === "text") return { type: "text", text: String(part.text ?? "") };
|
|
152
|
+
if (part.type === "image_url") {
|
|
153
|
+
const img = part.image_url;
|
|
154
|
+
if (typeof img === "string") return { type: "image_url", image_url: { url: img } };
|
|
155
|
+
if (img && typeof img === "object") {
|
|
156
|
+
if ("url" in img) return { type: "image_url", image_url: img };
|
|
157
|
+
if ("base64" in img) {
|
|
158
|
+
const media = img.media_type || "image/jpeg";
|
|
159
|
+
const dataUrl = `data:${media};base64,${img.base64}`;
|
|
160
|
+
const detail = img.detail;
|
|
161
|
+
return { type: "image_url", image_url: { url: dataUrl, detail } };
|
|
167
162
|
}
|
|
168
|
-
|
|
169
|
-
|
|
163
|
+
}
|
|
164
|
+
return part;
|
|
170
165
|
}
|
|
171
|
-
return
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
166
|
+
return part;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return content;
|
|
170
|
+
};
|
|
171
|
+
const toLC = (m) => {
|
|
172
|
+
if (m._getType || m.lc_serializable) return m;
|
|
173
|
+
return { role: m.role, content: normalizeContent(m.content), name: m.name, tool_calls: m.tool_calls, tool_call_id: m.tool_call_id };
|
|
174
|
+
};
|
|
175
|
+
const adapted = {
|
|
176
|
+
invoke: async (messages, options) => {
|
|
178
177
|
const lcMessages = messages.map(toLC);
|
|
179
178
|
const response = await lcModel.invoke(lcMessages, options);
|
|
180
179
|
if (response && typeof response === "object") {
|
|
@@ -192,38 +191,10 @@ function fromLangchainModel(lcModel) {
|
|
|
192
191
|
},
|
|
193
192
|
stream: async function* (messages, options) {
|
|
194
193
|
if (typeof lcModel.stream !== "function") return;
|
|
195
|
-
const normalizeContent = (content) => {
|
|
196
|
-
if (content == null) return content;
|
|
197
|
-
if (typeof content === "string") return content;
|
|
198
|
-
if (Array.isArray(content)) {
|
|
199
|
-
return content.map((part) => {
|
|
200
|
-
if (!part || typeof part !== "object") return part;
|
|
201
|
-
if (part.type === "text") return { type: "text", text: String(part.text ?? "") };
|
|
202
|
-
if (part.type === "image_url") {
|
|
203
|
-
const img = part.image_url;
|
|
204
|
-
if (typeof img === "string") return { type: "image_url", image_url: { url: img } };
|
|
205
|
-
if (img && typeof img === "object") {
|
|
206
|
-
if ("url" in img) return { type: "image_url", image_url: img };
|
|
207
|
-
if ("base64" in img) {
|
|
208
|
-
const media = img.media_type || "image/jpeg";
|
|
209
|
-
const dataUrl = `data:${media};base64,${img.base64}`;
|
|
210
|
-
const detail = img.detail;
|
|
211
|
-
return { type: "image_url", image_url: { url: dataUrl, detail } };
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return part;
|
|
215
|
-
}
|
|
216
|
-
return part;
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
return content;
|
|
220
|
-
};
|
|
221
|
-
const toLC = (m) => {
|
|
222
|
-
if (m._getType || m.lc_serializable) return m;
|
|
223
|
-
return { role: m.role, content: normalizeContent(m.content), name: m.name, tool_calls: m.tool_calls, tool_call_id: m.tool_call_id };
|
|
224
|
-
};
|
|
225
194
|
const lcMessages = messages.map(toLC);
|
|
226
|
-
|
|
195
|
+
const streamResult = lcModel.stream(lcMessages, options);
|
|
196
|
+
const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
|
|
197
|
+
for await (const chunk of stream) {
|
|
227
198
|
yield chunk;
|
|
228
199
|
}
|
|
229
200
|
},
|
|
@@ -345,17 +316,17 @@ function normalizeUsage(raw) {
|
|
|
345
316
|
raw.totalTokens,
|
|
346
317
|
(typeof prompt === "number" ? prompt : 0) + (typeof completion === "number" ? completion : 0)
|
|
347
318
|
);
|
|
348
|
-
const promptDetailsSrc = raw.prompt_tokens_details || raw.promptTokensDetails || {};
|
|
349
|
-
const completionDetailsSrc = raw.completion_tokens_details || raw.completionTokensDetails || {};
|
|
319
|
+
const promptDetailsSrc = raw.prompt_tokens_details || raw.promptTokensDetails || raw.input_token_details || raw.inputTokenDetails || {};
|
|
320
|
+
const completionDetailsSrc = raw.completion_tokens_details || raw.completionTokensDetails || raw.output_token_details || raw.outputTokenDetails || {};
|
|
350
321
|
const normalized = {
|
|
351
322
|
prompt_tokens: safe(prompt),
|
|
352
323
|
completion_tokens: safe(completion),
|
|
353
324
|
total_tokens: safe(total || (prompt || 0) + (completion || 0)),
|
|
354
325
|
prompt_tokens_details: {
|
|
355
326
|
cached_tokens: safe(
|
|
356
|
-
promptDetailsSrc.cached_tokens || promptDetailsSrc.cached || raw.cached_input_tokens || raw.cached_prompt_tokens
|
|
327
|
+
promptDetailsSrc.cached_tokens || promptDetailsSrc.cached || promptDetailsSrc.cache_read || raw.cached_input_tokens || raw.cached_prompt_tokens || raw.cache_read_input_tokens
|
|
357
328
|
),
|
|
358
|
-
audio_tokens: safe(promptDetailsSrc.audio_tokens)
|
|
329
|
+
audio_tokens: safe(promptDetailsSrc.audio_tokens || promptDetailsSrc.audio)
|
|
359
330
|
},
|
|
360
331
|
completion_tokens_details: {
|
|
361
332
|
reasoning_tokens: safe(completionDetailsSrc.reasoning_tokens),
|
|
@@ -1041,8 +1012,12 @@ function recordTraceEvent(session, event) {
|
|
|
1041
1012
|
session.summary.eventCounts[event.type] = (session.summary.eventCounts[event.type] || 0) + 1;
|
|
1042
1013
|
let sections;
|
|
1043
1014
|
if (session.resolvedConfig.logData) {
|
|
1044
|
-
|
|
1045
|
-
|
|
1015
|
+
if (event.sections && event.sections.length > 0) {
|
|
1016
|
+
sections = ensureUniqueSections(id, event.sections);
|
|
1017
|
+
} else {
|
|
1018
|
+
const converted = convertMessageListToSections(event.messageList);
|
|
1019
|
+
sections = ensureUniqueSections(id, converted);
|
|
1020
|
+
}
|
|
1046
1021
|
}
|
|
1047
1022
|
const resolvedModel = event.model ?? inferModelFromMessages(event.messageList);
|
|
1048
1023
|
const resolvedProvider = event.provider ?? inferProviderFromMessages(event.messageList);
|
|
@@ -1305,7 +1280,18 @@ function createAgentCoreNode(opts) {
|
|
|
1305
1280
|
outputSchema: opts.outputSchema,
|
|
1306
1281
|
tracing: opts.tracing
|
|
1307
1282
|
};
|
|
1308
|
-
const
|
|
1283
|
+
const rawTools = runtime.tools ?? [];
|
|
1284
|
+
const seenNames = /* @__PURE__ */ new Map();
|
|
1285
|
+
const tools = [];
|
|
1286
|
+
for (const t of rawTools) {
|
|
1287
|
+
const tName = t.name ?? t.schema?.title;
|
|
1288
|
+
if (tName && seenNames.has(tName)) {
|
|
1289
|
+
tools[seenNames.get(tName)] = t;
|
|
1290
|
+
} else {
|
|
1291
|
+
if (tName) seenNames.set(tName, tools.length);
|
|
1292
|
+
tools.push(t);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1309
1295
|
const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(tools) : runtime.model;
|
|
1310
1296
|
const traceSession = state.ctx?.__traceSession;
|
|
1311
1297
|
const actorName = runtime.name ?? opts.name ?? "agent";
|
|
@@ -1358,26 +1344,6 @@ function createAgentCoreNode(opts) {
|
|
|
1358
1344
|
}
|
|
1359
1345
|
return filteredMsgs;
|
|
1360
1346
|
};
|
|
1361
|
-
const debugToolPairing = (messagesToSend) => {
|
|
1362
|
-
try {
|
|
1363
|
-
const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
|
|
1364
|
-
const toolUseIds = [];
|
|
1365
|
-
const missingResults = [];
|
|
1366
|
-
for (let i = 0; i < msgs.length; i++) {
|
|
1367
|
-
const m = msgs[i];
|
|
1368
|
-
if (m?.role === "assistant") {
|
|
1369
|
-
for (const tu of extractToolUses(m)) {
|
|
1370
|
-
toolUseIds.push(tu.id);
|
|
1371
|
-
const next = msgs[i + 1];
|
|
1372
|
-
if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
|
|
1373
|
-
missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
} catch (e) {
|
|
1379
|
-
}
|
|
1380
|
-
};
|
|
1381
1347
|
const onEvent = state.ctx?.__onEvent;
|
|
1382
1348
|
const onStream = state.ctx?.__onStream;
|
|
1383
1349
|
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
@@ -1408,25 +1374,54 @@ function createAgentCoreNode(opts) {
|
|
|
1408
1374
|
const hasContentToolUse = contentArr.some((c) => c?.type === "tool_use" && c?.id);
|
|
1409
1375
|
const hasAdditionalToolCalls = Array.isArray(m.additional_kwargs?.tool_calls) && m.additional_kwargs.tool_calls.length > 0;
|
|
1410
1376
|
if (!hasToolCalls && !hasContentToolUse && !hasAdditionalToolCalls) continue;
|
|
1411
|
-
if (hasToolCalls) {
|
|
1412
|
-
|
|
1377
|
+
if (hasToolCalls && hasContentToolUse) {
|
|
1378
|
+
const toolCallIds = new Set(
|
|
1379
|
+
m.tool_calls.filter((tc) => tc?.id).map((tc) => tc.id)
|
|
1380
|
+
);
|
|
1381
|
+
const filtered = contentArr.filter((c) => {
|
|
1382
|
+
if (c?.type === "tool_use" && c?.id && toolCallIds.has(c.id)) return false;
|
|
1383
|
+
return true;
|
|
1384
|
+
});
|
|
1385
|
+
if (filtered.length === 0) {
|
|
1386
|
+
m.content = "";
|
|
1387
|
+
} else if (filtered.length !== contentArr.length) {
|
|
1388
|
+
m.content = filtered.length === 1 && filtered[0]?.type === "text" ? filtered[0].text ?? "" : filtered;
|
|
1389
|
+
}
|
|
1413
1390
|
}
|
|
1414
|
-
if (
|
|
1415
|
-
|
|
1416
|
-
(
|
|
1391
|
+
if (hasAdditionalToolCalls && Array.isArray(m.content)) {
|
|
1392
|
+
const akIds = new Set(
|
|
1393
|
+
m.additional_kwargs.tool_calls.filter((tc) => tc?.id).map((tc) => tc.id)
|
|
1417
1394
|
);
|
|
1395
|
+
const arr = m.content;
|
|
1396
|
+
const filtered = arr.filter((c) => {
|
|
1397
|
+
if (c?.type === "tool_use" && c?.id && akIds.has(c.id)) return false;
|
|
1398
|
+
return true;
|
|
1399
|
+
});
|
|
1400
|
+
if (filtered.length !== arr.length) {
|
|
1401
|
+
m.content = filtered.length === 0 ? "" : filtered.length === 1 && filtered[0]?.type === "text" ? filtered[0].text ?? "" : filtered;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
if (hasToolCalls) {
|
|
1405
|
+
m.tool_calls = m.tool_calls.map((tc) => ({ ...tc }));
|
|
1418
1406
|
}
|
|
1419
1407
|
if (hasAdditionalToolCalls) {
|
|
1420
1408
|
m.additional_kwargs = { ...m.additional_kwargs };
|
|
1421
1409
|
m.additional_kwargs.tool_calls = m.additional_kwargs.tool_calls.map((tc) => ({ ...tc }));
|
|
1422
1410
|
}
|
|
1411
|
+
const remainingContentArr = Array.isArray(m.content) ? m.content : [];
|
|
1412
|
+
const hasRemainingContentToolUse = remainingContentArr.some((c) => c?.type === "tool_use" && c?.id);
|
|
1413
|
+
if (hasRemainingContentToolUse) {
|
|
1414
|
+
m.content = remainingContentArr.map(
|
|
1415
|
+
(c) => c && typeof c === "object" ? { ...c } : c
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1423
1418
|
const idsInMessage = /* @__PURE__ */ new Set();
|
|
1424
1419
|
if (hasToolCalls) {
|
|
1425
1420
|
for (const tc of m.tool_calls) {
|
|
1426
1421
|
if (tc?.id) idsInMessage.add(tc.id);
|
|
1427
1422
|
}
|
|
1428
1423
|
}
|
|
1429
|
-
if (
|
|
1424
|
+
if (hasRemainingContentToolUse) {
|
|
1430
1425
|
for (const c of m.content) {
|
|
1431
1426
|
if (c?.type === "tool_use" && c?.id) idsInMessage.add(c.id);
|
|
1432
1427
|
}
|
|
@@ -1447,7 +1442,7 @@ function createAgentCoreNode(opts) {
|
|
|
1447
1442
|
if (tc.id === id) tc.id = newId;
|
|
1448
1443
|
}
|
|
1449
1444
|
}
|
|
1450
|
-
if (
|
|
1445
|
+
if (hasRemainingContentToolUse && Array.isArray(m.content)) {
|
|
1451
1446
|
for (const c of m.content) {
|
|
1452
1447
|
if (c?.type === "tool_use" && c.id === id) c.id = newId;
|
|
1453
1448
|
}
|
|
@@ -1485,11 +1480,12 @@ function createAgentCoreNode(opts) {
|
|
|
1485
1480
|
const normalizedMessages = ensureUniqueToolCallIds(
|
|
1486
1481
|
normalizeBedrockToolPairing([...state.messages])
|
|
1487
1482
|
);
|
|
1488
|
-
debugToolPairing(normalizedMessages);
|
|
1489
1483
|
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
1490
1484
|
let streamedText = "";
|
|
1491
1485
|
let streamedMessage;
|
|
1492
|
-
|
|
1486
|
+
const streamResult = modelWithTools.stream(normalizedMessages, { signal: abortSignal, cancellationToken });
|
|
1487
|
+
const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
|
|
1488
|
+
for await (const chunk of stream) {
|
|
1493
1489
|
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
1494
1490
|
break;
|
|
1495
1491
|
}
|
|
@@ -1534,7 +1530,7 @@ function createAgentCoreNode(opts) {
|
|
|
1534
1530
|
...state.messages,
|
|
1535
1531
|
response
|
|
1536
1532
|
];
|
|
1537
|
-
const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
1533
|
+
const rawUsage = response?.usage_metadata || response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
1538
1534
|
const normalized = normalizeUsage(rawUsage);
|
|
1539
1535
|
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
1540
1536
|
const durationMs = Date.now() - start;
|
|
@@ -1625,41 +1621,6 @@ function createToolsNode(initialTools, opts) {
|
|
|
1625
1621
|
const remaining = Math.max(0, limits.maxToolCalls - toolCount);
|
|
1626
1622
|
const planned = toolCalls.slice(0, remaining);
|
|
1627
1623
|
const skipped = toolCalls.slice(remaining);
|
|
1628
|
-
for (const tc of skipped) {
|
|
1629
|
-
onEvent?.({ type: "tool_call", phase: "skipped", name: tc.name, id: tc.id, args: tc.args });
|
|
1630
|
-
const sanitizedArgs = sanitizeTracePayload(tc.args);
|
|
1631
|
-
const messageList = [
|
|
1632
|
-
{
|
|
1633
|
-
role: "assistant",
|
|
1634
|
-
name: tc.name,
|
|
1635
|
-
content: `Skipped tool due to tool-call limit: ${tc.name}`,
|
|
1636
|
-
tool_calls: [
|
|
1637
|
-
{
|
|
1638
|
-
id: tc.id,
|
|
1639
|
-
type: "function",
|
|
1640
|
-
function: {
|
|
1641
|
-
name: tc.name,
|
|
1642
|
-
arguments: sanitizedArgs
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
]
|
|
1646
|
-
}
|
|
1647
|
-
];
|
|
1648
|
-
recordTraceEvent(traceSession, {
|
|
1649
|
-
type: "tool_call",
|
|
1650
|
-
label: `Tool Skipped - ${tc.name}`,
|
|
1651
|
-
actor: { scope: "tool", name: tc.name, role: "tool" },
|
|
1652
|
-
status: "skipped",
|
|
1653
|
-
toolExecutionId: tc.id,
|
|
1654
|
-
messageList
|
|
1655
|
-
});
|
|
1656
|
-
appended.push({
|
|
1657
|
-
role: "tool",
|
|
1658
|
-
content: `Skipped tool due to tool-call limit: ${tc.name}`,
|
|
1659
|
-
tool_call_id: tc.id || `${tc.name}_${appended.length}`,
|
|
1660
|
-
name: tc.name
|
|
1661
|
-
});
|
|
1662
|
-
}
|
|
1663
1624
|
const isCancelled = () => {
|
|
1664
1625
|
if (abortSignal?.aborted) return { cancelled: true, reason: "aborted" };
|
|
1665
1626
|
if (cancellationToken && cancellationToken.isCancellationRequested) return { cancelled: true, reason: "cancelled" };
|
|
@@ -1900,6 +1861,42 @@ function createToolsNode(initialTools, opts) {
|
|
|
1900
1861
|
break;
|
|
1901
1862
|
}
|
|
1902
1863
|
}
|
|
1864
|
+
for (const tc of skipped) {
|
|
1865
|
+
onEvent?.({ type: "tool_call", phase: "skipped", name: tc.name, id: tc.id, args: tc.args });
|
|
1866
|
+
const sanitizedArgs = sanitizeTracePayload(tc.args);
|
|
1867
|
+
const messageList = [
|
|
1868
|
+
{
|
|
1869
|
+
role: "assistant",
|
|
1870
|
+
name: tc.name,
|
|
1871
|
+
content: `Skipped tool due to tool-call limit: ${tc.name}`,
|
|
1872
|
+
tool_calls: [
|
|
1873
|
+
{
|
|
1874
|
+
id: tc.id,
|
|
1875
|
+
type: "function",
|
|
1876
|
+
function: {
|
|
1877
|
+
name: tc.name,
|
|
1878
|
+
arguments: sanitizedArgs
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
]
|
|
1882
|
+
}
|
|
1883
|
+
];
|
|
1884
|
+
recordTraceEvent(traceSession, {
|
|
1885
|
+
type: "tool_call",
|
|
1886
|
+
label: `Tool Skipped - ${tc.name}`,
|
|
1887
|
+
actor: { scope: "tool", name: tc.name, role: "tool" },
|
|
1888
|
+
status: "skipped",
|
|
1889
|
+
toolExecutionId: tc.id,
|
|
1890
|
+
messageList
|
|
1891
|
+
});
|
|
1892
|
+
appended.push({
|
|
1893
|
+
role: "tool",
|
|
1894
|
+
content: `Skipped tool due to tool-call limit: ${tc.name}`,
|
|
1895
|
+
tool_call_id: tc.id || `${tc.name}_${appended.length}`,
|
|
1896
|
+
name: tc.name
|
|
1897
|
+
});
|
|
1898
|
+
toolCount += 1;
|
|
1899
|
+
}
|
|
1903
1900
|
if (!awaitingApproval && state.ctx?.__awaitingApproval) {
|
|
1904
1901
|
const ctx = { ...state.ctx };
|
|
1905
1902
|
delete ctx.__awaitingApproval;
|
|
@@ -2131,7 +2128,62 @@ function resolveToolApprovalState(state, resolution) {
|
|
|
2131
2128
|
// src/utils/utilTokens.ts
|
|
2132
2129
|
function countApproxTokens(text) {
|
|
2133
2130
|
if (!text) return 0;
|
|
2134
|
-
|
|
2131
|
+
const nonAsciiCount = (text.match(/[^\x00-\x7F]/g) || []).length;
|
|
2132
|
+
const asciiCount = text.length - nonAsciiCount;
|
|
2133
|
+
return Math.ceil(asciiCount / 4 + nonAsciiCount / 1.5);
|
|
2134
|
+
}
|
|
2135
|
+
function extractMessageText(m) {
|
|
2136
|
+
if (!m) return "";
|
|
2137
|
+
const parts = [];
|
|
2138
|
+
parts.push(m.role || "");
|
|
2139
|
+
if (m.name) parts.push(m.name);
|
|
2140
|
+
if (typeof m.content === "string") {
|
|
2141
|
+
parts.push(m.content);
|
|
2142
|
+
} else if (Array.isArray(m.content)) {
|
|
2143
|
+
for (const c of m.content) {
|
|
2144
|
+
if (typeof c === "string") parts.push(c);
|
|
2145
|
+
else if (c?.text) parts.push(c.text);
|
|
2146
|
+
else if (c?.content) parts.push(c.content);
|
|
2147
|
+
else if (c?.type === "tool_use" && c?.input) {
|
|
2148
|
+
parts.push(c.name || "");
|
|
2149
|
+
parts.push(typeof c.input === "string" ? c.input : JSON.stringify(c.input));
|
|
2150
|
+
} else if (c != null && typeof c === "object") {
|
|
2151
|
+
parts.push(JSON.stringify(c));
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
} else if (m.content != null && typeof m.content === "object") {
|
|
2155
|
+
parts.push(JSON.stringify(m.content));
|
|
2156
|
+
}
|
|
2157
|
+
if (Array.isArray(m.tool_calls)) {
|
|
2158
|
+
for (const tc of m.tool_calls) {
|
|
2159
|
+
if (tc?.function?.name) parts.push(tc.function.name);
|
|
2160
|
+
if (tc?.function?.arguments) {
|
|
2161
|
+
parts.push(
|
|
2162
|
+
typeof tc.function.arguments === "string" ? tc.function.arguments : JSON.stringify(tc.function.arguments)
|
|
2163
|
+
);
|
|
2164
|
+
}
|
|
2165
|
+
if (tc?.name && !tc?.function?.name) parts.push(tc.name);
|
|
2166
|
+
if (tc?.args && !tc?.function?.arguments) {
|
|
2167
|
+
parts.push(typeof tc.args === "string" ? tc.args : JSON.stringify(tc.args));
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
if (Array.isArray(m.additional_kwargs?.tool_calls)) {
|
|
2172
|
+
for (const tc of m.additional_kwargs.tool_calls) {
|
|
2173
|
+
if (tc?.function?.name) parts.push(tc.function.name);
|
|
2174
|
+
if (tc?.function?.arguments) {
|
|
2175
|
+
parts.push(
|
|
2176
|
+
typeof tc.function.arguments === "string" ? tc.function.arguments : JSON.stringify(tc.function.arguments)
|
|
2177
|
+
);
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return parts.join("\n");
|
|
2182
|
+
}
|
|
2183
|
+
function countMessagesTokens(messages) {
|
|
2184
|
+
if (!Array.isArray(messages) || messages.length === 0) return 0;
|
|
2185
|
+
const allText = messages.map(extractMessageText).join("\n");
|
|
2186
|
+
return countApproxTokens(allText) + messages.length * 4;
|
|
2135
2187
|
}
|
|
2136
2188
|
|
|
2137
2189
|
// src/agent.ts
|
|
@@ -2234,7 +2286,8 @@ function createAgent(opts) {
|
|
|
2234
2286
|
let result = false;
|
|
2235
2287
|
try {
|
|
2236
2288
|
result = onStateChange(state);
|
|
2237
|
-
} catch {
|
|
2289
|
+
} catch (err) {
|
|
2290
|
+
console.warn("[agent-sdk] onStateChange callback error:", err);
|
|
2238
2291
|
result = false;
|
|
2239
2292
|
}
|
|
2240
2293
|
if (!result) return false;
|
|
@@ -2301,8 +2354,7 @@ function createAgent(opts) {
|
|
|
2301
2354
|
maxTok = 5e4;
|
|
2302
2355
|
}
|
|
2303
2356
|
if (maxTok) {
|
|
2304
|
-
const
|
|
2305
|
-
const tokenCount = countApproxTokens(allText);
|
|
2357
|
+
const tokenCount = countMessagesTokens(state.messages || []);
|
|
2306
2358
|
if (tokenCount > maxTok) {
|
|
2307
2359
|
const ctx = { ...state.ctx || {}, __needsSummarization: true };
|
|
2308
2360
|
state = { ...state, ctx };
|
|
@@ -2412,7 +2464,9 @@ function createAgent(opts) {
|
|
|
2412
2464
|
if (toolCallsAfter.length > 0) {
|
|
2413
2465
|
state = { ...state, ...await toolsNode(state) };
|
|
2414
2466
|
}
|
|
2415
|
-
} catch {
|
|
2467
|
+
} catch (err) {
|
|
2468
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2469
|
+
emit?.({ type: "metadata", error: `Structured output force-finalize failed: ${errMsg}` });
|
|
2416
2470
|
}
|
|
2417
2471
|
}
|
|
2418
2472
|
}
|
|
@@ -2430,13 +2484,15 @@ function createAgent(opts) {
|
|
|
2430
2484
|
const emit = (e) => {
|
|
2431
2485
|
try {
|
|
2432
2486
|
onEvent?.(e);
|
|
2433
|
-
} catch {
|
|
2487
|
+
} catch (err) {
|
|
2488
|
+
console.warn("[agent-sdk] onEvent callback error:", err);
|
|
2434
2489
|
}
|
|
2435
2490
|
};
|
|
2436
2491
|
const emitProgress = (progress) => {
|
|
2437
2492
|
try {
|
|
2438
2493
|
onProgress?.(progress);
|
|
2439
|
-
} catch {
|
|
2494
|
+
} catch (err) {
|
|
2495
|
+
console.warn("[agent-sdk] onProgress callback error:", err);
|
|
2440
2496
|
}
|
|
2441
2497
|
emit({ type: "progress", ...progress });
|
|
2442
2498
|
};
|
|
@@ -2679,6 +2735,83 @@ function createAgentNode(opts) {
|
|
|
2679
2735
|
};
|
|
2680
2736
|
}
|
|
2681
2737
|
|
|
2738
|
+
// src/utils/traceSections.ts
|
|
2739
|
+
function formatMessageContent(content) {
|
|
2740
|
+
if (content == null) return "";
|
|
2741
|
+
if (typeof content === "string") return content;
|
|
2742
|
+
if (Array.isArray(content)) {
|
|
2743
|
+
return content.map((item) => {
|
|
2744
|
+
if (typeof item === "string") return item;
|
|
2745
|
+
if (item && typeof item === "object") {
|
|
2746
|
+
if (typeof item.text === "string") return item.text;
|
|
2747
|
+
if (typeof item.content === "string") return item.content;
|
|
2748
|
+
try {
|
|
2749
|
+
return JSON.stringify(item);
|
|
2750
|
+
} catch {
|
|
2751
|
+
return String(item);
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
try {
|
|
2755
|
+
return JSON.stringify(item);
|
|
2756
|
+
} catch {
|
|
2757
|
+
return String(item);
|
|
2758
|
+
}
|
|
2759
|
+
}).filter(Boolean).join("\n");
|
|
2760
|
+
}
|
|
2761
|
+
if (typeof content === "object") {
|
|
2762
|
+
if (typeof content.text === "string") return content.text;
|
|
2763
|
+
if (typeof content.content === "string") return content.content;
|
|
2764
|
+
try {
|
|
2765
|
+
return JSON.stringify(content, null, 2);
|
|
2766
|
+
} catch {
|
|
2767
|
+
return String(content);
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
return String(content);
|
|
2771
|
+
}
|
|
2772
|
+
function buildSummarizationSections(opts) {
|
|
2773
|
+
const sections = [];
|
|
2774
|
+
sections.push({
|
|
2775
|
+
kind: "summary",
|
|
2776
|
+
label: "Context Summary",
|
|
2777
|
+
content: opts.summaryText
|
|
2778
|
+
});
|
|
2779
|
+
const tokensSaved = opts.tokenCountBefore - opts.tokenCountAfter;
|
|
2780
|
+
const reductionPct = opts.tokenCountBefore > 0 ? Math.round(tokensSaved / opts.tokenCountBefore * 100) : 0;
|
|
2781
|
+
const metaData = {
|
|
2782
|
+
messagesCompressed: opts.messagesCompressed,
|
|
2783
|
+
tokenCountBefore: opts.tokenCountBefore,
|
|
2784
|
+
tokenCountAfter: opts.tokenCountAfter,
|
|
2785
|
+
tokensSaved,
|
|
2786
|
+
reductionPercent: reductionPct
|
|
2787
|
+
};
|
|
2788
|
+
if (opts.inputTokens !== void 0) metaData.inputTokens = opts.inputTokens;
|
|
2789
|
+
if (opts.outputTokens !== void 0) metaData.outputTokens = opts.outputTokens;
|
|
2790
|
+
if (opts.cachedInputTokens !== void 0) metaData.cachedInputTokens = opts.cachedInputTokens;
|
|
2791
|
+
if (opts.durationMs !== void 0) metaData.durationMs = opts.durationMs;
|
|
2792
|
+
if (opts.previousSummary) metaData.previousSummaryLength = opts.previousSummary.length;
|
|
2793
|
+
sections.push({
|
|
2794
|
+
kind: "metadata",
|
|
2795
|
+
label: "Summarization Stats",
|
|
2796
|
+
data: metaData
|
|
2797
|
+
});
|
|
2798
|
+
if (Array.isArray(opts.promptMessages) && opts.promptMessages.length > 0) {
|
|
2799
|
+
for (const msg of opts.promptMessages) {
|
|
2800
|
+
const role = typeof msg?.role === "string" ? msg.role : "system";
|
|
2801
|
+
const content = formatMessageContent(msg?.content ?? "");
|
|
2802
|
+
if (content) {
|
|
2803
|
+
sections.push({
|
|
2804
|
+
kind: "message",
|
|
2805
|
+
label: `Summarization Prompt (${role})`,
|
|
2806
|
+
role,
|
|
2807
|
+
content
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
return sections;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2682
2815
|
// src/nodes/contextSummarize.ts
|
|
2683
2816
|
var systemMessage = (content) => ({ role: "system", content });
|
|
2684
2817
|
var humanMessage = (content) => ({ role: "user", content });
|
|
@@ -2737,8 +2870,7 @@ function createContextSummarizeNode(opts) {
|
|
|
2737
2870
|
if (compressableMessages.length === 0) {
|
|
2738
2871
|
return {};
|
|
2739
2872
|
}
|
|
2740
|
-
const
|
|
2741
|
-
const tokenCountBefore = countApproxTokens(allTextBefore);
|
|
2873
|
+
const tokenCountBefore = countMessagesTokens(messages);
|
|
2742
2874
|
const summaryPromptMaxTokens = config.summaryPromptMaxTokens;
|
|
2743
2875
|
const availableTokensForConversation = summaryPromptMaxTokens - 500;
|
|
2744
2876
|
const messageTexts = [];
|
|
@@ -2801,7 +2933,7 @@ Summary:`;
|
|
|
2801
2933
|
durationMs = Date.now() - startTime;
|
|
2802
2934
|
summaryText = typeof response.content === "string" ? response.content : Array.isArray(response.content) ? response.content.map((c) => c.text || "").join("") : JSON.stringify(response.content);
|
|
2803
2935
|
outputTokensEstimate = countApproxTokens(summaryText);
|
|
2804
|
-
const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
2936
|
+
const rawUsage = response?.usage_metadata || response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
2805
2937
|
const normalized = normalizeUsage(rawUsage);
|
|
2806
2938
|
if (normalized) {
|
|
2807
2939
|
inputTokensActual = normalized.prompt_tokens;
|
|
@@ -2833,7 +2965,16 @@ Summary:`;
|
|
|
2833
2965
|
inputTokens: inputTokensEstimate,
|
|
2834
2966
|
outputTokens: 0,
|
|
2835
2967
|
error: { message: err?.message || String(err), stack: err?.stack },
|
|
2836
|
-
|
|
2968
|
+
sections: buildSummarizationSections({
|
|
2969
|
+
summaryText: "",
|
|
2970
|
+
messagesCompressed: 0,
|
|
2971
|
+
tokenCountBefore,
|
|
2972
|
+
tokenCountAfter: tokenCountBefore,
|
|
2973
|
+
inputTokens: inputTokensEstimate,
|
|
2974
|
+
outputTokens: 0,
|
|
2975
|
+
durationMs,
|
|
2976
|
+
promptMessages: summaryPrompt
|
|
2977
|
+
})
|
|
2837
2978
|
});
|
|
2838
2979
|
return {};
|
|
2839
2980
|
}
|
|
@@ -2887,8 +3028,7 @@ Summary:`;
|
|
|
2887
3028
|
};
|
|
2888
3029
|
const summaries = Array.isArray(state.summaries) ? [...state.summaries, summaryText] : [summaryText];
|
|
2889
3030
|
const finalMessages = [...validatedMessages, assistantSummaryCall, toolSummaryResponse];
|
|
2890
|
-
const
|
|
2891
|
-
const tokenCountAfter = countApproxTokens(allTextAfter);
|
|
3031
|
+
const tokenCountAfter = countMessagesTokens(finalMessages);
|
|
2892
3032
|
const summarizationEvent = {
|
|
2893
3033
|
type: "summarization",
|
|
2894
3034
|
summary: summaryText,
|
|
@@ -2915,10 +3055,21 @@ Summary:`;
|
|
|
2915
3055
|
outputTokens: outputTokensActual ?? outputTokensEstimate,
|
|
2916
3056
|
cachedInputTokens,
|
|
2917
3057
|
totalTokens: totalTokensActual,
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
3058
|
+
sections: buildSummarizationSections({
|
|
3059
|
+
summaryText,
|
|
3060
|
+
previousSummary: previousSummary || void 0,
|
|
3061
|
+
messagesCompressed: compressableMessages.length,
|
|
3062
|
+
tokenCountBefore,
|
|
3063
|
+
tokenCountAfter,
|
|
3064
|
+
inputTokens: inputTokensActual ?? inputTokensEstimate,
|
|
3065
|
+
outputTokens: outputTokensActual ?? outputTokensEstimate,
|
|
3066
|
+
cachedInputTokens,
|
|
3067
|
+
durationMs,
|
|
3068
|
+
promptMessages: sanitizeTracePayload([
|
|
3069
|
+
...summaryPrompt,
|
|
3070
|
+
{ role: "assistant", content: summaryText, name: "summarization_result" }
|
|
3071
|
+
])
|
|
3072
|
+
}),
|
|
2922
3073
|
debug: {
|
|
2923
3074
|
messagesCompressed: compressableMessages.length,
|
|
2924
3075
|
tokenCountBefore,
|
|
@@ -2946,6 +3097,12 @@ async function applyTokenLimits({
|
|
|
2946
3097
|
let total = messages.reduce((acc, m) => acc + countApproxTokens(String(m.content || "")), 0);
|
|
2947
3098
|
if (total <= budget) return state;
|
|
2948
3099
|
const newMessages = [...messages];
|
|
3100
|
+
while (total > budget && newMessages.length > 1) {
|
|
3101
|
+
const idx = newMessages.findIndex((m) => m.role !== "system");
|
|
3102
|
+
if (idx === -1) break;
|
|
3103
|
+
const removed = newMessages.splice(idx, 1)[0];
|
|
3104
|
+
total -= countApproxTokens(String(removed.content || ""));
|
|
3105
|
+
}
|
|
2949
3106
|
return { ...state, messages: newMessages };
|
|
2950
3107
|
}
|
|
2951
3108
|
function createContextTools(stateRef, opts) {
|
|
@@ -3036,30 +3193,8 @@ function needsSummarization(state, opts, summarizationEnabled) {
|
|
|
3036
3193
|
maxTok = 5e4;
|
|
3037
3194
|
}
|
|
3038
3195
|
try {
|
|
3039
|
-
const
|
|
3040
|
-
|
|
3041
|
-
if (Array.isArray(m.content)) {
|
|
3042
|
-
return m.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? JSON.stringify(c)).join("");
|
|
3043
|
-
}
|
|
3044
|
-
if (m.content && typeof m.content === "object") {
|
|
3045
|
-
return JSON.stringify(m.content);
|
|
3046
|
-
}
|
|
3047
|
-
return "";
|
|
3048
|
-
}).join("\n");
|
|
3049
|
-
const tokenCount = countApproxTokens(allText);
|
|
3050
|
-
const needsSum = tokenCount > maxTok;
|
|
3051
|
-
if (process.env.DEBUG_SUMMARIZATION) {
|
|
3052
|
-
const msgCount = (state.messages || []).length;
|
|
3053
|
-
const toolMsgs = (state.messages || []).filter((m) => m.role === "tool");
|
|
3054
|
-
const toolDetails = toolMsgs.map((m, i) => {
|
|
3055
|
-
const contentStr = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
3056
|
-
return `[${i}] id:${m.tool_call_id?.slice(-8) || "none"} len:${contentStr.length} preview:"${contentStr.slice(0, 30)}..."`;
|
|
3057
|
-
});
|
|
3058
|
-
console.log(`[Summarization] Messages: ${msgCount}, Tool messages: ${toolMsgs.length}`);
|
|
3059
|
-
toolDetails.forEach((d) => console.log(` ${d}`));
|
|
3060
|
-
console.log(`[Summarization] Token count: ${tokenCount}, Max: ${maxTok}, Needs summarization: ${needsSum}`);
|
|
3061
|
-
}
|
|
3062
|
-
return needsSum;
|
|
3196
|
+
const tokenCount = countMessagesTokens(state.messages || []);
|
|
3197
|
+
return tokenCount > maxTok;
|
|
3063
3198
|
} catch (e) {
|
|
3064
3199
|
return false;
|
|
3065
3200
|
}
|
|
@@ -3465,6 +3600,7 @@ exports.captureSnapshot = captureSnapshot;
|
|
|
3465
3600
|
exports.codePresenceRule = codePresenceRule;
|
|
3466
3601
|
exports.cognipeerSink = cognipeerSink;
|
|
3467
3602
|
exports.countApproxTokens = countApproxTokens;
|
|
3603
|
+
exports.countMessagesTokens = countMessagesTokens;
|
|
3468
3604
|
exports.createAgent = createAgent;
|
|
3469
3605
|
exports.createAgentNode = createAgentNode;
|
|
3470
3606
|
exports.createCodeGuardrail = createCodeGuardrail;
|