fix: align tool-result guard budget

This commit is contained in:
Peter Steinberger
2026-04-30 16:36:49 +01:00
parent 797d574dfd
commit 1a2228d291
3 changed files with 48 additions and 7 deletions

View File

@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Agents/tool-result guard: use the resolved runtime context token budget for non-context-engine tool-result overflow checks, so long tool-heavy sessions no longer compact early when `contextTokens` is larger than native `contextWindow`. Fixes #74917. Thanks @kAIborg24.
- Gateway/systemd: exit with sysexits 78 for supervised lock and `EADDRINUSE` conflicts so `RestartPreventExitStatus=78` stops `Restart=always` restart loops instead of repeatedly reloading plugins against an occupied port. Fixes #75115. Thanks @yhyatt.
- Plugins/runtime-deps: replace stale symlinked mirror target roots before writing runtime-mirror temp files and skip rewriting already materialized hardlinks, so cross-version container upgrades no longer crash-loop on read-only image-layer paths while warm mirrors do less churn. Fixes #75108; refs #75069. Thanks @coletebou and @xiaohuaxi.
- Auto-reply/group chats: fall back to automatic source delivery when a channel precomputes message-tool-only replies but the `message` tool is unavailable, so Discord/Slack-style group turns do not silently complete without a visible reply. Fixes #74868. Thanks @kagura-agent.

View File

@@ -869,3 +869,43 @@ describe("runEmbeddedAttempt context engine mid-turn precheck integration", () =
expect(result.messagesSnapshot).toEqual([seedMessage]);
});
});
describe("runEmbeddedAttempt tool-result guard budget wiring", () => {
const sessionKey = "agent:main:guildchat:channel:tool-result-guard-budget";
const tempPaths: string[] = [];
beforeEach(() => {
resetEmbeddedAttemptHarness();
clearMemoryPluginState();
});
afterEach(async () => {
await cleanupTempPaths(tempPaths);
clearMemoryPluginState();
vi.restoreAllMocks();
});
it("uses the resolved contextTokenBudget before model contextWindow", async () => {
await createContextEngineAttemptRunner({
contextEngine: createContextEngineBootstrapAndAssemble(),
sessionKey,
tempPaths,
attemptOverrides: {
contextTokenBudget: 1_000_000,
model: {
api: "openai-completions",
provider: "openai",
compat: {},
contextWindow: 200_000,
input: ["text"],
} as never,
},
});
expect(hoisted.installToolResultContextGuardMock).toHaveBeenCalledWith(
expect.objectContaining({
contextWindowTokens: 1_000_000,
}),
);
});
});

View File

@@ -1528,7 +1528,12 @@ export async function runEmbeddedAttempt(
};
const contextTokenBudgetForGuard = Math.max(
1,
Math.floor(params.contextTokenBudget ?? DEFAULT_CONTEXT_TOKENS),
Math.floor(
params.contextTokenBudget ??
params.model.contextWindow ??
params.model.maxTokens ??
DEFAULT_CONTEXT_TOKENS,
),
);
const toolResultMaxCharsForGuard = resolveLiveToolResultMaxChars({
contextWindowTokens: contextTokenBudgetForGuard,
@@ -1544,12 +1549,7 @@ export async function runEmbeddedAttempt(
if (!activeContextEngine || activeContextEngine.info.ownsCompaction !== true) {
removeToolResultContextGuard = installToolResultContextGuard({
agent: activeSession.agent,
contextWindowTokens: Math.max(
1,
Math.floor(
params.model.contextWindow ?? params.model.maxTokens ?? DEFAULT_CONTEXT_TOKENS,
),
),
contextWindowTokens: contextTokenBudgetForGuard,
...(midTurnPrecheckEnabled
? {
midTurnPrecheck: {