compression: fix auto-compress no-op on few-huge-messages + honest status
Root cause: the compression gate (should_compress) measures tokens, but the
partition measures message/turn count, and CompressionStarted was emitted
before the attempt. For navi_code's "few very large messages" shape (one big
file read = 1 user + assistant + 1 huge tool result, 66k tokens in 3 messages)
the gate fired, the UI showed "compression", but partition returned
to_summarize=[] -> compress_context None -> nothing shrank. The agent kept
going until the window overflowed. It wasn't running "during" compression —
there was no compression, just a no-op the user mistook for one.

A. Per-message head/tail truncation in context_builder.build(): oversized
   tool/assistant messages (over context_message_token_budget, 0=num_ctx//6)
   are capped head+marker+tail in the LLM view only (model_copy — stored
   history and reloads are never affected). A single huge tool result can no
   longer alone blow the window; user/system messages are never truncated.

B. Token-budget hard-truncate fallback in compress_session: when partition
   no-ops but tokens exceed the threshold, drop oldest turns to num_ctx*0.5.
   _hard_truncate is now token-aware (was a fixed message-count floor that
   no-oped on <=6 messages even when huge). New would_compress() predicts
   compress_session's real outcome with no LLM call.

C. Honest CompressionStarted: _compression_events_midturn/_preturn emit it
   only after would_compress() confirms the partition (or token-budget
   fallback) can actually shrink the stored context — no more "compression"
   status with no ContextCompressed to follow.

Bonus: post-turn CompressionWorker now passes keep_recent_messages=
max(12, context_keep_recent*2), matching the midturn path, so a single long
autonomous turn compresses post-turn too (was always a no-op).

Tests (+14): would_compress agreement, token-budget fallback, token-aware
hard_truncate, build() truncation (preserves user, no mutation, head+tail),
agent no-CompressionStarted-when-nothing-to-compress, worker single-long-turn.

Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a918f22 commit 3d9c3dae1721025950e66f73da763e33ae659b13
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 8 hours ago
Showing 9 changed files
View
navi/config.py
View
navi/core/agent.py
View
navi/core/compressor.py
View
navi/core/context_builder.py
View
navi/workers/compressor.py
View
tests/unit/core/test_agent.py
View
tests/unit/core/test_compressor.py
View
tests/unit/core/test_context_builder.py
View
tests/unit/workers/test_compression_worker.py 0 → 100644