@cognipeer/agent-sdk 0.2.7 → 0.2.9
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 +63 -244
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -15
- package/dist/index.d.ts +8 -15
- package/dist/index.mjs +63 -244
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -75,15 +75,16 @@ interface ToolInterface<TInput = any, TOutput = any, TCallOptions = any> {
|
|
|
75
75
|
approvalDefaults?: any;
|
|
76
76
|
[key: string]: any;
|
|
77
77
|
}
|
|
78
|
-
type RunnableConfig =
|
|
78
|
+
type RunnableConfig = {
|
|
79
|
+
[key: string]: any;
|
|
80
|
+
};
|
|
79
81
|
type BaseMessage = {
|
|
80
82
|
role: string;
|
|
81
83
|
name?: string;
|
|
82
84
|
content: string | ContentPart[];
|
|
83
85
|
tool_calls?: any;
|
|
84
86
|
tool_call_id?: string;
|
|
85
|
-
|
|
86
|
-
additional_kwargs?: Record<string, any>;
|
|
87
|
+
[key: string]: any;
|
|
87
88
|
};
|
|
88
89
|
type AIMessage = BaseMessage & {
|
|
89
90
|
role: 'assistant';
|
|
@@ -143,7 +144,6 @@ type AgentLimits = {
|
|
|
143
144
|
maxToolCalls?: number;
|
|
144
145
|
maxParallelTools?: number;
|
|
145
146
|
};
|
|
146
|
-
/** @deprecated Use AgentLimits instead */
|
|
147
147
|
type SmartAgentLimits = AgentLimits;
|
|
148
148
|
type TraceSinkFileConfig = {
|
|
149
149
|
type: "file";
|
|
@@ -168,20 +168,15 @@ type TraceSinkConfig = TraceSinkFileConfig | TraceSinkCustomConfig | TraceSinkCo
|
|
|
168
168
|
type TracingMode = "batched" | "streaming";
|
|
169
169
|
type TracingConfig = {
|
|
170
170
|
enabled: boolean;
|
|
171
|
-
logData?: boolean;
|
|
172
|
-
/** Tracing mode:
|
|
173
|
-
* - "batched" (default): Events are collected and sent together when session ends
|
|
174
|
-
* - "streaming": Session starts immediately, events are sent in real-time as they occur
|
|
175
|
-
*/
|
|
176
171
|
mode?: TracingMode;
|
|
172
|
+
logData?: boolean;
|
|
177
173
|
sink?: TraceSinkConfig;
|
|
178
174
|
};
|
|
179
|
-
/** @deprecated Use TracingConfig instead */
|
|
180
175
|
type SmartAgentTracingConfig = TracingConfig;
|
|
181
176
|
type AgentOptions = {
|
|
182
177
|
name?: string;
|
|
183
178
|
version?: string;
|
|
184
|
-
model:
|
|
179
|
+
model: any;
|
|
185
180
|
tools?: Array<ToolInterface<any, any, any>>;
|
|
186
181
|
guardrails?: ConversationGuardrail[];
|
|
187
182
|
handoffs?: HandoffDescriptor[];
|
|
@@ -193,7 +188,7 @@ type AgentOptions = {
|
|
|
193
188
|
type SmartAgentOptions = {
|
|
194
189
|
name?: string;
|
|
195
190
|
version?: string;
|
|
196
|
-
model:
|
|
191
|
+
model: any;
|
|
197
192
|
tools?: Array<ToolInterface<any, any, any>>;
|
|
198
193
|
guardrails?: ConversationGuardrail[];
|
|
199
194
|
handoffs?: HandoffDescriptor[];
|
|
@@ -215,7 +210,7 @@ type SmartAgentOptions = {
|
|
|
215
210
|
type AgentRuntimeConfig = {
|
|
216
211
|
name?: string;
|
|
217
212
|
version?: string;
|
|
218
|
-
model:
|
|
213
|
+
model: any;
|
|
219
214
|
tools: Array<ToolInterface<any, any, any>>;
|
|
220
215
|
guardrails?: ConversationGuardrail[];
|
|
221
216
|
systemPrompt?: string;
|
|
@@ -393,9 +388,7 @@ type TraceSessionRuntime = {
|
|
|
393
388
|
errors: TraceErrorRecord[];
|
|
394
389
|
fileBaseDir?: string;
|
|
395
390
|
fileSessionDir?: string;
|
|
396
|
-
/** For streaming mode: whether session start has been sent to sink */
|
|
397
391
|
sessionStarted?: boolean;
|
|
398
|
-
/** Agent info for streaming mode session start */
|
|
399
392
|
agentInfo?: {
|
|
400
393
|
name?: string;
|
|
401
394
|
version?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -75,15 +75,16 @@ interface ToolInterface<TInput = any, TOutput = any, TCallOptions = any> {
|
|
|
75
75
|
approvalDefaults?: any;
|
|
76
76
|
[key: string]: any;
|
|
77
77
|
}
|
|
78
|
-
type RunnableConfig =
|
|
78
|
+
type RunnableConfig = {
|
|
79
|
+
[key: string]: any;
|
|
80
|
+
};
|
|
79
81
|
type BaseMessage = {
|
|
80
82
|
role: string;
|
|
81
83
|
name?: string;
|
|
82
84
|
content: string | ContentPart[];
|
|
83
85
|
tool_calls?: any;
|
|
84
86
|
tool_call_id?: string;
|
|
85
|
-
|
|
86
|
-
additional_kwargs?: Record<string, any>;
|
|
87
|
+
[key: string]: any;
|
|
87
88
|
};
|
|
88
89
|
type AIMessage = BaseMessage & {
|
|
89
90
|
role: 'assistant';
|
|
@@ -143,7 +144,6 @@ type AgentLimits = {
|
|
|
143
144
|
maxToolCalls?: number;
|
|
144
145
|
maxParallelTools?: number;
|
|
145
146
|
};
|
|
146
|
-
/** @deprecated Use AgentLimits instead */
|
|
147
147
|
type SmartAgentLimits = AgentLimits;
|
|
148
148
|
type TraceSinkFileConfig = {
|
|
149
149
|
type: "file";
|
|
@@ -168,20 +168,15 @@ type TraceSinkConfig = TraceSinkFileConfig | TraceSinkCustomConfig | TraceSinkCo
|
|
|
168
168
|
type TracingMode = "batched" | "streaming";
|
|
169
169
|
type TracingConfig = {
|
|
170
170
|
enabled: boolean;
|
|
171
|
-
logData?: boolean;
|
|
172
|
-
/** Tracing mode:
|
|
173
|
-
* - "batched" (default): Events are collected and sent together when session ends
|
|
174
|
-
* - "streaming": Session starts immediately, events are sent in real-time as they occur
|
|
175
|
-
*/
|
|
176
171
|
mode?: TracingMode;
|
|
172
|
+
logData?: boolean;
|
|
177
173
|
sink?: TraceSinkConfig;
|
|
178
174
|
};
|
|
179
|
-
/** @deprecated Use TracingConfig instead */
|
|
180
175
|
type SmartAgentTracingConfig = TracingConfig;
|
|
181
176
|
type AgentOptions = {
|
|
182
177
|
name?: string;
|
|
183
178
|
version?: string;
|
|
184
|
-
model:
|
|
179
|
+
model: any;
|
|
185
180
|
tools?: Array<ToolInterface<any, any, any>>;
|
|
186
181
|
guardrails?: ConversationGuardrail[];
|
|
187
182
|
handoffs?: HandoffDescriptor[];
|
|
@@ -193,7 +188,7 @@ type AgentOptions = {
|
|
|
193
188
|
type SmartAgentOptions = {
|
|
194
189
|
name?: string;
|
|
195
190
|
version?: string;
|
|
196
|
-
model:
|
|
191
|
+
model: any;
|
|
197
192
|
tools?: Array<ToolInterface<any, any, any>>;
|
|
198
193
|
guardrails?: ConversationGuardrail[];
|
|
199
194
|
handoffs?: HandoffDescriptor[];
|
|
@@ -215,7 +210,7 @@ type SmartAgentOptions = {
|
|
|
215
210
|
type AgentRuntimeConfig = {
|
|
216
211
|
name?: string;
|
|
217
212
|
version?: string;
|
|
218
|
-
model:
|
|
213
|
+
model: any;
|
|
219
214
|
tools: Array<ToolInterface<any, any, any>>;
|
|
220
215
|
guardrails?: ConversationGuardrail[];
|
|
221
216
|
systemPrompt?: string;
|
|
@@ -393,9 +388,7 @@ type TraceSessionRuntime = {
|
|
|
393
388
|
errors: TraceErrorRecord[];
|
|
394
389
|
fileBaseDir?: string;
|
|
395
390
|
fileSessionDir?: string;
|
|
396
|
-
/** For streaming mode: whether session start has been sent to sink */
|
|
397
391
|
sessionStarted?: boolean;
|
|
398
|
-
/** Agent info for streaming mode session start */
|
|
399
392
|
agentInfo?: {
|
|
400
393
|
name?: string;
|
|
401
394
|
version?: string;
|
package/dist/index.mjs
CHANGED
|
@@ -638,7 +638,7 @@ async function postStreamingSessionStart(baseUrl, headers, payload) {
|
|
|
638
638
|
if (!fetchFn) {
|
|
639
639
|
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
640
640
|
}
|
|
641
|
-
const url = `${baseUrl.replace(/\/$/, "")}/${payload.sessionId}/start`;
|
|
641
|
+
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/start`;
|
|
642
642
|
const finalHeaders = { ...headers || {} };
|
|
643
643
|
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
644
644
|
finalHeaders["content-type"] = "application/json";
|
|
@@ -672,7 +672,7 @@ async function postStreamingEvent(baseUrl, headers, sessionId, event) {
|
|
|
672
672
|
if (!fetchFn) {
|
|
673
673
|
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
674
674
|
}
|
|
675
|
-
const url = `${baseUrl.replace(/\/$/, "")}/${sessionId}/events`;
|
|
675
|
+
const url = `${baseUrl.replace(/\/$/, "")}/stream/${sessionId}/events`;
|
|
676
676
|
const finalHeaders = { ...headers || {} };
|
|
677
677
|
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
678
678
|
finalHeaders["content-type"] = "application/json";
|
|
@@ -706,7 +706,7 @@ async function postStreamingSessionEnd(baseUrl, headers, payload) {
|
|
|
706
706
|
if (!fetchFn) {
|
|
707
707
|
throw new Error("HTTP sink requires fetch to be available in this runtime.");
|
|
708
708
|
}
|
|
709
|
-
const url = `${baseUrl.replace(/\/$/, "")}/${payload.sessionId}/end`;
|
|
709
|
+
const url = `${baseUrl.replace(/\/$/, "")}/stream/${payload.sessionId}/end`;
|
|
710
710
|
const finalHeaders = { ...headers || {} };
|
|
711
711
|
if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
|
|
712
712
|
finalHeaders["content-type"] = "application/json";
|
|
@@ -1271,18 +1271,7 @@ function createAgentCoreNode(opts) {
|
|
|
1271
1271
|
outputSchema: opts.outputSchema,
|
|
1272
1272
|
tracing: opts.tracing
|
|
1273
1273
|
};
|
|
1274
|
-
const
|
|
1275
|
-
const seenNames = /* @__PURE__ */ new Map();
|
|
1276
|
-
const tools = [];
|
|
1277
|
-
for (const t of rawTools) {
|
|
1278
|
-
const tName = t.name ?? t.schema?.title;
|
|
1279
|
-
if (tName && seenNames.has(tName)) {
|
|
1280
|
-
tools[seenNames.get(tName)] = t;
|
|
1281
|
-
} else {
|
|
1282
|
-
if (tName) seenNames.set(tName, tools.length);
|
|
1283
|
-
tools.push(t);
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1274
|
+
const tools = runtime.tools ?? [];
|
|
1286
1275
|
const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(tools) : runtime.model;
|
|
1287
1276
|
const traceSession = state.ctx?.__traceSession;
|
|
1288
1277
|
const actorName = runtime.name ?? opts.name ?? "agent";
|
|
@@ -1335,6 +1324,26 @@ function createAgentCoreNode(opts) {
|
|
|
1335
1324
|
}
|
|
1336
1325
|
return filteredMsgs;
|
|
1337
1326
|
};
|
|
1327
|
+
const debugToolPairing = (messagesToSend) => {
|
|
1328
|
+
try {
|
|
1329
|
+
const msgs = Array.isArray(messagesToSend) ? messagesToSend : [];
|
|
1330
|
+
const toolUseIds = [];
|
|
1331
|
+
const missingResults = [];
|
|
1332
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
1333
|
+
const m = msgs[i];
|
|
1334
|
+
if (m?.role === "assistant") {
|
|
1335
|
+
for (const tu of extractToolUses(m)) {
|
|
1336
|
+
toolUseIds.push(tu.id);
|
|
1337
|
+
const next = msgs[i + 1];
|
|
1338
|
+
if (!(next && next.role === "tool" && (next.tool_call_id === tu.id || next.tool_call_id === m?.tool_call_id))) {
|
|
1339
|
+
missingResults.push({ id: tu.id, atIndex: i, tool: tu.name });
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
} catch (e) {
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1338
1347
|
const onEvent = state.ctx?.__onEvent;
|
|
1339
1348
|
const onStream = state.ctx?.__onStream;
|
|
1340
1349
|
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
@@ -1353,130 +1362,12 @@ function createAgentCoreNode(opts) {
|
|
|
1353
1362
|
};
|
|
1354
1363
|
let response;
|
|
1355
1364
|
try {
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
const usedIds = /* @__PURE__ */ new Set();
|
|
1359
|
-
let counter = 0;
|
|
1360
|
-
for (let i = 0; i < msgs.length; i++) {
|
|
1361
|
-
const m = msgs[i];
|
|
1362
|
-
if (m?.role !== "assistant") continue;
|
|
1363
|
-
const hasToolCalls = Array.isArray(m.tool_calls) && m.tool_calls.length > 0;
|
|
1364
|
-
const contentArr = Array.isArray(m.content) ? m.content : [];
|
|
1365
|
-
const hasContentToolUse = contentArr.some((c) => c?.type === "tool_use" && c?.id);
|
|
1366
|
-
const hasAdditionalToolCalls = Array.isArray(m.additional_kwargs?.tool_calls) && m.additional_kwargs.tool_calls.length > 0;
|
|
1367
|
-
if (!hasToolCalls && !hasContentToolUse && !hasAdditionalToolCalls) continue;
|
|
1368
|
-
if (hasToolCalls && hasContentToolUse) {
|
|
1369
|
-
const toolCallIds = new Set(
|
|
1370
|
-
m.tool_calls.filter((tc) => tc?.id).map((tc) => tc.id)
|
|
1371
|
-
);
|
|
1372
|
-
const filtered = contentArr.filter((c) => {
|
|
1373
|
-
if (c?.type === "tool_use" && c?.id && toolCallIds.has(c.id)) return false;
|
|
1374
|
-
return true;
|
|
1375
|
-
});
|
|
1376
|
-
if (filtered.length === 0) {
|
|
1377
|
-
m.content = "";
|
|
1378
|
-
} else if (filtered.length !== contentArr.length) {
|
|
1379
|
-
m.content = filtered.length === 1 && filtered[0]?.type === "text" ? filtered[0].text ?? "" : filtered;
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
if (hasAdditionalToolCalls && Array.isArray(m.content)) {
|
|
1383
|
-
const akIds = new Set(
|
|
1384
|
-
m.additional_kwargs.tool_calls.filter((tc) => tc?.id).map((tc) => tc.id)
|
|
1385
|
-
);
|
|
1386
|
-
const arr = m.content;
|
|
1387
|
-
const filtered = arr.filter((c) => {
|
|
1388
|
-
if (c?.type === "tool_use" && c?.id && akIds.has(c.id)) return false;
|
|
1389
|
-
return true;
|
|
1390
|
-
});
|
|
1391
|
-
if (filtered.length !== arr.length) {
|
|
1392
|
-
m.content = filtered.length === 0 ? "" : filtered.length === 1 && filtered[0]?.type === "text" ? filtered[0].text ?? "" : filtered;
|
|
1393
|
-
}
|
|
1394
|
-
}
|
|
1395
|
-
if (hasToolCalls) {
|
|
1396
|
-
m.tool_calls = m.tool_calls.map((tc) => ({ ...tc }));
|
|
1397
|
-
}
|
|
1398
|
-
if (hasAdditionalToolCalls) {
|
|
1399
|
-
m.additional_kwargs = { ...m.additional_kwargs };
|
|
1400
|
-
m.additional_kwargs.tool_calls = m.additional_kwargs.tool_calls.map((tc) => ({ ...tc }));
|
|
1401
|
-
}
|
|
1402
|
-
const remainingContentArr = Array.isArray(m.content) ? m.content : [];
|
|
1403
|
-
const hasRemainingContentToolUse = remainingContentArr.some((c) => c?.type === "tool_use" && c?.id);
|
|
1404
|
-
if (hasRemainingContentToolUse) {
|
|
1405
|
-
m.content = remainingContentArr.map(
|
|
1406
|
-
(c) => c && typeof c === "object" ? { ...c } : c
|
|
1407
|
-
);
|
|
1408
|
-
}
|
|
1409
|
-
const idsInMessage = /* @__PURE__ */ new Set();
|
|
1410
|
-
if (hasToolCalls) {
|
|
1411
|
-
for (const tc of m.tool_calls) {
|
|
1412
|
-
if (tc?.id) idsInMessage.add(tc.id);
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
if (hasRemainingContentToolUse) {
|
|
1416
|
-
for (const c of m.content) {
|
|
1417
|
-
if (c?.type === "tool_use" && c?.id) idsInMessage.add(c.id);
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
if (hasAdditionalToolCalls) {
|
|
1421
|
-
for (const tc of m.additional_kwargs.tool_calls) {
|
|
1422
|
-
if (tc?.id) idsInMessage.add(tc.id);
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
for (const id of idsInMessage) {
|
|
1426
|
-
if (!usedIds.has(id)) {
|
|
1427
|
-
usedIds.add(id);
|
|
1428
|
-
continue;
|
|
1429
|
-
}
|
|
1430
|
-
const newId = `${id}_${Date.now()}_${counter++}`;
|
|
1431
|
-
if (hasToolCalls) {
|
|
1432
|
-
for (const tc of m.tool_calls) {
|
|
1433
|
-
if (tc.id === id) tc.id = newId;
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
if (hasRemainingContentToolUse && Array.isArray(m.content)) {
|
|
1437
|
-
for (const c of m.content) {
|
|
1438
|
-
if (c?.type === "tool_use" && c.id === id) c.id = newId;
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
if (hasAdditionalToolCalls) {
|
|
1442
|
-
for (const tc of m.additional_kwargs.tool_calls) {
|
|
1443
|
-
if (tc.id === id) tc.id = newId;
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
for (let j = i + 1; j < msgs.length; j++) {
|
|
1447
|
-
const next = msgs[j];
|
|
1448
|
-
if (next?.role === "assistant") break;
|
|
1449
|
-
if (next?.role === "tool" && next.tool_call_id === id) {
|
|
1450
|
-
next.tool_call_id = newId;
|
|
1451
|
-
}
|
|
1452
|
-
if (Array.isArray(next?.content)) {
|
|
1453
|
-
let contentCloned = false;
|
|
1454
|
-
for (let k = 0; k < next.content.length; k++) {
|
|
1455
|
-
const block = next.content[k];
|
|
1456
|
-
if (block?.type === "tool_result" && block.tool_use_id === id) {
|
|
1457
|
-
if (!contentCloned) {
|
|
1458
|
-
next.content = next.content.map((x) => x && typeof x === "object" ? { ...x } : x);
|
|
1459
|
-
contentCloned = true;
|
|
1460
|
-
}
|
|
1461
|
-
next.content[k].tool_use_id = newId;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
usedIds.add(newId);
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
return msgs;
|
|
1470
|
-
};
|
|
1471
|
-
const normalizedMessages = ensureUniqueToolCallIds(
|
|
1472
|
-
normalizeBedrockToolPairing([...state.messages])
|
|
1473
|
-
);
|
|
1365
|
+
const normalizedMessages = normalizeBedrockToolPairing([...state.messages]);
|
|
1366
|
+
debugToolPairing(normalizedMessages);
|
|
1474
1367
|
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
1475
1368
|
let streamedText = "";
|
|
1476
1369
|
let streamedMessage;
|
|
1477
|
-
const
|
|
1478
|
-
const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
|
|
1479
|
-
for await (const chunk of stream) {
|
|
1370
|
+
for await (const chunk of modelWithTools.stream(normalizedMessages, { signal: abortSignal, cancellationToken })) {
|
|
1480
1371
|
if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
|
|
1481
1372
|
break;
|
|
1482
1373
|
}
|
|
@@ -1521,7 +1412,7 @@ function createAgentCoreNode(opts) {
|
|
|
1521
1412
|
...state.messages,
|
|
1522
1413
|
response
|
|
1523
1414
|
];
|
|
1524
|
-
const rawUsage = response?.
|
|
1415
|
+
const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
1525
1416
|
const normalized = normalizeUsage(rawUsage);
|
|
1526
1417
|
const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
|
|
1527
1418
|
const durationMs = Date.now() - start;
|
|
@@ -2517,6 +2408,7 @@ function createAgent(opts) {
|
|
|
2517
2408
|
};
|
|
2518
2409
|
let res;
|
|
2519
2410
|
try {
|
|
2411
|
+
await startStreamingSession(traceSession, runtimeWithInvokeLimits);
|
|
2520
2412
|
res = await runLoop(initial, config, emit);
|
|
2521
2413
|
} catch (err) {
|
|
2522
2414
|
await finalizeTraceSession(traceSession, {
|
|
@@ -2726,83 +2618,6 @@ function createAgentNode(opts) {
|
|
|
2726
2618
|
};
|
|
2727
2619
|
}
|
|
2728
2620
|
|
|
2729
|
-
// src/utils/traceSections.ts
|
|
2730
|
-
function formatMessageContent(content) {
|
|
2731
|
-
if (content == null) return "";
|
|
2732
|
-
if (typeof content === "string") return content;
|
|
2733
|
-
if (Array.isArray(content)) {
|
|
2734
|
-
return content.map((item) => {
|
|
2735
|
-
if (typeof item === "string") return item;
|
|
2736
|
-
if (item && typeof item === "object") {
|
|
2737
|
-
if (typeof item.text === "string") return item.text;
|
|
2738
|
-
if (typeof item.content === "string") return item.content;
|
|
2739
|
-
try {
|
|
2740
|
-
return JSON.stringify(item);
|
|
2741
|
-
} catch {
|
|
2742
|
-
return String(item);
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
2745
|
-
try {
|
|
2746
|
-
return JSON.stringify(item);
|
|
2747
|
-
} catch {
|
|
2748
|
-
return String(item);
|
|
2749
|
-
}
|
|
2750
|
-
}).filter(Boolean).join("\n");
|
|
2751
|
-
}
|
|
2752
|
-
if (typeof content === "object") {
|
|
2753
|
-
if (typeof content.text === "string") return content.text;
|
|
2754
|
-
if (typeof content.content === "string") return content.content;
|
|
2755
|
-
try {
|
|
2756
|
-
return JSON.stringify(content, null, 2);
|
|
2757
|
-
} catch {
|
|
2758
|
-
return String(content);
|
|
2759
|
-
}
|
|
2760
|
-
}
|
|
2761
|
-
return String(content);
|
|
2762
|
-
}
|
|
2763
|
-
function buildSummarizationSections(opts) {
|
|
2764
|
-
const sections = [];
|
|
2765
|
-
sections.push({
|
|
2766
|
-
kind: "summary",
|
|
2767
|
-
label: "Context Summary",
|
|
2768
|
-
content: opts.summaryText
|
|
2769
|
-
});
|
|
2770
|
-
const tokensSaved = opts.tokenCountBefore - opts.tokenCountAfter;
|
|
2771
|
-
const reductionPct = opts.tokenCountBefore > 0 ? Math.round(tokensSaved / opts.tokenCountBefore * 100) : 0;
|
|
2772
|
-
const metaData = {
|
|
2773
|
-
messagesCompressed: opts.messagesCompressed,
|
|
2774
|
-
tokenCountBefore: opts.tokenCountBefore,
|
|
2775
|
-
tokenCountAfter: opts.tokenCountAfter,
|
|
2776
|
-
tokensSaved,
|
|
2777
|
-
reductionPercent: reductionPct
|
|
2778
|
-
};
|
|
2779
|
-
if (opts.inputTokens !== void 0) metaData.inputTokens = opts.inputTokens;
|
|
2780
|
-
if (opts.outputTokens !== void 0) metaData.outputTokens = opts.outputTokens;
|
|
2781
|
-
if (opts.cachedInputTokens !== void 0) metaData.cachedInputTokens = opts.cachedInputTokens;
|
|
2782
|
-
if (opts.durationMs !== void 0) metaData.durationMs = opts.durationMs;
|
|
2783
|
-
if (opts.previousSummary) metaData.previousSummaryLength = opts.previousSummary.length;
|
|
2784
|
-
sections.push({
|
|
2785
|
-
kind: "metadata",
|
|
2786
|
-
label: "Summarization Stats",
|
|
2787
|
-
data: metaData
|
|
2788
|
-
});
|
|
2789
|
-
if (Array.isArray(opts.promptMessages) && opts.promptMessages.length > 0) {
|
|
2790
|
-
for (const msg of opts.promptMessages) {
|
|
2791
|
-
const role = typeof msg?.role === "string" ? msg.role : "system";
|
|
2792
|
-
const content = formatMessageContent(msg?.content ?? "");
|
|
2793
|
-
if (content) {
|
|
2794
|
-
sections.push({
|
|
2795
|
-
kind: "message",
|
|
2796
|
-
label: `Summarization Prompt (${role})`,
|
|
2797
|
-
role,
|
|
2798
|
-
content
|
|
2799
|
-
});
|
|
2800
|
-
}
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
return sections;
|
|
2804
|
-
}
|
|
2805
|
-
|
|
2806
2621
|
// src/nodes/contextSummarize.ts
|
|
2807
2622
|
var systemMessage = (content) => ({ role: "system", content });
|
|
2808
2623
|
var humanMessage = (content) => ({ role: "user", content });
|
|
@@ -2861,7 +2676,8 @@ function createContextSummarizeNode(opts) {
|
|
|
2861
2676
|
if (compressableMessages.length === 0) {
|
|
2862
2677
|
return {};
|
|
2863
2678
|
}
|
|
2864
|
-
const
|
|
2679
|
+
const allTextBefore = messages.map((m) => typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("") : "").join("\n");
|
|
2680
|
+
const tokenCountBefore = countApproxTokens(allTextBefore);
|
|
2865
2681
|
const summaryPromptMaxTokens = config.summaryPromptMaxTokens;
|
|
2866
2682
|
const availableTokensForConversation = summaryPromptMaxTokens - 500;
|
|
2867
2683
|
const messageTexts = [];
|
|
@@ -2924,7 +2740,7 @@ Summary:`;
|
|
|
2924
2740
|
durationMs = Date.now() - startTime;
|
|
2925
2741
|
summaryText = typeof response.content === "string" ? response.content : Array.isArray(response.content) ? response.content.map((c) => c.text || "").join("") : JSON.stringify(response.content);
|
|
2926
2742
|
outputTokensEstimate = countApproxTokens(summaryText);
|
|
2927
|
-
const rawUsage = response?.
|
|
2743
|
+
const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.tokenUsage || response?.response_metadata?.usage;
|
|
2928
2744
|
const normalized = normalizeUsage(rawUsage);
|
|
2929
2745
|
if (normalized) {
|
|
2930
2746
|
inputTokensActual = normalized.prompt_tokens;
|
|
@@ -2956,16 +2772,7 @@ Summary:`;
|
|
|
2956
2772
|
inputTokens: inputTokensEstimate,
|
|
2957
2773
|
outputTokens: 0,
|
|
2958
2774
|
error: { message: err?.message || String(err), stack: err?.stack },
|
|
2959
|
-
|
|
2960
|
-
summaryText: "",
|
|
2961
|
-
messagesCompressed: 0,
|
|
2962
|
-
tokenCountBefore,
|
|
2963
|
-
tokenCountAfter: tokenCountBefore,
|
|
2964
|
-
inputTokens: inputTokensEstimate,
|
|
2965
|
-
outputTokens: 0,
|
|
2966
|
-
durationMs,
|
|
2967
|
-
promptMessages: summaryPrompt
|
|
2968
|
-
})
|
|
2775
|
+
messageList: sanitizeTracePayload(summaryPrompt)
|
|
2969
2776
|
});
|
|
2970
2777
|
return {};
|
|
2971
2778
|
}
|
|
@@ -3019,7 +2826,8 @@ Summary:`;
|
|
|
3019
2826
|
};
|
|
3020
2827
|
const summaries = Array.isArray(state.summaries) ? [...state.summaries, summaryText] : [summaryText];
|
|
3021
2828
|
const finalMessages = [...validatedMessages, assistantSummaryCall, toolSummaryResponse];
|
|
3022
|
-
const
|
|
2829
|
+
const allTextAfter = finalMessages.map((m) => typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("") : "").join("\n");
|
|
2830
|
+
const tokenCountAfter = countApproxTokens(allTextAfter);
|
|
3023
2831
|
const summarizationEvent = {
|
|
3024
2832
|
type: "summarization",
|
|
3025
2833
|
summary: summaryText,
|
|
@@ -3046,21 +2854,10 @@ Summary:`;
|
|
|
3046
2854
|
outputTokens: outputTokensActual ?? outputTokensEstimate,
|
|
3047
2855
|
cachedInputTokens,
|
|
3048
2856
|
totalTokens: totalTokensActual,
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
tokenCountBefore,
|
|
3054
|
-
tokenCountAfter,
|
|
3055
|
-
inputTokens: inputTokensActual ?? inputTokensEstimate,
|
|
3056
|
-
outputTokens: outputTokensActual ?? outputTokensEstimate,
|
|
3057
|
-
cachedInputTokens,
|
|
3058
|
-
durationMs,
|
|
3059
|
-
promptMessages: sanitizeTracePayload([
|
|
3060
|
-
...summaryPrompt,
|
|
3061
|
-
{ role: "assistant", content: summaryText, name: "summarization_result" }
|
|
3062
|
-
])
|
|
3063
|
-
}),
|
|
2857
|
+
messageList: sanitizeTracePayload([
|
|
2858
|
+
...summaryPrompt,
|
|
2859
|
+
{ role: "assistant", content: summaryText, name: "summarization_result" }
|
|
2860
|
+
]),
|
|
3064
2861
|
debug: {
|
|
3065
2862
|
messagesCompressed: compressableMessages.length,
|
|
3066
2863
|
tokenCountBefore,
|
|
@@ -3184,8 +2981,30 @@ function needsSummarization(state, opts, summarizationEnabled) {
|
|
|
3184
2981
|
maxTok = 5e4;
|
|
3185
2982
|
}
|
|
3186
2983
|
try {
|
|
3187
|
-
const
|
|
3188
|
-
|
|
2984
|
+
const allText = (state.messages || []).map((m) => {
|
|
2985
|
+
if (typeof m.content === "string") return m.content;
|
|
2986
|
+
if (Array.isArray(m.content)) {
|
|
2987
|
+
return m.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? JSON.stringify(c)).join("");
|
|
2988
|
+
}
|
|
2989
|
+
if (m.content && typeof m.content === "object") {
|
|
2990
|
+
return JSON.stringify(m.content);
|
|
2991
|
+
}
|
|
2992
|
+
return "";
|
|
2993
|
+
}).join("\n");
|
|
2994
|
+
const tokenCount = countApproxTokens(allText);
|
|
2995
|
+
const needsSum = tokenCount > maxTok;
|
|
2996
|
+
if (process.env.DEBUG_SUMMARIZATION) {
|
|
2997
|
+
const msgCount = (state.messages || []).length;
|
|
2998
|
+
const toolMsgs = (state.messages || []).filter((m) => m.role === "tool");
|
|
2999
|
+
const toolDetails = toolMsgs.map((m, i) => {
|
|
3000
|
+
const contentStr = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
3001
|
+
return `[${i}] id:${m.tool_call_id?.slice(-8) || "none"} len:${contentStr.length} preview:"${contentStr.slice(0, 30)}..."`;
|
|
3002
|
+
});
|
|
3003
|
+
console.log(`[Summarization] Messages: ${msgCount}, Tool messages: ${toolMsgs.length}`);
|
|
3004
|
+
toolDetails.forEach((d) => console.log(` ${d}`));
|
|
3005
|
+
console.log(`[Summarization] Token count: ${tokenCount}, Max: ${maxTok}, Needs summarization: ${needsSum}`);
|
|
3006
|
+
}
|
|
3007
|
+
return needsSum;
|
|
3189
3008
|
} catch (e) {
|
|
3190
3009
|
return false;
|
|
3191
3010
|
}
|