fix(compaction): add mid-turn in-flight compression safety valve - #42898
fix(compaction): add mid-turn in-flight compression safety valve#42898JimStenstrom wants to merge 1 commit into
Conversation
Proactive context compression runs only once per turn, in the preflight before the tool-calling loop, so a single long autonomous turn that makes many tool calls can grow context unbounded and overflow the model's window mid-turn — today only a reactive post-error path and the Ollama hard-abort catch it. Observed on a local model: a 6-tool-call turn reached 2.6x the preflight threshold with zero compaction. Add _maybe_inflight_compress(), called at the top of the tool-calling loop, which re-checks compression but only once the request nears the model's real context window — an emergency fraction (HERMES_INFLIGHT_COMPRESS_FRACTION, default 0.85), well above the 50% preflight threshold. Normal turns stay below it and keep their prompt-cache prefix; the one-time mid-turn cache bust is paid only when a turn would otherwise overflow. Mirrors the preflight's post-compression resets and clears the caller's history ref so the session-DB flush writes the compacted messages. Complements (not replaces) the preflight and reactive-on-error compaction paths. Refs NousResearch#36624
|
Code Review — clean ✅ Reviewed the full diff (conversation_loop.py + tests). The safety valve design is well-thought-out:
One note: the Tests cover: fire-at-limit, skip-first-iteration, skip-below-emergency, skip-disabled, anti-thrash-blocks, env-override. Good coverage. No issues found. 🚀 |
|
Closing as redundant. Re-reviewing against current |
What does this PR do?
Proactive context compression only runs once per turn, at preflight before the tool-calling loop (
agent/turn_context.py). A single long autonomous turn that emits many/large tool calls can therefore grow context unbounded and overflow the model's window mid-turn, before the next turn's preflight ever runs — today only the reactive post-error path and the Ollama hard-abort catch it. Observed on a local model: a 6-tool-call turn reached 2.6× the preflight threshold with zero compaction.This adds
_maybe_inflight_compress(), called at the top of the tool-calling loop, which re-checks compression but only once the request nears the model's real context window — an emergency fraction (HERMES_INFLIGHT_COMPRESS_FRACTION, default 0.85, well above the 50% preflight threshold). Normal turns never cross it and keep their prompt-cache prefix intact; the one-time mid-turn cache bust is paid only when a turn would otherwise overflow. It mirrors preflight's post-compression resets and clears the caller's history ref so the session-DB flush writes the compacted messages. It complements (does not replace) the preflight and reactive-on-error paths.The 0.85 default lines up with the maintainer's own choice in #40957 (raised the compaction trigger to 85% for gpt-5.5 on Codex OAuth).
Related Issue
Refs #36624 — this owns one sub-symptom of that P1 ("auto compression can exhaust context in tool-heavy sessions"): the proactive trigger cadence (compaction is never re-evaluated between preflight and overflow). It is complementary, not a duplicate, to the other open PRs on #36624, which address a different facet — compaction effectiveness and graceful exhaustion:
compression_exhaustedat the preflight site.Even with both merged, nothing triggers compaction in time mid-turn; this PR adds that missing proactive valve. Using
Refs(notCloses) intentionally — the broader #36624 scope (tail demotion, explicit exhaustion) stays open.Type of Change
Changes Made
agent/conversation_loop.py— add_maybe_inflight_compress()and call it at the top of the tool-calling loop. Guarded: only after the first iteration, only when compression is enabled and a compressor exists, only once usage crosses the emergency fraction, honoring the compressor's anti-thrash gate andprotect_first_n/protect_last_nboundaries. Prefers the real provider prompt-token count from the prior response, falling back to a rough estimate.tests/test_inflight_compression.py— 6 behavioral unit tests.How to Test
scripts/run_tests.sh tests/test_inflight_compression.py→ 6 passed.HERMES_INFLIGHT_COMPRESS_FRACTIONoverride path.Checklist
Code
fix(compaction):)scripts/run_tests.sh(the CI-parity hermetic wrapper)Documentation & Housekeeping
HERMES_INFLIGHT_COMPRESS_FRACTIONknob is documented in the commit body)cli-config.yaml.example— N/A (env-var controlled, not a config key)CONTRIBUTING.md/AGENTS.md— N/A (no architecture/workflow change)Screenshots / Logs
N/A — logs/perf-safe change. Diff is additive: +246 / −0 across 2 files (1 prod, 1 test).