fix(compression): overflow handlers pass overhead-aware token size to LCM recovery (issue 441)

Root fix (Option A) for design-session "Context compression exhausted" crashes. The three
compression-retry handlers after an API overflow/413/long-context error (conversation_loop.py
~4229/4488/4747) passed the tool-BLIND messages-only estimate (approx_tokens) to _compress_context,
so hermes-lcm's forced-overflow recovery armed on the message count and missed overflows driven by
tool-schema/system overhead. Now they pass estimate_request_tokens_rough(api_messages, tools=...)
— the same overhead-aware estimator already used at :4580 — so recovery arms on the TRUE request
size; LCM's _overflow_recovery_assembly_cap self-subtracts the overhead so the full request fits.

Empirically validated on real failed session 6dddf1a67b76 (LCM engine, floor=24000/cap=248000):
observed 256,359 >= 248,000 -> arms; recovery 231,313->208,559 msg-tokens -> full request
233,605 < 272,000 FITS. Prior messages-only path did NOT arm (231K < 248K) and crashed.

Durable copy: ~/.hermes/local-patches/optionA-overflow-overhead-aware.patch (survives hermes update
reset). Upstream PR pending. classify_api_error call at :3667 intentionally unchanged (not recovery).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
LFDM Core 2026-08-02 14:45:47 -07:00 committed by kshitij
parent e8c1882766
commit 4ffc8449a3
1 changed files with 13 additions and 3 deletions

View File

@ -4360,9 +4360,11 @@ def run_conversation(
compression_attempts += 1
if compression_attempts <= max_compression_attempts:
original_len = len(messages)
# Option A (LCM issue 441): overhead-aware request size so recovery arms on
# the true request (msgs + tools + system), not the tool-blind message count.
messages, active_system_prompt = agent._compress_context(
messages, system_message,
approx_tokens=approx_tokens,
approx_tokens=estimate_request_tokens_rough(api_messages, tools=agent.tools or None),
task_id=effective_task_id,
)
conversation_history = conversation_history_after_compression(
@ -4617,8 +4619,11 @@ def run_conversation(
original_len = len(messages)
original_tokens = estimate_messages_tokens_rough(messages)
_overflow_input = messages
# Option A (LCM issue 441): overhead-aware request size so recovery arms on the
# true request (msgs + tools + system), not the tool-blind message count.
messages, active_system_prompt = agent._compress_context(
messages, system_message, approx_tokens=approx_tokens,
messages, system_message,
approx_tokens=estimate_request_tokens_rough(api_messages, tools=agent.tools or None),
task_id=effective_task_id,
)
if messages is _overflow_input and compression_skipped_due_to_lock(agent):
@ -4878,8 +4883,13 @@ def run_conversation(
original_len = len(messages)
original_tokens = estimate_messages_tokens_rough(messages)
_overflow_input = messages
# Option A (LCM issue 441): pass the OVERHEAD-AWARE request size (msgs + tool
# schemas + system), not the tool-blind message count, so LCM forced-overflow
# recovery arms on the TRUE request that overflowed. See hermes-lcm engine
# _should_force_overflow_recovery. (approx_tokens stays for the status display.)
messages, active_system_prompt = agent._compress_context(
messages, system_message, approx_tokens=approx_tokens,
messages, system_message,
approx_tokens=estimate_request_tokens_rough(api_messages, tools=agent.tools or None),
task_id=effective_task_id,
)
if messages is _overflow_input and compression_skipped_due_to_lock(agent):