diff --git a/agent/conversation_loop.py b/agent/conversation_loop.py index 83681e426670..5b4185a24124 100644 --- a/agent/conversation_loop.py +++ b/agent/conversation_loop.py @@ -3061,14 +3061,21 @@ def run_conversation( # (``/new``), switch to a larger-context model, or reduce # attachments. Forced compaction via ``/compress`` # (``force=True``) is unaffected — it never reaches this loop. + # + # Output-cap errors (max_tokens too large) are NOT input + # overflow — the recovery is a max_tokens-only retry that + # does not require compression. Exempt them from this guard + # so the retry still fires even when compression is disabled. _overflow_reasons = { FailoverReason.long_context_tier, FailoverReason.payload_too_large, FailoverReason.context_overflow, } + _is_output_cap_error = is_output_cap_error(error_msg) if ( classified.reason in _overflow_reasons and not getattr(agent, "compression_enabled", True) + and not _is_output_cap_error ): agent._flush_status_buffer() agent._vprint( @@ -3487,8 +3494,10 @@ def run_conversation( if local_available_out > 0: safe_out = max(1, min(available_out, local_available_out) - 64) else: - # Rough local estimate can overshoot; provider truth - # still allows a minimal retry. + # The rough local estimate can overshoot the real + # request size. Fall back to the provider-reported + # budget, which is authoritative for the failed + # request. safe_out = max(1, available_out - 64) agent._ephemeral_max_output_tokens = safe_out agent._buffer_vprint(