@cognipeer/agent-sdk 0.5.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -14
- package/dist/index.cjs +92 -186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -20
- package/dist/index.d.ts +18 -20
- package/dist/index.mjs +92 -186
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,12 +137,8 @@ const agent = createSmartAgent({
|
|
|
137
137
|
summarization: { summaryTriggerTokens: 8000, summaryMode: "incremental" },
|
|
138
138
|
context: { policy: "hybrid", lastTurnsToKeep: 8 },
|
|
139
139
|
toolResponses: {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
defaultPolicy: "keep_structured",
|
|
143
|
-
largeResponsePolicy: "summarize_archive",
|
|
144
|
-
fallbackPolicy: "keep_full",
|
|
145
|
-
keepRecentFullCount: 2,
|
|
140
|
+
defaultPolicy: "summarize_archive",
|
|
141
|
+
toolResponseRetentionByTool: { read_skills: "keep_full" },
|
|
146
142
|
maxToolResponseChars: 4000,
|
|
147
143
|
maxToolResponseTokens: 1200,
|
|
148
144
|
},
|
|
@@ -158,15 +154,13 @@ const result = await agent.invoke({
|
|
|
158
154
|
console.log(result.content);
|
|
159
155
|
```
|
|
160
156
|
|
|
161
|
-
Tool-response retention is
|
|
157
|
+
Tool-response retention is lazy and summarizer-driven:
|
|
162
158
|
|
|
163
|
-
-
|
|
164
|
-
- `defaultPolicy`
|
|
165
|
-
- `
|
|
166
|
-
- `
|
|
167
|
-
- `
|
|
168
|
-
|
|
169
|
-
Resolution order is: per-tool override, then critical fallback, then large/small classification, then the default policy. Redundant payloads like `ok`, `true`, and `null` are dropped automatically.
|
|
159
|
+
- Tool outputs are stored at full fidelity in `state.toolHistory` and are never reduced at tool-call time.
|
|
160
|
+
- When the summarizer runs (context limits reached), old tool messages are rewritten in place according to `defaultPolicy` (default: `summarize_archive`). The full payload is still recoverable via `get_tool_response` using the execution id embedded in the placeholder.
|
|
161
|
+
- `toolResponseRetentionByTool` lets you opt specific tools out of reduction (e.g. `read_skills: "keep_full"`).
|
|
162
|
+
- `criticalTools` are never reduced. The built-in list covers `response`, `manage_todo_list`, and `get_tool_response`.
|
|
163
|
+
- `maxToolResponseChars` / `maxToolResponseTokens` only drive an eager hard-cap truncation when a single tool output is big enough to blow up the very next model call. The truncated head always points at `get_tool_response` for recovery.
|
|
170
164
|
|
|
171
165
|
The smart wrapper now supports runtime presets (`fast`, `balanced`, `deep`, `research`), custom profiles layered on top of a base preset, structured summarization, hybrid context compaction, configurable tool-response retention, in-memory fact storage, delegation limits, and an eval harness via `runSmartAgentEvalHarness(...)`.
|
|
172
166
|
|
package/dist/index.cjs
CHANGED
|
@@ -2136,18 +2136,13 @@ var BASE_DEFAULTS = {
|
|
|
2136
2136
|
requireJsonOutputContract: true
|
|
2137
2137
|
},
|
|
2138
2138
|
toolResponses: {
|
|
2139
|
-
maxToolResponseChars:
|
|
2140
|
-
maxToolResponseTokens:
|
|
2141
|
-
|
|
2142
|
-
smallResponsePolicy: "keep_full",
|
|
2143
|
-
defaultPolicy: "keep_structured",
|
|
2144
|
-
largeResponsePolicy: "summarize_archive",
|
|
2139
|
+
maxToolResponseChars: 12e3,
|
|
2140
|
+
maxToolResponseTokens: 3e3,
|
|
2141
|
+
defaultPolicy: "summarize_archive",
|
|
2145
2142
|
toolResponseRetentionByTool: {},
|
|
2146
2143
|
criticalTools: [...DEFAULT_CRITICAL_TOOLS],
|
|
2147
2144
|
schemaValidation: "strict",
|
|
2148
|
-
retryOnSchemaError: true
|
|
2149
|
-
fallbackPolicy: "keep_full",
|
|
2150
|
-
keepRecentFullCount: 0
|
|
2145
|
+
retryOnSchemaError: true
|
|
2151
2146
|
}
|
|
2152
2147
|
};
|
|
2153
2148
|
function buildProfile(overrides) {
|
|
@@ -2186,7 +2181,7 @@ var DEFAULT_PROFILE_CONFIGS = {
|
|
|
2186
2181
|
},
|
|
2187
2182
|
memory: { readPolicy: "recent_only" },
|
|
2188
2183
|
delegation: { mode: "off", maxDelegationDepth: 1, maxChildCalls: 2, maxParallelChild: 1, childContextPolicy: "minimal" },
|
|
2189
|
-
toolResponses: { maxToolResponseChars:
|
|
2184
|
+
toolResponses: { maxToolResponseChars: 8e3, maxToolResponseTokens: 2e3 }
|
|
2190
2185
|
}),
|
|
2191
2186
|
balanced: buildProfile({}),
|
|
2192
2187
|
deep: buildProfile({
|
|
@@ -2203,7 +2198,7 @@ var DEFAULT_PROFILE_CONFIGS = {
|
|
|
2203
2198
|
},
|
|
2204
2199
|
memory: { scope: "workspace" },
|
|
2205
2200
|
delegation: { maxDelegationDepth: 3, maxChildCalls: 6 },
|
|
2206
|
-
toolResponses: { maxToolResponseChars:
|
|
2201
|
+
toolResponses: { maxToolResponseChars: 16e3, maxToolResponseTokens: 4e3 }
|
|
2207
2202
|
}),
|
|
2208
2203
|
research: buildProfile({
|
|
2209
2204
|
limits: { maxToolCalls: 20, maxParallelTools: 4, maxContextTokens: 56e3 },
|
|
@@ -2219,7 +2214,7 @@ var DEFAULT_PROFILE_CONFIGS = {
|
|
|
2219
2214
|
},
|
|
2220
2215
|
memory: { scope: "workspace" },
|
|
2221
2216
|
delegation: { mode: "automatic", maxDelegationDepth: 4, maxChildCalls: 8, maxParallelChild: 3, childContextPolicy: "full" },
|
|
2222
|
-
toolResponses: { maxToolResponseChars:
|
|
2217
|
+
toolResponses: { maxToolResponseChars: 24e3, maxToolResponseTokens: 6e3 }
|
|
2223
2218
|
})
|
|
2224
2219
|
};
|
|
2225
2220
|
function mergeLimits(base, override) {
|
|
@@ -2426,63 +2421,65 @@ function summarizeObject(value) {
|
|
|
2426
2421
|
return safeStringify(value);
|
|
2427
2422
|
}
|
|
2428
2423
|
function classifyToolResponse(toolName, output, config) {
|
|
2429
|
-
const serialized = safeStringify(output);
|
|
2430
|
-
const tokenCount = countApproxTokens(serialized);
|
|
2431
2424
|
const criticalTools = new Set(config.toolResponses.criticalTools);
|
|
2432
2425
|
if (criticalTools.has(toolName)) return "critical";
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
}
|
|
2426
|
+
const serialized = safeStringify(output);
|
|
2427
|
+
const tokenCount = countApproxTokens(serialized);
|
|
2436
2428
|
if (tokenCount >= config.toolResponses.maxToolResponseTokens || serialized.length >= config.toolResponses.maxToolResponseChars) {
|
|
2437
2429
|
return "verbose";
|
|
2438
2430
|
}
|
|
2439
|
-
const smallChars = config.toolResponses.smallResponseChars;
|
|
2440
|
-
if (smallChars > 0 && serialized.length <= smallChars) {
|
|
2441
|
-
return "small";
|
|
2442
|
-
}
|
|
2443
2431
|
return "informative";
|
|
2444
2432
|
}
|
|
2445
|
-
function
|
|
2433
|
+
function applyToolResponseHardCap(toolName, output, executionId, config) {
|
|
2446
2434
|
const serialized = safeStringify(output);
|
|
2447
2435
|
const tokenCount = countApproxTokens(serialized);
|
|
2448
2436
|
const classification = classifyToolResponse(toolName, output, config);
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
if (byTool) ; else if (classification === "critical") {
|
|
2452
|
-
retentionPolicy = config.toolResponses.fallbackPolicy;
|
|
2453
|
-
} else if (classification === "verbose") {
|
|
2454
|
-
retentionPolicy = config.toolResponses.largeResponsePolicy;
|
|
2455
|
-
} else if (classification === "small") {
|
|
2456
|
-
retentionPolicy = config.toolResponses.smallResponsePolicy;
|
|
2457
|
-
} else if (classification === "redundant") {
|
|
2458
|
-
retentionPolicy = "drop";
|
|
2459
|
-
}
|
|
2460
|
-
const summary = summarizeObject(output);
|
|
2461
|
-
if (retentionPolicy === "keep_full") {
|
|
2462
|
-
return { classification, retentionPolicy, content: serialized, rawOutput: output, summary, tokenCount };
|
|
2463
|
-
}
|
|
2464
|
-
if (retentionPolicy === "keep_structured") {
|
|
2465
|
-
return { classification, retentionPolicy, content: summary, rawOutput: output, summary, tokenCount };
|
|
2466
|
-
}
|
|
2467
|
-
if (retentionPolicy === "summarize_archive") {
|
|
2468
|
-
return {
|
|
2469
|
-
classification,
|
|
2470
|
-
retentionPolicy,
|
|
2471
|
-
content: `ARCHIVED_TOOL_RESPONSE: ${summary}`,
|
|
2472
|
-
rawOutput: output,
|
|
2473
|
-
summary,
|
|
2474
|
-
tokenCount
|
|
2475
|
-
};
|
|
2437
|
+
if (classification !== "verbose") {
|
|
2438
|
+
return { classification, content: serialized, rawOutput: output, tokenCount, truncated: false };
|
|
2476
2439
|
}
|
|
2440
|
+
const cap = config.toolResponses.maxToolResponseChars;
|
|
2441
|
+
const head = serialized.slice(0, cap);
|
|
2442
|
+
const note = `
|
|
2443
|
+
... [TRUNCATED ${serialized.length - cap} chars by hard cap. Use get_tool_response with executionId="${executionId}" to fetch the full payload.]`;
|
|
2477
2444
|
return {
|
|
2478
2445
|
classification,
|
|
2479
|
-
|
|
2480
|
-
content: `DROPPED_TOOL_RESPONSE: ${summary}`,
|
|
2446
|
+
content: head + note,
|
|
2481
2447
|
rawOutput: output,
|
|
2482
|
-
|
|
2483
|
-
|
|
2448
|
+
tokenCount,
|
|
2449
|
+
truncated: true
|
|
2484
2450
|
};
|
|
2485
2451
|
}
|
|
2452
|
+
function resolveSummarizationRetention(toolName, config) {
|
|
2453
|
+
const criticalTools = new Set(config.toolResponses.criticalTools);
|
|
2454
|
+
if (criticalTools.has(toolName)) return "keep_full";
|
|
2455
|
+
const byTool = config.toolResponses.toolResponseRetentionByTool[toolName];
|
|
2456
|
+
return byTool || config.toolResponses.defaultPolicy;
|
|
2457
|
+
}
|
|
2458
|
+
function renderRetainedToolMessage(args) {
|
|
2459
|
+
const { policy, rawOutput, toolName, toolCallId, executionId, prebuiltSummary } = args;
|
|
2460
|
+
if (policy === "keep_full") {
|
|
2461
|
+
return typeof rawOutput === "string" ? rawOutput : safeStringify(rawOutput);
|
|
2462
|
+
}
|
|
2463
|
+
const summary = prebuiltSummary || summarizeObject(rawOutput);
|
|
2464
|
+
const refs = [
|
|
2465
|
+
`toolName=${toolName}`,
|
|
2466
|
+
toolCallId ? `toolCallId=${toolCallId}` : null,
|
|
2467
|
+
executionId ? `executionId=${executionId}` : null
|
|
2468
|
+
].filter(Boolean).join("; ");
|
|
2469
|
+
const refId = executionId || toolCallId || "";
|
|
2470
|
+
if (policy === "keep_structured") {
|
|
2471
|
+
return `STRUCTURED_TOOL_RESPONSE [${refs}]
|
|
2472
|
+
Preview: ${summary}
|
|
2473
|
+
Use get_tool_response with executionId "${refId}" to fetch the full payload when a specific field is needed.`;
|
|
2474
|
+
}
|
|
2475
|
+
if (policy === "summarize_archive") {
|
|
2476
|
+
return `ARCHIVED_TOOL_RESPONSE [${refs}]
|
|
2477
|
+
Summary: ${summary}
|
|
2478
|
+
Use get_tool_response with executionId "${refId}" to fetch the full payload.`;
|
|
2479
|
+
}
|
|
2480
|
+
return `DROPPED_TOOL_RESPONSE [${refs}]
|
|
2481
|
+
Use get_tool_response with executionId "${refId}" only if you must recover the original payload.`;
|
|
2482
|
+
}
|
|
2486
2483
|
function validateToolArgs(tool, args) {
|
|
2487
2484
|
const schema = tool.schema;
|
|
2488
2485
|
if (!schema || typeof schema.parse !== "function") {
|
|
@@ -2761,52 +2758,25 @@ function createToolsNode(initialTools, opts) {
|
|
|
2761
2758
|
state.ctx.__structuredOutputParsed = output.data;
|
|
2762
2759
|
state.ctx.__finalizedDueToStructuredOutput = true;
|
|
2763
2760
|
}
|
|
2764
|
-
const responsePolicy =
|
|
2761
|
+
const responsePolicy = applyToolResponseHardCap(toolName, output, executionId, resolved);
|
|
2765
2762
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2766
|
-
const storedOutput = responsePolicy.retentionPolicy === "keep_full" ? output : responsePolicy.summary;
|
|
2767
2763
|
toolHistory.push({
|
|
2768
2764
|
executionId,
|
|
2769
2765
|
toolName,
|
|
2770
2766
|
args,
|
|
2771
|
-
output
|
|
2767
|
+
output,
|
|
2772
2768
|
rawOutput: output,
|
|
2773
2769
|
timestamp,
|
|
2774
2770
|
tool_call_id: tc.id,
|
|
2775
|
-
summarized:
|
|
2771
|
+
summarized: false,
|
|
2776
2772
|
originalTokenCount: responsePolicy.tokenCount,
|
|
2777
2773
|
classification: responsePolicy.classification,
|
|
2778
|
-
retentionPolicy:
|
|
2779
|
-
summary:
|
|
2780
|
-
archiveId:
|
|
2774
|
+
retentionPolicy: "keep_full",
|
|
2775
|
+
summary: void 0,
|
|
2776
|
+
archiveId: void 0,
|
|
2781
2777
|
status: "success"
|
|
2782
2778
|
});
|
|
2783
|
-
|
|
2784
|
-
toolHistoryArchived.push({
|
|
2785
|
-
executionId,
|
|
2786
|
-
toolName,
|
|
2787
|
-
args,
|
|
2788
|
-
output,
|
|
2789
|
-
rawOutput: output,
|
|
2790
|
-
timestamp,
|
|
2791
|
-
tool_call_id: tc.id,
|
|
2792
|
-
summarized: true,
|
|
2793
|
-
originalTokenCount: responsePolicy.tokenCount,
|
|
2794
|
-
classification: responsePolicy.classification,
|
|
2795
|
-
retentionPolicy: responsePolicy.retentionPolicy,
|
|
2796
|
-
summary: responsePolicy.summary,
|
|
2797
|
-
archiveId: executionId,
|
|
2798
|
-
status: "success"
|
|
2799
|
-
});
|
|
2800
|
-
}
|
|
2801
|
-
let toolMessageContent = responsePolicy.content;
|
|
2802
|
-
if (responsePolicy.retentionPolicy === "summarize_archive") {
|
|
2803
|
-
toolMessageContent = `ARCHIVED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2804
|
-
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2805
|
-
} else if (responsePolicy.retentionPolicy === "drop") {
|
|
2806
|
-
toolMessageContent = `DROPPED_TOOL_RESPONSE [executionId=${executionId}]: ${responsePolicy.summary}
|
|
2807
|
-
Only use get_tool_response with executionId "${executionId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
2808
|
-
}
|
|
2809
|
-
appended.push({ role: "tool", content: toolMessageContent, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
2779
|
+
appended.push({ role: "tool", content: responsePolicy.content, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
|
|
2810
2780
|
onEvent?.({ type: "tool_call", phase: "success", name: toolName, id: tc.id, args, result: output, durationMs });
|
|
2811
2781
|
onProgress?.({ stage: "tools", message: `Tool ${tc.name} completed`, detail: { durationMs } });
|
|
2812
2782
|
if (needsApproval && approvalEntry) {
|
|
@@ -2850,8 +2820,9 @@ Only use get_tool_response with executionId "${executionId}" if this summary is
|
|
|
2850
2820
|
messageList,
|
|
2851
2821
|
debug: {
|
|
2852
2822
|
classification: responsePolicy.classification,
|
|
2853
|
-
retentionPolicy:
|
|
2854
|
-
originalTokenCount: responsePolicy.tokenCount
|
|
2823
|
+
retentionPolicy: "keep_full",
|
|
2824
|
+
originalTokenCount: responsePolicy.tokenCount,
|
|
2825
|
+
truncated: responsePolicy.truncated
|
|
2855
2826
|
}
|
|
2856
2827
|
});
|
|
2857
2828
|
toolCount += 1;
|
|
@@ -3990,40 +3961,6 @@ function createAgentNode(opts) {
|
|
|
3990
3961
|
}
|
|
3991
3962
|
|
|
3992
3963
|
// src/smart/contextPolicy.ts
|
|
3993
|
-
function collectRecentFullToolCallIds(state, keepRecentFullCount) {
|
|
3994
|
-
if (!keepRecentFullCount || keepRecentFullCount <= 0) return /* @__PURE__ */ new Set();
|
|
3995
|
-
const history = state.toolHistory || [];
|
|
3996
|
-
const ids = [];
|
|
3997
|
-
for (let index = history.length - 1; index >= 0 && ids.length < keepRecentFullCount; index -= 1) {
|
|
3998
|
-
const entry = history[index];
|
|
3999
|
-
if (!entry || !entry.tool_call_id) continue;
|
|
4000
|
-
if (entry.status && entry.status !== "success") continue;
|
|
4001
|
-
ids.push(entry.tool_call_id);
|
|
4002
|
-
}
|
|
4003
|
-
return new Set(ids);
|
|
4004
|
-
}
|
|
4005
|
-
function applyRecentFullOverride(messages, state, config) {
|
|
4006
|
-
const keepN = config.toolResponses.keepRecentFullCount;
|
|
4007
|
-
if (!keepN || keepN <= 0) return messages;
|
|
4008
|
-
const recentIds = collectRecentFullToolCallIds(state, keepN);
|
|
4009
|
-
if (recentIds.size === 0) return messages;
|
|
4010
|
-
const history = state.toolHistory || [];
|
|
4011
|
-
const byCallId = /* @__PURE__ */ new Map();
|
|
4012
|
-
for (const entry of history) {
|
|
4013
|
-
if (entry?.tool_call_id) byCallId.set(entry.tool_call_id, entry);
|
|
4014
|
-
}
|
|
4015
|
-
return messages.map((message) => {
|
|
4016
|
-
if (message.role !== "tool" || !message.tool_call_id) return message;
|
|
4017
|
-
if (!recentIds.has(message.tool_call_id)) return message;
|
|
4018
|
-
const entry = byCallId.get(message.tool_call_id);
|
|
4019
|
-
if (!entry) return message;
|
|
4020
|
-
const raw = entry.rawOutput ?? entry.output;
|
|
4021
|
-
if (raw === void 0) return message;
|
|
4022
|
-
const fullContent = typeof raw === "string" ? raw : safeStringify(raw);
|
|
4023
|
-
if (!fullContent || fullContent === message.content) return message;
|
|
4024
|
-
return { ...message, content: fullContent };
|
|
4025
|
-
});
|
|
4026
|
-
}
|
|
4027
3964
|
function collectRecentTurns(messages, lastTurnsToKeep) {
|
|
4028
3965
|
if (lastTurnsToKeep <= 0) return [];
|
|
4029
3966
|
const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
|
|
@@ -4124,7 +4061,7 @@ function clampToBudget(messages, maxContextTokens) {
|
|
|
4124
4061
|
function buildModelMessages(state, config) {
|
|
4125
4062
|
const rawMessages = state.messages || [];
|
|
4126
4063
|
if (config.context.policy === "raw") {
|
|
4127
|
-
return clampToBudget(
|
|
4064
|
+
return clampToBudget(rawMessages, config.limits.maxContextTokens);
|
|
4128
4065
|
}
|
|
4129
4066
|
const recentMessages = collectRecentTurns(rawMessages, config.context.lastTurnsToKeep);
|
|
4130
4067
|
const latestSummary = state.summaryRecords?.[state.summaryRecords.length - 1];
|
|
@@ -4144,7 +4081,7 @@ function buildModelMessages(state, config) {
|
|
|
4144
4081
|
...syntheticContextMessages,
|
|
4145
4082
|
...config.context.policy === "summary_only" ? body.filter((message) => message.role === "user" || message.role === "assistant").slice(-2) : body
|
|
4146
4083
|
];
|
|
4147
|
-
return clampToBudget(
|
|
4084
|
+
return clampToBudget(assembled, config.limits.maxContextTokens);
|
|
4148
4085
|
}
|
|
4149
4086
|
|
|
4150
4087
|
// src/nodes/contextSummarize.ts
|
|
@@ -4246,24 +4183,8 @@ function extractCanonicalFacts(messages) {
|
|
|
4246
4183
|
}
|
|
4247
4184
|
return [...facts.values()];
|
|
4248
4185
|
}
|
|
4249
|
-
function flattenToolMessageContent(message) {
|
|
4250
|
-
if (typeof message.content === "string") {
|
|
4251
|
-
return message.content;
|
|
4252
|
-
}
|
|
4253
|
-
if (Array.isArray(message.content)) {
|
|
4254
|
-
return message.content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? String(part ?? "")).join(" ");
|
|
4255
|
-
}
|
|
4256
|
-
return "";
|
|
4257
|
-
}
|
|
4258
4186
|
function isSummarizedToolPlaceholder(content) {
|
|
4259
|
-
return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE"));
|
|
4260
|
-
}
|
|
4261
|
-
function summarizeToolMessagePreview(message) {
|
|
4262
|
-
const preview = flattenToolMessageContent(message).trim();
|
|
4263
|
-
if (!preview) {
|
|
4264
|
-
return "No summary available.";
|
|
4265
|
-
}
|
|
4266
|
-
return preview.length > 240 ? `${preview.slice(0, 240)}...` : preview;
|
|
4187
|
+
return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
|
|
4267
4188
|
}
|
|
4268
4189
|
function findToolHistoryEntry(state, toolCallId, toolName) {
|
|
4269
4190
|
const entries = [
|
|
@@ -4289,29 +4210,6 @@ function findToolHistoryEntry(state, toolCallId, toolName) {
|
|
|
4289
4210
|
}
|
|
4290
4211
|
return void 0;
|
|
4291
4212
|
}
|
|
4292
|
-
function buildSummarizedToolMessage(message, state) {
|
|
4293
|
-
const toolName = message.name || "unknown_tool";
|
|
4294
|
-
const toolCallId = message.tool_call_id;
|
|
4295
|
-
const historyEntry = findToolHistoryEntry(state, toolCallId, toolName);
|
|
4296
|
-
const executionId = historyEntry?.executionId;
|
|
4297
|
-
const summary = historyEntry?.summary || summarizeToolMessagePreview(message);
|
|
4298
|
-
const references = [
|
|
4299
|
-
`toolName=${toolName}`,
|
|
4300
|
-
toolCallId ? `toolCallId=${toolCallId}` : null,
|
|
4301
|
-
executionId ? `executionId=${executionId}` : null
|
|
4302
|
-
].filter(Boolean).join("; ");
|
|
4303
|
-
let retrievalHint = "Only use get_tool_response if this summary is missing a specific field, id, snippet, or exact payload you still need.";
|
|
4304
|
-
if (executionId && toolCallId) {
|
|
4305
|
-
retrievalHint = `Only use get_tool_response with executionId "${executionId}" or tool call id "${toolCallId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
4306
|
-
} else if (executionId || toolCallId) {
|
|
4307
|
-
retrievalHint = `Only use get_tool_response with executionId "${executionId || toolCallId}" if this summary is missing a specific field, id, snippet, or exact payload you still need.`;
|
|
4308
|
-
}
|
|
4309
|
-
return [
|
|
4310
|
-
`SUMMARIZED_TOOL_RESPONSE [${references}]`,
|
|
4311
|
-
`Summary: ${summary}`,
|
|
4312
|
-
retrievalHint
|
|
4313
|
-
].join("\n");
|
|
4314
|
-
}
|
|
4315
4213
|
function mergeStableFacts(summary, additionalFacts) {
|
|
4316
4214
|
if (additionalFacts.length === 0) return summary;
|
|
4317
4215
|
const merged = new Map(summary.stable_facts.map((fact) => [fact.key, fact]));
|
|
@@ -4369,20 +4267,13 @@ function createContextSummarizeNode(opts) {
|
|
|
4369
4267
|
const messages = state.messages || [];
|
|
4370
4268
|
const onEvent = state.ctx?.__onEvent;
|
|
4371
4269
|
const traceSession = state.ctx?.__traceSession;
|
|
4372
|
-
const toolResponsesConfigEarly = resolved.toolResponses;
|
|
4373
|
-
const recentFullToolCallIdsEarly = collectRecentFullToolCallIds(state, toolResponsesConfigEarly.keepRecentFullCount);
|
|
4374
4270
|
const compressableMessages = messages.filter(
|
|
4375
4271
|
(m) => {
|
|
4376
4272
|
if (m.role !== "tool") return false;
|
|
4377
4273
|
if (isSummarizedToolPlaceholder(m.content)) return false;
|
|
4378
4274
|
if (isSyntheticSummaryMessage(m)) return false;
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
if (histEntry?.retentionPolicy === "keep_full") return false;
|
|
4382
|
-
if (!histEntry?.retentionPolicy) {
|
|
4383
|
-
const byTool = toolResponsesConfigEarly.toolResponseRetentionByTool?.[m.name || ""];
|
|
4384
|
-
if ((byTool || toolResponsesConfigEarly.defaultPolicy) === "keep_full") return false;
|
|
4385
|
-
}
|
|
4275
|
+
const policy = resolveSummarizationRetention(m.name || "", resolved);
|
|
4276
|
+
if (policy === "keep_full") return false;
|
|
4386
4277
|
return true;
|
|
4387
4278
|
}
|
|
4388
4279
|
);
|
|
@@ -4562,8 +4453,8 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4562
4453
|
break;
|
|
4563
4454
|
}
|
|
4564
4455
|
}
|
|
4565
|
-
const
|
|
4566
|
-
const
|
|
4456
|
+
const archivedExecutions = [...state.toolHistoryArchived || []];
|
|
4457
|
+
const archivedIds = new Set(archivedExecutions.map((entry) => entry?.executionId).filter(Boolean));
|
|
4567
4458
|
const newMessages = messages.map((m) => {
|
|
4568
4459
|
if (m.role === "tool") {
|
|
4569
4460
|
if (isSyntheticSummaryMessage(m)) {
|
|
@@ -4575,25 +4466,39 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4575
4466
|
}
|
|
4576
4467
|
if (isSummarizedToolPlaceholder(m.content)) return m;
|
|
4577
4468
|
if (toolCallId && protectedToolCallIds.has(toolCallId)) return m;
|
|
4578
|
-
if (toolCallId && recentFullToolCallIds.has(toolCallId)) return m;
|
|
4579
4469
|
const toolName = m.name || "";
|
|
4470
|
+
const policy = resolveSummarizationRetention(toolName, resolved);
|
|
4471
|
+
if (policy === "keep_full") return m;
|
|
4580
4472
|
const historyEntry = findToolHistoryEntry(state, toolCallId, toolName);
|
|
4581
|
-
const
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4473
|
+
const rawOutput = historyEntry?.rawOutput ?? historyEntry?.output ?? m.content;
|
|
4474
|
+
const executionId = historyEntry?.executionId;
|
|
4475
|
+
const prebuiltSummary = historyEntry?.summary || summarizeObject(rawOutput);
|
|
4476
|
+
if ((policy === "summarize_archive" || policy === "drop") && historyEntry && executionId && !archivedIds.has(executionId)) {
|
|
4477
|
+
archivedExecutions.push({
|
|
4478
|
+
...historyEntry,
|
|
4479
|
+
summarized: true,
|
|
4480
|
+
retentionPolicy: policy,
|
|
4481
|
+
archiveId: executionId,
|
|
4482
|
+
summary: prebuiltSummary
|
|
4483
|
+
});
|
|
4484
|
+
archivedIds.add(executionId);
|
|
4587
4485
|
}
|
|
4588
4486
|
return {
|
|
4589
4487
|
...m,
|
|
4590
|
-
content:
|
|
4488
|
+
content: renderRetainedToolMessage({
|
|
4489
|
+
policy,
|
|
4490
|
+
rawOutput,
|
|
4491
|
+
toolName,
|
|
4492
|
+
toolCallId,
|
|
4493
|
+
executionId,
|
|
4494
|
+
prebuiltSummary
|
|
4495
|
+
})
|
|
4591
4496
|
};
|
|
4592
4497
|
}
|
|
4593
4498
|
return m;
|
|
4594
4499
|
}).filter((m) => m !== null);
|
|
4595
4500
|
const actuallyCompressed = newMessages.filter(
|
|
4596
|
-
(m) => m.role === "tool" &&
|
|
4501
|
+
(m) => m.role === "tool" && isSummarizedToolPlaceholder(m.content) && !messages.some((orig) => orig.tool_call_id === m.tool_call_id && isSummarizedToolPlaceholder(orig.content))
|
|
4597
4502
|
);
|
|
4598
4503
|
if (actuallyCompressed.length === 0) {
|
|
4599
4504
|
return {};
|
|
@@ -4672,7 +4577,8 @@ ${canonicalFacts.length > 0 ? canonicalFacts.map((fact) => `- ${fact.key}: ${fac
|
|
|
4672
4577
|
return {
|
|
4673
4578
|
messages: finalMessages,
|
|
4674
4579
|
summaries,
|
|
4675
|
-
summaryRecords
|
|
4580
|
+
summaryRecords,
|
|
4581
|
+
toolHistoryArchived: archivedExecutions
|
|
4676
4582
|
};
|
|
4677
4583
|
};
|
|
4678
4584
|
}
|