fix(session): stop auto-compacting after 3 consecutive attempts that don't shrink the request - #48188
fix(session): stop auto-compacting after 3 consecutive attempts that don't shrink the request#48188OracleCLM wants to merge 1 commit into
Conversation
…don't shrink the request Compaction can only reduce the conversation. When what exceeds the provider's context window is the fixed overhead — system prompt plus tool definitions — every compaction genuinely succeeds (the request really is smaller) and the very next turn overflows again. isOverflow() keeps evaluating true, compaction.create() keeps firing, and the loop never terminates. Observed live: Build -> "Task completed" -> Compaction -> Build -> ... cycling five or more times in about forty-five seconds, never producing an answer. The failure mode is worse than a visible hang: as soon as the sequence of oversized replies ends, the loop finishes on an ordinary response with a benign "stop" and no error at all. The session quietly stops doing what it was asked instead of saying why it cannot. Adds a per-run counter of consecutive compactions, capped at 3, on both triggers (the preventive isOverflow check and the reactive mid-stream "compact" path). When the cap is exceeded the assistant message carries a ContextOverflowError naming the real constraint, and the loop stops. The counter resets when a finished turn no longer overflows — the precise meaning of "compaction did its job". Resetting on any completed turn would defeat the cap in exactly the case it exists for, where every turn succeeds and every turn is still too large. The test seeds an already-finished oversized reply so the first decision comes from the preventive check, and queues more oversized turns than the cap allows, so it measures how many the loop tries rather than when the queue runs out. Against the current code it fails with Expected "ContextOverflowError", received undefined.
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
|
The following comment was made by an LLM, it may be inaccurate: Found one potentially related PR: PR #10123: feat(session): add custom compaction thresholds along with prevention of continuous compaction This PR appears related as it also addresses continuous/repeated compaction prevention in sessions. It may have explored similar solutions or approaches to preventing infinite compaction loops, though it focuses on thresholds rather than a 3-attempt cap with error handling. The other results (PR #48188 is the current PR, #42424 is about model fallback which is unrelated). |
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
|
This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window. Feel free to open a new pull request that follows our guidelines. |
Body
Compaction can only reduce the conversation. When what exceeds the
provider's context window is the fixed overhead — system prompt plus tool
definitions — every compaction genuinely succeeds (the request really is
smaller) and the very next turn overflows again.
isOverflow()keeps evaluatingtrue,
compaction.create()keeps firing, and the loop never terminates.Observed live:
Build -> "Task completed" -> Compaction -> Build -> "Task completed" -> Compaction …, cycling five or more times in about forty-fiveseconds, never producing a visible answer.
The failure mode is worse than a visible hang. Once the queue of oversized
replies runs out in a test — or the provider's behaviour shifts slightly in
production — the loop ends on an ordinary small response and finishes with a
benign
stopand no error at all. The session quietly stops doing what itwas asked instead of saying why it cannot.
The change
A per-run counter of consecutive compactions, capped at 3, on both triggers (the
preventive
isOverflowcheck and the reactive mid-streamresult === "compact"path). When the cap is exceeded, the assistant message carries a
ContextOverflowErrornaming the actual constraint — the system prompt or thetool set — and the loop stops.
The counter resets when a finished turn no longer overflows, which is the
precise meaning of "compaction did its job". Resetting on any completed turn
would defeat the cap in exactly the case it exists for, where every turn
succeeds and every turn is still too large.
Test
loop gives up after repeated auto-compaction instead of looping foreverseedsan already-finished oversized reply so the loop's first decision comes from the
preventive check, then queues more oversized turns than the cap allows — so what
is measured is how many the loop tries, not whether the queue runs out.
Verified in both directions: against the current code the test fails with
Expected: "ContextOverflowError" / Received: undefined— the benign silentending described above.