@ai-agent-forge/agent-forge 0.86.1 → 0.86.3
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 +34 -0
- package/dist/bundle/.build-manifest.json +158 -152
- 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-N6BQJSGH.js} +1 -1
- package/dist/bundle/chunks/chunk-RK2X2KU2.js +1442 -0
- package/dist/bundle/chunks/chunk-TBPTHASB.js +2 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-NZ66X6K7.js → google-generative-ai-ISTTUZMW.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-2ZZOFBNQ.js → google-vertex-NS7ZF7DK.js} +1 -1
- package/dist/bundle/chunks/jiti-static-loader-CDSTNEDU.js +2 -0
- package/dist/bundle/chunks/{mistral-conversations-B6DZRMEK.js → mistral-conversations-GINO6Z4I.js} +1 -1
- 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 +7 -2
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +137 -43
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-internal.d.ts +6 -0
- package/dist/core/agent-session-internal.d.ts.map +1 -1
- package/dist/core/agent-session-internal.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 +21 -4
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +104 -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 +3 -1
- 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 +3 -2
- package/dist/core/extensions/microcompact.d.ts.map +1 -1
- package/dist/core/extensions/microcompact.js +14 -5
- 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 +4 -0
- 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 +18 -3
- 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/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/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-KQEGUM34.js +0 -2
- package/dist/bundle/chunks/chunk-S3YLY4MG.js +0 -1581
- package/dist/bundle/chunks/openai-responses-TJLXRAXR.js +0 -2
|
@@ -12,7 +12,7 @@ import { completeSimple, streamSimple } from "@agent-forge/ai/compat";
|
|
|
12
12
|
import { detachedSessionSnapshot, SessionCancelledError, } from "./agent-session-internal.js";
|
|
13
13
|
import { dispatchCompactionDecisionLifecycle, dispatchCompactionFailedLifecycle } from "./agent-session-lifecycle.js";
|
|
14
14
|
import { formatNoApiKeyFoundMessage, formatNoModelSelectedMessage } from "./auth-guidance.js";
|
|
15
|
-
import { calculateContextTokens, collectEntriesForBranchSummary, estimateContextTokens, estimateTokens, isTurnStartMessage, } from "./compaction/index.js";
|
|
15
|
+
import { calculateContextTokens, collectEntriesForBranchSummary, effectiveKeepRecentTokens, estimateContextTokens, estimateTokens, isTurnStartMessage, } from "./compaction/index.js";
|
|
16
16
|
import { DEFAULT_COMPACTION_POLICY_NAME, SESSION_COMPACTION_COMMIT_EVENT_ID, SESSION_COMPACTION_COMMIT_EVENT_VERSION, } from "./extensions/index.js";
|
|
17
17
|
import { SUMMARY_MODEL_INVOCATION_ERROR_CODES } from "./extensions/public-api.js";
|
|
18
18
|
import { getLatestCompactionEntry } from "./session-manager.js";
|
|
@@ -37,11 +37,26 @@ function estimateMessagesTokens(messages) {
|
|
|
37
37
|
const OVERFLOW_TRIM_MAX_STAGES = 3;
|
|
38
38
|
/** 溢出裁剪第 2 级的目标 token 预算(估算)。 */
|
|
39
39
|
const OVERFLOW_TRIM_STAGE2_TARGET_TOKENS = 10_000;
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
/**
|
|
41
|
+
* microcompact 冷却长度(按模型请求计数):relief 落地后置此值,之后每次
|
|
42
|
+
* assistant message_end(无论 stopReason)减 1,归零前阈值 decide 以
|
|
43
|
+
* `microcompactEnabled: false` 关闭便宜缓解,落回全量压缩;user message_start
|
|
44
|
+
* 不复位——冷却按模型请求计数,与 turn 边界无关。
|
|
45
|
+
*
|
|
46
|
+
* 微观经济动机:每次 microcompact 触发都是一次中部历史改写,本网关前缀缓存
|
|
47
|
+
* 不稳定(实测同请求命中 3-99%),改尾部命中 88-99.9%、改中部 40-50%——
|
|
48
|
+
* 冷却把"阈值带上反复触发中部改写"的最坏情形封顶。
|
|
49
|
+
*/
|
|
50
|
+
const MICROCOMPACT_COOLDOWN_ASSISTANT_RESPONSES = 3;
|
|
51
|
+
/**
|
|
52
|
+
* 溢出/截断裁剪失败文案:实际发生过裁剪时附上前缀(分语:context overflow
|
|
53
|
+
* 维持既有精确文案,recoverable length 用截断响应措辞),0 次保持策略原文。
|
|
54
|
+
*/
|
|
55
|
+
function overflowTrimFailureMessage(attempts, failureMessage, kind) {
|
|
56
|
+
if (attempts <= 0)
|
|
57
|
+
return failureMessage;
|
|
58
|
+
const head = kind === "contextOverflow" ? "Context overflow" : "Truncated response";
|
|
59
|
+
return `${head} persists after compaction and ${attempts} trim attempts. ${failureMessage}`;
|
|
45
60
|
}
|
|
46
61
|
/**
|
|
47
62
|
* Trim the runtime projection for one overflow-recovery stage: drop the oldest
|
|
@@ -88,10 +103,10 @@ function trimOverflowProjection(messages, stage, keepRecentTokens) {
|
|
|
88
103
|
const floorStart = turnStarts[turnStarts.length - 1];
|
|
89
104
|
return floorStart === 0 ? messages : messages.slice(floorStart);
|
|
90
105
|
}
|
|
91
|
-
export async function getRequiredRequestAuth(session, model) {
|
|
106
|
+
export async function getRequiredRequestAuth(session, model, signal) {
|
|
92
107
|
let result;
|
|
93
108
|
try {
|
|
94
|
-
result = await session._modelRuntime.getAuth(model);
|
|
109
|
+
result = await session._modelRuntime.getAuth(model, { signal });
|
|
95
110
|
}
|
|
96
111
|
catch (error) {
|
|
97
112
|
const cause = error instanceof Error ? error.cause : undefined;
|
|
@@ -117,12 +132,12 @@ export async function getRequiredRequestAuth(session, model) {
|
|
|
117
132
|
}
|
|
118
133
|
throw new Error(formatNoApiKeyFoundMessage(model.provider));
|
|
119
134
|
}
|
|
120
|
-
export async function getSummarizationRequestAuth(session, model) {
|
|
135
|
+
export async function getSummarizationRequestAuth(session, model, signal) {
|
|
121
136
|
if (session.agent.streamFunction === streamSimple) {
|
|
122
|
-
return getRequiredRequestAuth(session, model);
|
|
137
|
+
return getRequiredRequestAuth(session, model, signal);
|
|
123
138
|
}
|
|
124
139
|
try {
|
|
125
|
-
const result = await session._modelRuntime.getAuth(model);
|
|
140
|
+
const result = await session._modelRuntime.getAuth(model, { signal });
|
|
126
141
|
if (!result)
|
|
127
142
|
return { model };
|
|
128
143
|
const requestModel = result.auth.baseUrl ? { ...model, baseUrl: result.auth.baseUrl } : model;
|
|
@@ -133,7 +148,12 @@ export async function getSummarizationRequestAuth(session, model) {
|
|
|
133
148
|
env: result.env,
|
|
134
149
|
};
|
|
135
150
|
}
|
|
136
|
-
catch {
|
|
151
|
+
catch (error) {
|
|
152
|
+
// Auth resolution normally falls back to an unauthenticated summary when
|
|
153
|
+
// it fails, but an abort must not be swallowed into that fallback: the
|
|
154
|
+
// caller's signal decided this run is over.
|
|
155
|
+
if (signal?.aborted)
|
|
156
|
+
throw error;
|
|
137
157
|
return { model };
|
|
138
158
|
}
|
|
139
159
|
}
|
|
@@ -255,6 +275,13 @@ export async function compactBeforeNextAssistantResponse(session, context, signa
|
|
|
255
275
|
if (!model || model.contextWindow <= 0) {
|
|
256
276
|
return context;
|
|
257
277
|
}
|
|
278
|
+
// Adaptive keepRecentTokens:小窗口把近期保护预算钳到可摘要窗口的一半
|
|
279
|
+
//(effectiveKeepRecentTokens,动机见其注释;大窗口原值不变),本路径与
|
|
280
|
+
// checkCompaction/compactInternal/runAutoCompactionInternal 一致使用 effective 值。
|
|
281
|
+
const effectiveSettings = {
|
|
282
|
+
...settings,
|
|
283
|
+
keepRecentTokens: effectiveKeepRecentTokens(settings.keepRecentTokens, model.contextWindow, settings.reserveTokens),
|
|
284
|
+
};
|
|
258
285
|
const contextTokens = estimateContextTokens(context.messages).tokens;
|
|
259
286
|
const decision = await decideCompaction(session, {
|
|
260
287
|
reason: "threshold",
|
|
@@ -266,6 +293,11 @@ export async function compactBeforeNextAssistantResponse(session, context, signa
|
|
|
266
293
|
reserveTokens: settings.reserveTokens,
|
|
267
294
|
},
|
|
268
295
|
canContinue: false,
|
|
296
|
+
// 便宜缓解的事实输入与门控,与 checkCompaction 的 threshold decide 相同
|
|
297
|
+
//(设置开关 ∧ 冷却归零):被任一条件挡住时策略不做便宜缓解,直接走全量压缩。
|
|
298
|
+
branchEntries: session.sessionManager.getBranch(),
|
|
299
|
+
keepRecentTokens: effectiveSettings.keepRecentTokens,
|
|
300
|
+
microcompactEnabled: settings.microcompactEnabled && session._microcompactCooldown === 0,
|
|
269
301
|
signal: signal ?? session._policyDecisionAbortController?.signal,
|
|
270
302
|
});
|
|
271
303
|
await dispatchCompactionDecisionLifecycle(session, {
|
|
@@ -279,6 +311,27 @@ export async function compactBeforeNextAssistantResponse(session, context, signa
|
|
|
279
311
|
reserveTokens: settings.reserveTokens,
|
|
280
312
|
...(decision.failureMessage === undefined ? {} : { failureMessage: decision.failureMessage }),
|
|
281
313
|
});
|
|
314
|
+
// 策略便宜缓解(通用通道),镜像 checkCompaction 的 relief 落地分支:宿主原样
|
|
315
|
+
// 追加条目并重投影上下文,条目语义与投影归策略。执行上下文:本函数经默认
|
|
316
|
+
// prepareNextTurn loop link 在 agent 回合之间被 agent run await,不在
|
|
317
|
+
// _compactionQueue 内;手动压缩入口 compactInternal 先 _abortInternal() 等待
|
|
318
|
+
// 活跃回合结束,而本路径位于回合执行链上,回合结束前必先完成——relief 落地
|
|
319
|
+
// (同步 append + 投影)不会与手动压缩的摘要/提交交错,与 postAgentRun 的
|
|
320
|
+
// relief 落地同模式,不加队列锁。
|
|
321
|
+
if (decision.relief !== undefined && !decision.compact) {
|
|
322
|
+
session.sessionManager.appendCustomEntry(decision.relief.customType, decision.relief.data);
|
|
323
|
+
const sessionContext = session.sessionManager.buildSessionContext();
|
|
324
|
+
await session._applyContextTransition(sessionContext.messages, "compaction");
|
|
325
|
+
// 冷却起点:relief 已落地即开始计数(由 assistant message_end 递减)。
|
|
326
|
+
session._microcompactCooldown = MICROCOMPACT_COOLDOWN_ASSISTANT_RESPONSES;
|
|
327
|
+
session._hostLogger?.info("compaction", "policy relief applied", {
|
|
328
|
+
fields: { customType: decision.relief.customType, path: "pre-response" },
|
|
329
|
+
});
|
|
330
|
+
return {
|
|
331
|
+
...context,
|
|
332
|
+
messages: session.agent.state.messages.slice(),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
282
335
|
if (!decision.compact)
|
|
283
336
|
return context;
|
|
284
337
|
await session._runAutoCompaction("threshold", false);
|
|
@@ -521,9 +574,16 @@ export async function compactInternal(session, customInstructions) {
|
|
|
521
574
|
if (!session.model) {
|
|
522
575
|
throw new Error(formatNoModelSelectedMessage());
|
|
523
576
|
}
|
|
524
|
-
const auth = await getSummarizationRequestAuth(session, session.model);
|
|
577
|
+
const auth = await getSummarizationRequestAuth(session, session.model, session._compactionAbortController.signal);
|
|
525
578
|
const { pathEntries, expectedRevision, operationId } = captureCompactionCommitBoundary(session, "manual");
|
|
526
|
-
const
|
|
579
|
+
const rawSettings = session.settingsManager.getCompactionSettings();
|
|
580
|
+
// Adaptive keepRecentTokens(effectiveKeepRecentTokens,动机见其注释):手动
|
|
581
|
+
// 压缩与自动路径同一 effective 值,小窗口下 /compact 不再因保护预算吃满
|
|
582
|
+
// 整个可摘要窗口而报 "Nothing to compact"。
|
|
583
|
+
const settings = {
|
|
584
|
+
...rawSettings,
|
|
585
|
+
keepRecentTokens: effectiveKeepRecentTokens(rawSettings.keepRecentTokens, session.model.contextWindow, rawSettings.reserveTokens),
|
|
586
|
+
};
|
|
527
587
|
const execution = executionFacts(session, "compaction", operationId);
|
|
528
588
|
const preparation = await prepareCompaction(session, pathEntries, settings, execution, session._compactionAbortController.signal);
|
|
529
589
|
if (!preparation) {
|
|
@@ -636,6 +696,13 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
636
696
|
if (signal?.aborted)
|
|
637
697
|
return false;
|
|
638
698
|
const settings = session.settingsManager.getCompactionSettings();
|
|
699
|
+
// Adaptive keepRecentTokens(effectiveKeepRecentTokens,动机见其注释:座席实测
|
|
700
|
+
// 30K 窗口 20K 保护预算使可摘要前缀为零,阈值反复命中却无事可做)。一次性
|
|
701
|
+
// 替换后全文一致使用:下方 trim 阶梯 stage 0 目标与 threshold decide 请求。
|
|
702
|
+
const effectiveSettings = {
|
|
703
|
+
...settings,
|
|
704
|
+
keepRecentTokens: effectiveKeepRecentTokens(settings.keepRecentTokens, session.model?.contextWindow ?? 0, settings.reserveTokens),
|
|
705
|
+
};
|
|
639
706
|
// Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
|
|
640
707
|
if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
|
|
641
708
|
return false;
|
|
@@ -679,11 +746,12 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
679
746
|
...(decision.failureMessage === undefined ? {} : { failureMessage: decision.failureMessage }),
|
|
680
747
|
});
|
|
681
748
|
if (!decision.compact) {
|
|
682
|
-
// 溢出裁剪兜底:压缩恢复(recoveryAttempted)后仍 context overflow
|
|
683
|
-
//
|
|
684
|
-
//
|
|
749
|
+
// 溢出裁剪兜底:压缩恢复(recoveryAttempted)后仍 context overflow 或
|
|
750
|
+
// recoverable length(截断响应=输出被掐,缩输入可让输出有空间,turn 边界
|
|
751
|
+
// 裁剪对两种溢出同样有效)时,先对运行时投影做逐级裁剪重试,3 级全失败才
|
|
752
|
+
// 走策略 failureMessage 失败路径。执行逻辑归 AgentSession,策略接口与事件面不变。
|
|
685
753
|
if (decision.failureMessage &&
|
|
686
|
-
contextOverflow &&
|
|
754
|
+
(contextOverflow || recoverableLength) &&
|
|
687
755
|
session._overflowRecoveryAttempted &&
|
|
688
756
|
session._overflowTrimStage < OVERFLOW_TRIM_MAX_STAGES) {
|
|
689
757
|
const stage = session._overflowTrimStage;
|
|
@@ -704,11 +772,11 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
704
772
|
const base = messages.length > 0 && messages[messages.length - 1].role === "assistant"
|
|
705
773
|
? messages.slice(0, -1)
|
|
706
774
|
: messages;
|
|
707
|
-
const trimmed = trimOverflowProjection(base, stage,
|
|
775
|
+
const trimmed = trimOverflowProjection(base, stage, effectiveSettings.keepRecentTokens);
|
|
708
776
|
// 返回原引用 = 已无可裁(估算已在目标内或无 turn 边界):重试注定
|
|
709
777
|
// 同样溢出,不空转请求,按策略失败文案直接失败(级数未增,无前缀)。
|
|
710
778
|
if (trimmed.length === 0 || trimmed === base) {
|
|
711
|
-
const errorMessage = overflowTrimFailureMessage(stage, failureMessage);
|
|
779
|
+
const errorMessage = overflowTrimFailureMessage(stage, failureMessage, contextOverflow ? "contextOverflow" : "recoverableLength");
|
|
712
780
|
session._emit({
|
|
713
781
|
type: "compaction_end",
|
|
714
782
|
reason: "overflow",
|
|
@@ -772,9 +840,7 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
772
840
|
});
|
|
773
841
|
}
|
|
774
842
|
if (decision.failureMessage) {
|
|
775
|
-
const errorMessage = contextOverflow
|
|
776
|
-
? overflowTrimFailureMessage(session._overflowTrimStage, decision.failureMessage)
|
|
777
|
-
: decision.failureMessage;
|
|
843
|
+
const errorMessage = overflowTrimFailureMessage(session._overflowTrimStage, decision.failureMessage, contextOverflow ? "contextOverflow" : "recoverableLength");
|
|
778
844
|
session._emit({
|
|
779
845
|
type: "compaction_end",
|
|
780
846
|
reason: "overflow",
|
|
@@ -842,9 +908,11 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
842
908
|
canContinue: false,
|
|
843
909
|
// 便宜缓解的事实输入:策略可以据此先做零成本的本地上下文缓解(如
|
|
844
910
|
// bootstrap 策略的 microcompact),把 LLM 摘要留作兜底。分支快照仅为
|
|
845
|
-
//
|
|
911
|
+
// 策略读取,内核不解释其内容。门控(设置开关 ∧ 冷却归零)被挡住时,
|
|
912
|
+
// 策略直接走全量压缩。
|
|
846
913
|
branchEntries: session.sessionManager.getBranch(),
|
|
847
|
-
keepRecentTokens:
|
|
914
|
+
keepRecentTokens: effectiveSettings.keepRecentTokens,
|
|
915
|
+
microcompactEnabled: effectiveSettings.microcompactEnabled && session._microcompactCooldown === 0,
|
|
848
916
|
signal,
|
|
849
917
|
});
|
|
850
918
|
await dispatchCompactionDecisionLifecycle(session, {
|
|
@@ -863,6 +931,9 @@ export async function checkCompaction(session, assistantMessage, skipAbortedChec
|
|
|
863
931
|
session.sessionManager.appendCustomEntry(decision.relief.customType, decision.relief.data);
|
|
864
932
|
const sessionContext = session.sessionManager.buildSessionContext();
|
|
865
933
|
await session._applyContextTransition(sessionContext.messages, "compaction");
|
|
934
|
+
// 冷却起点:relief 已落地即开始计数(本次改写后的下一个模型请求起算,
|
|
935
|
+
// 由 assistant message_end 递减,见 AgentSession)。
|
|
936
|
+
session._microcompactCooldown = MICROCOMPACT_COOLDOWN_ASSISTANT_RESPONSES;
|
|
866
937
|
session._hostLogger?.info("compaction", "policy relief applied", {
|
|
867
938
|
fields: { customType: decision.relief.customType },
|
|
868
939
|
});
|
|
@@ -912,13 +983,19 @@ export async function runAutoCompactionInternal(session, reason, willRetry) {
|
|
|
912
983
|
session._autoCompactionAbortController = undefined;
|
|
913
984
|
throw error;
|
|
914
985
|
}
|
|
915
|
-
const
|
|
986
|
+
const rawSettings = session.settingsManager.getCompactionSettings();
|
|
987
|
+
// Adaptive keepRecentTokens(effectiveKeepRecentTokens,动机见其注释):
|
|
988
|
+
// 小窗口下可摘要前缀不再被保护预算吃满,阈值命中的压缩真实落地而非空转。
|
|
989
|
+
const settings = {
|
|
990
|
+
...rawSettings,
|
|
991
|
+
keepRecentTokens: effectiveKeepRecentTokens(rawSettings.keepRecentTokens, session.model?.contextWindow ?? 0, rawSettings.reserveTokens),
|
|
992
|
+
};
|
|
916
993
|
let started = false;
|
|
917
994
|
try {
|
|
918
995
|
if (!session.model) {
|
|
919
996
|
return false;
|
|
920
997
|
}
|
|
921
|
-
const auth = await getSummarizationRequestAuth(session, session.model);
|
|
998
|
+
const auth = await getSummarizationRequestAuth(session, session.model, autoCompactionSignal);
|
|
922
999
|
const { pathEntries, expectedRevision, operationId } = captureCompactionCommitBoundary(session, reason);
|
|
923
1000
|
const execution = executionFacts(session, "compaction", operationId);
|
|
924
1001
|
const preparation = await prepareCompaction(session, pathEntries, settings, execution, autoCompactionSignal);
|
|
@@ -986,22 +1063,39 @@ export async function runAutoCompactionInternal(session, reason, willRetry) {
|
|
|
986
1063
|
return session.agent.hasQueuedMessages();
|
|
987
1064
|
}
|
|
988
1065
|
catch (error) {
|
|
989
|
-
const
|
|
1066
|
+
const message = error instanceof Error ? error.message : "compaction failed";
|
|
1067
|
+
// Cancellation is decided by the controller state, not the error shape:
|
|
1068
|
+
// aborts surface as AbortError from the summary pipeline, but so can
|
|
1069
|
+
// unrelated failures — only the signal tells them apart.
|
|
1070
|
+
const aborted = autoCompactionSignal.aborted;
|
|
990
1071
|
if (started) {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1072
|
+
if (aborted) {
|
|
1073
|
+
// 取消按正常结果收场(aborted:true、无错误文案),不打失败日志、
|
|
1074
|
+
// 不 dispatch failed lifecycle(契约见 dispatchCompactionFailedLifecycle 注释)。
|
|
1075
|
+
session._emit({
|
|
1076
|
+
type: "compaction_end",
|
|
1077
|
+
reason,
|
|
1078
|
+
result: undefined,
|
|
1079
|
+
aborted: true,
|
|
1080
|
+
willRetry: false,
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
const formattedErrorMessage = reason === "overflow"
|
|
1085
|
+
? `Context overflow recovery failed: ${message}`
|
|
1086
|
+
: `Auto-compaction failed: ${message}`;
|
|
1087
|
+
session._emit({
|
|
1088
|
+
type: "compaction_end",
|
|
1089
|
+
reason,
|
|
1090
|
+
result: undefined,
|
|
1091
|
+
aborted: false,
|
|
1092
|
+
willRetry: false,
|
|
1093
|
+
errorMessage: formattedErrorMessage,
|
|
1094
|
+
});
|
|
1095
|
+
// 压缩失败打点:与下方 failed 事件同一事实;取消路径不打点。
|
|
1096
|
+
session._hostLogger?.error("compaction", "compaction failed", { fields: { reason }, cause: error });
|
|
1097
|
+
await dispatchCompactionFailedLifecycle(session, { reason, errorMessage: formattedErrorMessage });
|
|
1098
|
+
}
|
|
1005
1099
|
}
|
|
1006
1100
|
return false;
|
|
1007
1101
|
}
|
|
@@ -1141,7 +1235,7 @@ export async function navigateTree(session, targetId, options = {}) {
|
|
|
1141
1235
|
let summaryUsage;
|
|
1142
1236
|
if (options.summarize && entriesToSummarize.length > 0) {
|
|
1143
1237
|
const model = session.model;
|
|
1144
|
-
const auth = await getSummarizationRequestAuth(session, model);
|
|
1238
|
+
const auth = await getSummarizationRequestAuth(session, model, session._branchSummaryAbortController.signal);
|
|
1145
1239
|
const branchSummarySettings = session.settingsManager.getBranchSummarySettings();
|
|
1146
1240
|
const runtime = session._capabilityRuntime;
|
|
1147
1241
|
if (!runtime || !runtime.hasBranchSummaryPolicy(session._branchSummaryPolicyName)) {
|