-
-
Notifications
You must be signed in to change notification settings - Fork 52.7k
Description
Bug Description
When an agent enters a long tool-use loop (many consecutive tool calls without user messages), the context grows steadily but auto-compaction never triggers. The session eventually hits the model's context window limit and becomes permanently stuck with "Context window is full" errors.
Steps to Reproduce
- Configure
compaction.mode: "safeguard"withreserveTokensFloor: 45000and a model withcontextWindow: 200000 - Start a session where the agent performs many consecutive tool calls (e.g., build/deploy workflow with 15+ exec calls)
- Observe context growing: 188k → 190k → 194k → 196k → 199k → 200k
- At 200k, API returns
400 Context window is full - Auto-compaction attempts to run but also fails because the context is already too full to generate a summary
Expected Behavior
Compaction should trigger proactively when context approaches the limit (e.g., at contextWindow - reserveTokensFloor = 155k), not only reactively after the API returns a context overflow error.
Actual Behavior
run.tsonly checks for context overflow after the API call fails (line ~528:if (contextOverflowError))- During tool-use loops, there is no pre-prompt context size check
- By the time overflow is detected, the context is already at 100% capacity
- The compaction attempt itself needs API calls, which also fail due to full context
- Session becomes permanently stuck —
Compactions: 0despite 200k+ context - Only recovery is
/newor/reset
Analysis
Looking at the source code:
run.ts: Auto-compaction is only triggered in thecontextOverflowErrorhandler (reactive, not proactive)compaction-safeguard.ts: Only handlessession_before_compactevent — it improves compaction quality but doesn't control when compaction triggersreserveTokensFloor: 45000: This setting exists but doesn't appear to trigger proactive compaction during tool loops
The reserveTokensFloor should ideally trigger compaction when currentContextTokens > contextWindow - reserveTokensFloor, but this check doesn't happen between tool-call iterations in the run loop.
Session Data (anonymized)
Last 5 successful API calls before crash:
input=196,804 tokens (tool call)
input=197,281 tokens (tool call)
input=198,216 tokens (tool call)
input=199,735 tokens (tool call)
input=199,960 tokens (tool call) ← last successful
input=0 (error: "Context window is full")
Session stats: Compactions: 0, Context: 200k/200k (100%)
Suggested Fix
Add a proactive context check in the tool-use loop in run.ts, something like:
// Before each tool-call iteration, check if context is approaching the limit
const currentTokens = attempt.usage?.input ?? 0;
const compactionThreshold = ctxInfo.tokens - reserveTokensFloor;
if (currentTokens > compactionThreshold && !proactiveCompactionAttempted) {
proactiveCompactionAttempted = true;
log.warn(`Proactive compaction: ${currentTokens}/${ctxInfo.tokens} tokens used`);
await compactEmbeddedPiSessionDirect({...});
}Environment
- OpenClaw version: 2026.2.13
- Model: Claude Opus 4.6 (contextWindow: 200000)
- Compaction config:
{ mode: "safeguard", reserveTokensFloor: 45000 } - Context pruning:
{ mode: "cache-ttl", ttl: "24h" }