@ai-agent-forge/agent-forge 0.86.2 → 0.86.4
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/CHANGELOG.md +38 -1
- package/dist/bundle/.build-manifest.json +183 -177
- package/dist/bundle/chunks/{anthropic-messages-RJYU4TCY.js → anthropic-messages-EVFQ6MLR.js} +3 -3
- package/dist/bundle/chunks/{azure-openai-responses-LESTCUL7.js → azure-openai-responses-WQCZWFAH.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-MDOTREMR.js → chunk-3WE3W52L.js} +2 -2
- package/dist/bundle/chunks/chunk-F6SBZUJG.js +141 -0
- package/dist/bundle/chunks/{chunk-SER2HCLE.js → chunk-PE3XUHPT.js} +3 -3
- package/dist/bundle/chunks/chunk-TBPTHASB.js +2 -0
- package/dist/bundle/chunks/chunk-ZV3W36HK.js +1445 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/google-generative-ai-LQ375GYC.js +2 -0
- package/dist/bundle/chunks/google-vertex-HXSRAKEZ.js +2 -0
- package/dist/bundle/chunks/jiti-static-loader-CDSTNEDU.js +2 -0
- package/dist/bundle/chunks/mistral-conversations-CSNMFR4J.js +5 -0
- package/dist/bundle/chunks/{openai-codex-responses-UFH6O5K6.js → openai-codex-responses-YDJSZOIH.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-A55GHA4O.js → openai-completions-UPRWTQPT.js} +3 -3
- package/dist/bundle/chunks/openai-responses-O63W6HQ3.js +2 -0
- package/dist/bundle/chunks/virtual-modules-O72ICTMQ.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +14 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +8 -2
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +4 -4
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +161 -45
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +1 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +13 -4
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +91 -93
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +15 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +20 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/template.css +10 -0
- package/dist/core/export-html/template.js +50 -17
- package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-compaction-policy.js +1 -2
- package/dist/core/extensions/bootstrap-compaction-policy.js.map +1 -1
- package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
- package/dist/core/extensions/capability-plugin.js +25 -30
- package/dist/core/extensions/capability-plugin.js.map +1 -1
- package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-static-loader.js +5 -0
- package/dist/core/extensions/jiti-static-loader.js.map +1 -0
- package/dist/core/extensions/microcompact.d.ts +16 -8
- package/dist/core/extensions/microcompact.d.ts.map +1 -1
- package/dist/core/extensions/microcompact.js +9 -7
- package/dist/core/extensions/microcompact.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts +3 -0
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/virtual-modules.js +32 -0
- package/dist/core/extensions/virtual-modules.js.map +1 -0
- package/dist/core/facade/coding-agent-facade.d.ts +3 -3
- package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-facade.js.map +1 -1
- package/dist/core/facade/coding-agent-runtime-facade.d.ts +2 -2
- package/dist/core/facade/coding-agent-runtime-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-runtime-facade.js +4 -4
- package/dist/core/facade/coding-agent-runtime-facade.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-install-host.d.ts +1 -1
- package/dist/core/package-install-host.d.ts.map +1 -1
- package/dist/core/package-install-host.js +4 -3
- package/dist/core/package-install-host.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +6 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +61 -35
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +6 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +23 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +146 -108
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +5 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +27 -13
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -7
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +8 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +40 -4
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +74 -50
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +18 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +35 -32
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +14 -6
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +47 -10
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +9 -10
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +10 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/remote/server-assembly.d.ts.map +1 -1
- package/dist/remote/server-assembly.js +1 -1
- package/dist/remote/server-assembly.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -12
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +88 -13
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/shell.d.ts +1 -3
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +3 -30
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/wsl.d.ts +3 -0
- package/dist/utils/wsl.d.ts.map +1 -0
- package/dist/utils/wsl.js +15 -0
- package/dist/utils/wsl.js.map +1 -0
- package/docs/rpc.md +7 -5
- package/docs/sdk.md +9 -8
- package/package.json +1 -1
- package/dist/bundle/chunks/chunk-JR3Q27QP.js +0 -1581
- package/dist/bundle/chunks/chunk-KQEGUM34.js +0 -2
- package/dist/bundle/chunks/google-generative-ai-NZ66X6K7.js +0 -2
- package/dist/bundle/chunks/google-vertex-2ZZOFBNQ.js +0 -2
- package/dist/bundle/chunks/mistral-conversations-B6DZRMEK.js +0 -5
- package/dist/bundle/chunks/openai-responses-TJLXRAXR.js +0 -2
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
* spies keep working unchanged. Method-to-method calls go through the session
|
|
8
8
|
* parameter (not direct function calls) to preserve that dispatch.
|
|
9
9
|
*/
|
|
10
|
+
import { SUMMARIZATION_SYSTEM_PROMPT } from "@agent-forge/agent-core";
|
|
10
11
|
import { contentText, retryAssistantCall, uuidv7 } from "@agent-forge/ai";
|
|
11
12
|
import { completeSimple, streamSimple } from "@agent-forge/ai/compat";
|
|
12
13
|
import { detachedSessionSnapshot, SessionCancelledError, } from "./agent-session-internal.js";
|
|
13
14
|
import { dispatchCompactionDecisionLifecycle, dispatchCompactionFailedLifecycle } from "./agent-session-lifecycle.js";
|
|
14
15
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
15
|
-
import { calculateContextTokens, collectEntriesForBranchSummary, estimateContextTokens, estimateTokens, isTurnStartMessage, } from "./compaction/index.js";
|
|
16
|
+
import { calculateContextTokens, collectEntriesForBranchSummary, effectiveKeepRecentTokens, estimateContextTokens, estimateTokens, isTurnStartMessage, } from "./compaction/index.js";
|
|
16
17
|
import { DEFAULT_COMPACTION_POLICY_NAME, SESSION_COMPACTION_COMMIT_EVENT_ID, SESSION_COMPACTION_COMMIT_EVENT_VERSION, } from "./extensions/index.js";
|
|
17
18
|
import { SUMMARY_MODEL_INVOCATION_ERROR_CODES } from "./extensions/public-api.js";
|
|
18
19
|
import { getLatestCompactionEntry } from "./session-manager.js";
|
|
@@ -48,11 +49,23 @@ const OVERFLOW_TRIM_STAGE2_TARGET_TOKENS = 10_000;
|
|
|
48
49
|
* 冷却把"阈值带上反复触发中部改写"的最坏情形封顶。
|
|
49
50
|
*/
|
|
50
51
|
const MICROCOMPACT_COOLDOWN_ASSISTANT_RESPONSES = 3;
|
|
51
|
-
/**
|
|
52
|
-
function
|
|
53
|
-
return
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
/** 摘要自批判评审轮 prompt(gemini-cli 同款思路,compaction.summarySelfCritique 开启时启用)。 */
|
|
53
|
+
function summarySelfCritiquePrompt(summary) {
|
|
54
|
+
return `Critically evaluate the summary in <summary> tags: it is the only context a continuation model will receive. Check for omissions that would break continuity - exact file paths, function/identifier names, error messages, user-stated constraints and preferences, decisions with rationale, and current task state. If something important is missing or wrong, output the corrected summary in the same format. If it is already complete, output it again verbatim. Output ONLY the summary.
|
|
55
|
+
|
|
56
|
+
<summary>
|
|
57
|
+
${summary}
|
|
58
|
+
</summary>`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 溢出/截断裁剪失败文案:实际发生过裁剪时附上前缀(分语:context overflow
|
|
62
|
+
* 维持既有精确文案,recoverable length 用截断响应措辞),0 次保持策略原文。
|
|
63
|
+
*/
|
|
64
|
+
function overflowTrimFailureMessage(attempts, failureMessage, kind) {
|
|
65
|
+
if (attempts <= 0)
|
|
66
|
+
return failureMessage;
|
|
67
|
+
const head = kind === "contextOverflow" ? "Context overflow" : "Truncated response";
|
|
68
|
+
return `${head} persists after compaction and ${attempts} trim attempts. ${failureMessage}`;
|
|
56
69
|
}
|
|
57
70
|
/**
|
|
58
71
|
* Trim the runtime projection for one overflow-recovery stage: drop the oldest
|
|
@@ -99,10 +112,10 @@ function trimOverflowProjection(messages, stage, keepRecentTokens) {
|
|
|
99
112
|
const floorStart = turnStarts[turnStarts.length - 1];
|
|
100
113
|
return floorStart === 0 ? messages : messages.slice(floorStart);
|
|
101
114
|
}
|
|
102
|
-
export async function getRequiredRequestAuth(session, model) {
|
|
115
|
+
export async function getRequiredRequestAuth(session, model, signal) {
|
|
103
116
|
let result;
|
|
104
117
|
try {
|
|
105
|
-
result = await session._modelRuntime.getAuth(model);
|
|
118
|
+
result = await session._modelRuntime.getAuth(model, { signal });
|
|
106
119
|
}
|
|
107
120
|
catch (error) {
|
|
108
121
|
const cause = error instanceof Error ? error.cause : undefined;
|
|
@@ -128,12 +141,12 @@ export async function getRequiredRequestAuth(session, model) {
|
|
|
128
141
|
}
|
|
129
142
|
throw new Error(formatNoApiKeyFoundMessage(model.provider));
|
|
130
143
|
}
|
|
131
|
-
export async function getSummarizationRequestAuth(session, model) {
|
|
144
|
+
export async function getSummarizationRequestAuth(session, model, signal) {
|
|
132
145
|
if (session.agent.streamFunction === streamSimple) {
|
|
133
|
-
return getRequiredRequestAuth(session, model);
|
|
146
|
+
return getRequiredRequestAuth(session, model, signal);
|
|
134
147
|
}
|
|
135
148
|
try {
|
|
136
|
-
const result = await session._modelRuntime.getAuth(model);
|
|
149
|
+
const result = await session._modelRuntime.getAuth(model, { signal });
|
|
137
150
|
if (!result)
|
|
138
151
|
return { model };
|
|
139
152
|
const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;
|
|
@@ -144,7 +157,12 @@ export async function getSummarizationRequestAuth(session, model) {
|
|
|
144
157
|
env: result.env,
|
|
145
158
|
};
|
|
146
159
|
}
|
|
147
|
-
catch {
|
|
160
|
+
catch (error) {
|
|
161
|
+
// Auth resolution normally falls back to an unauthenticated summary when
|
|
162
|
+
// it fails, but an abort must not be swallowed into that fallback: the
|
|
163
|
+
// caller's signal decided this run is over.
|
|
164
|
+
if (signal?.aborted)
|
|
165
|
+
throw error;
|
|
148
166
|
return { model };
|
|
149
167
|
}
|
|
150
168
|
}
|
|
@@ -266,6 +284,13 @@ export async function compactBeforeNextAssistantResponse(session, context, signa
|
|
|
266
284
|
if (!model || model.contextWindow <= 0) {
|
|
267
285
|
return context;
|
|
268
286
|
}
|
|
287
|
+
// Adaptive keepRecentTokens:小窗口把近期保护预算钳到可摘要窗口的一半
|
|
288
|
+
//(effectiveKeepRecentTokens,动机见其注释;大窗口原值不变),本路径与
|
|
289
|
+
// checkCompaction/compactInternal/runAutoCompactionInternal 一致使用 effective 值。
|
|
290
|
+
const effectiveSettings = {
|
|
291
|
+
...settings,
|
|
292
|
+
keepRecentTokens: effectiveKeepRecentTokens(settings.keepRecentTokens, model.contextWindow, settings.reserveTokens),
|
|
293
|
+
};
|
|
269
294
|
const contextTokens = estimateContextTokens(context.messages).tokens;
|
|
270
295
|
const decision = await decideCompaction(session, {
|
|
271
296
|
reason: "threshold",
|
|
@@ -277,7 +302,10 @@ export async function compactBeforeNextAssistantResponse(session, context, signa
|
|
|
277
302
|
reserveTokens: settings.reserveTokens,
|
|
278
303
|
},
|
|
279
304
|
canContinue: false,
|
|
280
|
-
//
|
|
305
|
+
// 便宜缓解的事实输入与门控,与 checkCompaction 的 threshold decide 相同
|
|
306
|
+
//(设置开关 ∧ 冷却归零):被任一条件挡住时策略不做便宜缓解,直接走全量压缩。
|
|
307
|
+
branchEntries: session.sessionManager.getBranch(),
|
|
308
|
+
keepRecentTokens: effectiveSettings.keepRecentTokens,
|
|
281
309
|
microcompactEnabled: settings.microcompactEnabled && session._microcompactCooldown === 0,
|
|
282
310
|
signal: signal ?? session._policyDecisionAbortController?.signal,
|
|
283
311
|
});
|
|
@@ -292,6 +320,27 @@ export async function compactBeforeNextAssistantResponse(session, context, signa
|
|
|
292
320
|
reserveTokens: settings.reserveTokens,
|
|
293
321
|
...(decision.failureMessage === undefined ? {} : { failureMessage: decision.failureMessage }),
|
|
294
322
|
});
|
|
323
|
+
// 策略便宜缓解(通用通道),镜像 checkCompaction 的 relief 落地分支:宿主原样
|
|
324
|
+
// 追加条目并重投影上下文,条目语义与投影归策略。执行上下文:本函数经默认
|
|
325
|
+
// prepareNextTurn loop link 在 agent 回合之间被 agent run await,不在
|
|
326
|
+
// _compactionQueue 内;手动压缩入口 compactInternal 先 _abortInternal() 等待
|
|
327
|
+
// 活跃回合结束,而本路径位于回合执行链上,回合结束前必先完成——relief 落地
|
|
328
|
+
// (同步 append + 投影)不会与手动压缩的摘要/提交交错,与 postAgentRun 的
|
|
329
|
+
// relief 落地同模式,不加队列锁。
|
|
330
|
+
if (decision.relief !== undefined && !decision.compact) {
|
|
331
|
+
session.sessionManager.appendCustomEntry(decision.relief.customType, decision.relief.data);
|
|
332
|
+
const sessionContext = session.sessionManager.buildSessionContext();
|
|
333
|
+
await session._applyContextTransition(sessionContext.messages, "compaction");
|
|
334
|
+
// 冷却起点:relief 已落地即开始计数(由 assistant message_end 递减)。
|
|
335
|
+
session._microcompactCooldown = MICROCOMPACT_COOLDOWN_ASSISTANT_RESPONSES;
|
|
336
|
+
session._hostLogger?.info("compaction", "policy relief applied", {
|
|
337
|
+
fields: { customType: decision.relief.customType, path: "pre-response" },
|
|
338
|
+
});
|
|
339
|
+
return {
|
|
340
|
+
...context,
|
|
341
|
+
messages: session.agent.state.messages.slice(),
|
|
342
|
+
};
|
|
343
|
+
}
|
|
295
344
|
if (!decision.compact)
|
|
296
345
|
return context;
|
|
297
346
|
await session._runAutoCompaction("threshold", false);
|
|
@@ -330,8 +379,39 @@ export async function runCompactionSummary(session, preparation, auth, customIns
|
|
|
330
379
|
context: { version: 1, sessionId: session.sessionId, phase: "compaction" },
|
|
331
380
|
execution,
|
|
332
381
|
});
|
|
382
|
+
let summary = result.summary;
|
|
383
|
+
let usage = result.usage;
|
|
384
|
+
// 摘要自批判评审轮(settings compaction.summarySelfCritique,默认关闭):
|
|
385
|
+
// 摘要是续接模型的全部上下文,漏一处路径/约束就断一环——多花一次小请求换
|
|
386
|
+
// 一遍"漏了什么"的自检(gemini-cli 两段式压缩的同款思路)。失败/中止/空文
|
|
387
|
+
// 本时保持第一轮摘要,评审轮不产生降级路径。
|
|
388
|
+
if (session.settingsManager.getCompactionSettings().summarySelfCritique && summary.trim() && !signal.aborted) {
|
|
389
|
+
const critique = await createSummaryModelInvocationV1(session, auth, summarizationRetryPolicy(session, execution.operationId, execution.inputRevision, signal), summarizationRetryCallbacks(session, { source: "compaction", reason }), { routingSessionId: session.sessionId }).invoke({
|
|
390
|
+
version: 1,
|
|
391
|
+
systemPrompt: SUMMARIZATION_SYSTEM_PROMPT,
|
|
392
|
+
prompt: summarySelfCritiquePrompt(summary),
|
|
393
|
+
maxTokens: 8192,
|
|
394
|
+
thinkingLevel: session.thinkingLevel === "off" ? "off" : "low",
|
|
395
|
+
}, signal);
|
|
396
|
+
if (critique.status === "completed" && critique.text && critique.text.trim()) {
|
|
397
|
+
summary = critique.text;
|
|
398
|
+
// 公共契约的 usage 是不透明透传;评审轮实际回传 provider Usage 形状,
|
|
399
|
+
// 这里按字段防御性收窄后并入压缩 usage。
|
|
400
|
+
const critiqueUsage = critique.usage;
|
|
401
|
+
if (usage && critiqueUsage) {
|
|
402
|
+
const add = (a, b) => a + (b ?? 0);
|
|
403
|
+
usage = {
|
|
404
|
+
...usage,
|
|
405
|
+
input: add(usage.input, critiqueUsage.input),
|
|
406
|
+
output: add(usage.output, critiqueUsage.output),
|
|
407
|
+
cacheRead: add(usage.cacheRead ?? 0, critiqueUsage.cacheRead),
|
|
408
|
+
cacheWrite: add(usage.cacheWrite ?? 0, critiqueUsage.cacheWrite),
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
333
413
|
// 包内收窄:invocation 结果按 provider 原样透传 usage;压缩 usage 合并需要内部 Usage 形状。
|
|
334
|
-
return { ...result,
|
|
414
|
+
return { ...result, summary, usage };
|
|
335
415
|
}
|
|
336
416
|
export async function decideCompaction(session, input) {
|
|
337
417
|
const runtime = session._capabilityRuntime;
|
|
@@ -534,9 +614,16 @@ export async function compactInternal(session, customInstructions) {
|
|
|
534
614
|
if (!session.model) {
|
|
535
615
|
throw new Error(formatNoModelSelectedMessage());
|
|
536
616
|
}
|
|
537
|
-
const auth = await getSummarizationRequestAuth(session, session.model);
|
|
617
|
+
const auth = await getSummarizationRequestAuth(session, session.model, session._compactionAbortController.signal);
|
|
538
618
|
const { pathEntries, expectedRevision, operationId } = captureCompactionCommitBoundary(session, "manual");
|
|
539
|
-
const
|
|
619
|
+
const rawSettings = session.settingsManager.getCompactionSettings();
|
|
620
|
+
// Adaptive keepRecentTokens(effectiveKeepRecentTokens,动机见其注释):手动
|
|
621
|
+
// 压缩与自动路径同一 effective 值,小窗口下 /compact 不再因保护预算吃满
|
|
622
|
+
// 整个可摘要窗口而报 "Nothing to compact"。
|
|
623
|
+
const settings = {
|
|
624
|
+
...rawSettings,
|
|
625
|
+
keepRecentTokens: effectiveKeepRecentTokens(rawSettings.keepRecentTokens, session.model.contextWindow, rawSettings.reserveTokens),
|
|
626
|
+
};
|
|
540
627
|
const execution = executionFacts(session, "compaction", operationId);
|
|
541
628
|
const preparation = await prepareCompaction(session, pathEntries, settings, execution, session._compactionAbortController.signal);
|
|
542
629
|
if (!preparation) {
|
|
@@ -649,6 +736,13 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
649
736
|
if (signal?.aborted)
|
|
650
737
|
return false;
|
|
651
738
|
const settings = session.settingsManager.getCompactionSettings();
|
|
739
|
+
// Adaptive keepRecentTokens(effectiveKeepRecentTokens,动机见其注释:座席实测
|
|
740
|
+
// 30K 窗口 20K 保护预算使可摘要前缀为零,阈值反复命中却无事可做)。一次性
|
|
741
|
+
// 替换后全文一致使用:下方 trim 阶梯 stage 0 目标与 threshold decide 请求。
|
|
742
|
+
const effectiveSettings = {
|
|
743
|
+
...settings,
|
|
744
|
+
keepRecentTokens: effectiveKeepRecentTokens(settings.keepRecentTokens, session.model?.contextWindow ?? 0, settings.reserveTokens),
|
|
745
|
+
};
|
|
652
746
|
// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
|
|
653
747
|
if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
|
|
654
748
|
return false;
|
|
@@ -692,11 +786,12 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
692
786
|
...(decision.failureMessage === undefined ? {} : { failureMessage: decision.failureMessage }),
|
|
693
787
|
});
|
|
694
788
|
if (!decision.compact) {
|
|
695
|
-
// 溢出裁剪兜底:压缩恢复(recoveryAttempted)后仍 context overflow
|
|
696
|
-
//
|
|
697
|
-
//
|
|
789
|
+
// 溢出裁剪兜底:压缩恢复(recoveryAttempted)后仍 context overflow 或
|
|
790
|
+
// recoverable length(截断响应=输出被掐,缩输入可让输出有空间,turn 边界
|
|
791
|
+
// 裁剪对两种溢出同样有效)时,先对运行时投影做逐级裁剪重试,3 级全失败才
|
|
792
|
+
// 走策略 failureMessage 失败路径。执行逻辑归 AgentSession,策略接口与事件面不变。
|
|
698
793
|
if (decision.failureMessage &&
|
|
699
|
-
contextOverflow &&
|
|
794
|
+
(contextOverflow || recoverableLength) &&
|
|
700
795
|
session._overflowRecoveryAttempted &&
|
|
701
796
|
session._overflowTrimStage < OVERFLOW_TRIM_MAX_STAGES) {
|
|
702
797
|
const stage = session._overflowTrimStage;
|
|
@@ -717,11 +812,11 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
717
812
|
const base = messages.length > 0 && messages[messages.length - 1].role === "assistant"
|
|
718
813
|
? messages.slice(0, -1)
|
|
719
814
|
: messages;
|
|
720
|
-
const trimmed = trimOverflowProjection(base, stage,
|
|
815
|
+
const trimmed = trimOverflowProjection(base, stage, effectiveSettings.keepRecentTokens);
|
|
721
816
|
// 返回原引用 = 已无可裁(估算已在目标内或无 turn 边界):重试注定
|
|
722
817
|
// 同样溢出,不空转请求,按策略失败文案直接失败(级数未增,无前缀)。
|
|
723
818
|
if (trimmed.length === 0 || trimmed === base) {
|
|
724
|
-
const errorMessage = overflowTrimFailureMessage(stage, failureMessage);
|
|
819
|
+
const errorMessage = overflowTrimFailureMessage(stage, failureMessage, contextOverflow ? "contextOverflow" : "recoverableLength");
|
|
725
820
|
session._emit({
|
|
726
821
|
type: "compaction_end",
|
|
727
822
|
reason: "overflow",
|
|
@@ -785,9 +880,7 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
785
880
|
});
|
|
786
881
|
}
|
|
787
882
|
if (decision.failureMessage) {
|
|
788
|
-
const errorMessage = contextOverflow
|
|
789
|
-
? overflowTrimFailureMessage(session._overflowTrimStage, decision.failureMessage)
|
|
790
|
-
: decision.failureMessage;
|
|
883
|
+
const errorMessage = overflowTrimFailureMessage(session._overflowTrimStage, decision.failureMessage, contextOverflow ? "contextOverflow" : "recoverableLength");
|
|
791
884
|
session._emit({
|
|
792
885
|
type: "compaction_end",
|
|
793
886
|
reason: "overflow",
|
|
@@ -858,8 +951,8 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
858
951
|
// 策略读取,内核不解释其内容。门控(设置开关 ∧ 冷却归零)被挡住时,
|
|
859
952
|
// 策略直接走全量压缩。
|
|
860
953
|
branchEntries: session.sessionManager.getBranch(),
|
|
861
|
-
keepRecentTokens:
|
|
862
|
-
microcompactEnabled:
|
|
954
|
+
keepRecentTokens: effectiveSettings.keepRecentTokens,
|
|
955
|
+
microcompactEnabled: effectiveSettings.microcompactEnabled && session._microcompactCooldown === 0,
|
|
863
956
|
signal,
|
|
864
957
|
});
|
|
865
958
|
await dispatchCompactionDecisionLifecycle(session, {
|
|
@@ -930,13 +1023,19 @@ export async function runAutoCompactionInternal(session, reason, willRetry) {
|
|
|
930
1023
|
session._autoCompactionAbortController = undefined;
|
|
931
1024
|
throw error;
|
|
932
1025
|
}
|
|
933
|
-
const
|
|
1026
|
+
const rawSettings = session.settingsManager.getCompactionSettings();
|
|
1027
|
+
// Adaptive keepRecentTokens(effectiveKeepRecentTokens,动机见其注释):
|
|
1028
|
+
// 小窗口下可摘要前缀不再被保护预算吃满,阈值命中的压缩真实落地而非空转。
|
|
1029
|
+
const settings = {
|
|
1030
|
+
...rawSettings,
|
|
1031
|
+
keepRecentTokens: effectiveKeepRecentTokens(rawSettings.keepRecentTokens, session.model?.contextWindow ?? 0, rawSettings.reserveTokens),
|
|
1032
|
+
};
|
|
934
1033
|
let started = false;
|
|
935
1034
|
try {
|
|
936
1035
|
if (!session.model) {
|
|
937
1036
|
return false;
|
|
938
1037
|
}
|
|
939
|
-
const auth = await getSummarizationRequestAuth(session, session.model);
|
|
1038
|
+
const auth = await getSummarizationRequestAuth(session, session.model, autoCompactionSignal);
|
|
940
1039
|
const { pathEntries, expectedRevision, operationId } = captureCompactionCommitBoundary(session, reason);
|
|
941
1040
|
const execution = executionFacts(session, "compaction", operationId);
|
|
942
1041
|
const preparation = await prepareCompaction(session, pathEntries, settings, execution, autoCompactionSignal);
|
|
@@ -1004,22 +1103,39 @@ export async function runAutoCompactionInternal(session, reason, willRetry) {
|
|
|
1004
1103
|
return session.agent.hasQueuedMessages();
|
|
1005
1104
|
}
|
|
1006
1105
|
catch (error) {
|
|
1007
|
-
const
|
|
1106
|
+
const message = error instanceof Error ? error.message : "compaction failed";
|
|
1107
|
+
// Cancellation is decided by the controller state, not the error shape:
|
|
1108
|
+
// aborts surface as AbortError from the summary pipeline, but so can
|
|
1109
|
+
// unrelated failures — only the signal tells them apart.
|
|
1110
|
+
const aborted = autoCompactionSignal.aborted;
|
|
1008
1111
|
if (started) {
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1112
|
+
if (aborted) {
|
|
1113
|
+
// 取消按正常结果收场(aborted:true、无错误文案),不打失败日志、
|
|
1114
|
+
// 不 dispatch failed lifecycle(契约见 dispatchCompactionFailedLifecycle 注释)。
|
|
1115
|
+
session._emit({
|
|
1116
|
+
type: "compaction_end",
|
|
1117
|
+
reason,
|
|
1118
|
+
result: undefined,
|
|
1119
|
+
aborted: true,
|
|
1120
|
+
willRetry: false,
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
else {
|
|
1124
|
+
const formattedErrorMessage = reason === "overflow"
|
|
1125
|
+
? `Context overflow recovery failed: ${message}`
|
|
1126
|
+
: `Auto-compaction failed: ${message}`;
|
|
1127
|
+
session._emit({
|
|
1128
|
+
type: "compaction_end",
|
|
1129
|
+
reason,
|
|
1130
|
+
result: undefined,
|
|
1131
|
+
aborted: false,
|
|
1132
|
+
willRetry: false,
|
|
1133
|
+
errorMessage: formattedErrorMessage,
|
|
1134
|
+
});
|
|
1135
|
+
// 压缩失败打点:与下方 failed 事件同一事实;取消路径不打点。
|
|
1136
|
+
session._hostLogger?.error("compaction", "compaction failed", { fields: { reason }, cause: error });
|
|
1137
|
+
await dispatchCompactionFailedLifecycle(session, { reason, errorMessage: formattedErrorMessage });
|
|
1138
|
+
}
|
|
1023
1139
|
}
|
|
1024
1140
|
return false;
|
|
1025
1141
|
}
|
|
@@ -1159,7 +1275,7 @@ export async function navigateTree(session, targetId, options = {}) {
|
|
|
1159
1275
|
let summaryUsage;
|
|
1160
1276
|
if (options.summarize && entriesToSummarize.length > 0) {
|
|
1161
1277
|
const model = session.model;
|
|
1162
|
-
const auth = await getSummarizationRequestAuth(session, model);
|
|
1278
|
+
const auth = await getSummarizationRequestAuth(session, model, session._branchSummaryAbortController.signal);
|
|
1163
1279
|
const branchSummarySettings = session.settingsManager.getBranchSummarySettings();
|
|
1164
1280
|
const runtime = session._capabilityRuntime;
|
|
1165
1281
|
if (!runtime || !runtime.hasBranchSummaryPolicy(session._branchSummaryPolicyName)) {
|