From 9981242f883de7acf50a6abc1532d6868d648f80 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:23:27 -0700 Subject: [PATCH] fix(gateway): widen compression noise filter to all routine status lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-sweep audit of every compression status emission (conversation_loop, turn_context, conversation_compression): the buffered overflow/attempt-cap retry chatter (πŸ—œοΈ 'Context too large…', 'Compressed X β†’ Y, retrying…', 'Context reduced to…'), the #69332-reworded auto-lower notice ("Auto-lowered this session's threshold…"), the aux-provider-unavailable notice, and the concurrent-compression skip all leaked past _TELEGRAM_NOISY_STATUS_RE on chat platforms. Add anchored alternatives for each; the ', retrying'/'β€” compressing' anchors keep manual /compress feedback ('Compressed: 30 β†’ 12 messages') and failure/abort notices visible per the deliberate carve-outs. Also extract every routine compression status string into importable template constants in agent/conversation_compression.py (single source of truth shared by all emission sites), so tests can iterate the actual emitted wording instead of hand-copied literals. --- agent/conversation_compression.py | 52 +++++++++++++++++++++++++++++++ agent/conversation_loop.py | 29 +++++++++++------ agent/turn_context.py | 18 +++++++---- gateway/run.py | 13 ++++++++ 4 files changed, 96 insertions(+), 16 deletions(-) diff --git a/agent/conversation_compression.py b/agent/conversation_compression.py index 33aa074ecbd..04206a40721 100644 --- a/agent/conversation_compression.py +++ b/agent/conversation_compression.py @@ -71,6 +71,58 @@ def _emit_compaction_done(agent: Any) -> None: logger.debug("status_callback error in compaction completion", exc_info=True) +# ── Routine compression status templates ──────────────────────────────────── +# Every ROUTINE (non-failure, non-manual-/compress) compression status line the +# agent emits lives here so the gateway noise filter and its tests can couple +# to the real emitted wording instead of hand-copied literals. These are +# suppressed on human-facing chat platforms by _TELEGRAM_NOISY_STATUS_RE +# (gateway/run.py) β€” when rewording ANY of them, update that regex and the +# pinned data in tests/gateway/test_telegram_noise_filter.py in the same PR. +# Failure notices (⚠ Compression aborted / empty transcript / codex compaction +# failed) and manual /compress feedback (manual_compression_feedback.py) are +# deliberate carve-outs from silence and must NOT be added here. +PRE_API_COMPRESSION_STATUS_TEMPLATE = ( + "πŸ“¦ Pre-API compression: ~{tokens:,} tokens " + "near the context/output limit. Compacting before the next model call." +) +PREFLIGHT_COMPRESSION_STATUS_TEMPLATE = ( + "πŸ“¦ Preflight compression: ~{tokens:,} tokens " + ">= {threshold:,} threshold. This may take a moment." +) +IDLE_COMPACTION_STATUS_TEMPLATE = ( + "πŸ’€ Resumed after {idle_seconds}s idle β€” compacting " + "~{tokens:,} tokens before continuing." +) +COMPRESSION_RETRY_TOO_LARGE_STATUS_TEMPLATE = ( + "πŸ—œοΈ Context too large (~{tokens:,} tokens) β€” compressing ({attempt}/{cap})..." +) +COMPRESSION_RETRY_MESSAGES_STATUS_TEMPLATE = ( + "πŸ—œοΈ Compressed {before} β†’ {after} messages, retrying..." +) +COMPRESSION_RETRY_TOKENS_STATUS_TEMPLATE = ( + "πŸ—œοΈ Compressed ~{before:,} β†’ ~{after:,} tokens, retrying..." +) +COMPRESSION_RETRY_CONTEXT_REDUCED_STATUS_TEMPLATE = ( + "πŸ—œοΈ Context reduced to {new_ctx:,} tokens (was {old_ctx:,}), retrying..." +) + +# Sample-formatted instances of every routine compression status line, for +# behavioral tests that iterate the ACTUAL emitted wording (formatted from the +# same constants the emission sites use) through the gateway noise filter. +ROUTINE_COMPRESSION_STATUS_SAMPLES = ( + COMPACTION_STATUS, + PRE_API_COMPRESSION_STATUS_TEMPLATE.format(tokens=123456), + PREFLIGHT_COMPRESSION_STATUS_TEMPLATE.format(tokens=120000, threshold=100000), + IDLE_COMPACTION_STATUS_TEMPLATE.format(idle_seconds=3600, tokens=120000), + COMPRESSION_RETRY_TOO_LARGE_STATUS_TEMPLATE.format(tokens=250000, attempt=1, cap=3), + COMPRESSION_RETRY_MESSAGES_STATUS_TEMPLATE.format(before=30, after=12), + COMPRESSION_RETRY_TOKENS_STATUS_TEMPLATE.format(before=250000, after=120000), + COMPRESSION_RETRY_CONTEXT_REDUCED_STATUS_TEMPLATE.format( + new_ctx=120000, old_ctx=250000 + ), +) + + def _builtin_memory_prompt_snapshot(agent: Any) -> Optional[Tuple[str, str]]: """Return the built-in memory text that can affect a system prompt. diff --git a/agent/conversation_loop.py b/agent/conversation_loop.py index fb9d11b66fc..f31d3c54a33 100644 --- a/agent/conversation_loop.py +++ b/agent/conversation_loop.py @@ -28,7 +28,14 @@ import uuid from typing import Any, Dict, List, Optional from agent.codex_responses_adapter import _summarize_user_message_for_log -from agent.conversation_compression import conversation_history_after_compression +from agent.conversation_compression import ( + COMPRESSION_RETRY_CONTEXT_REDUCED_STATUS_TEMPLATE, + COMPRESSION_RETRY_MESSAGES_STATUS_TEMPLATE, + COMPRESSION_RETRY_TOKENS_STATUS_TEMPLATE, + COMPRESSION_RETRY_TOO_LARGE_STATUS_TEMPLATE, + PRE_API_COMPRESSION_STATUS_TEMPLATE, + conversation_history_after_compression, +) from agent.display import KawaiiSpinner from agent.error_classifier import FailoverReason, classify_api_error from agent.iteration_budget import IterationBudget @@ -1279,8 +1286,9 @@ def run_conversation( max_compression_attempts, ) agent._emit_status( - f"πŸ“¦ Pre-API compression: ~{request_pressure_tokens:,} tokens " - f"near the context/output limit. Compacting before the next model call." + PRE_API_COMPRESSION_STATUS_TEMPLATE.format( + tokens=request_pressure_tokens + ) ) _last_preflight_pressure = request_pressure_tokens messages, active_system_prompt = agent._compress_context( @@ -3494,8 +3502,9 @@ def run_conversation( ) if len(messages) < original_len or old_ctx > _reduced_ctx: agent._buffer_status( - f"πŸ—œοΈ Context reduced to {_reduced_ctx:,} tokens " - f"(was {old_ctx:,}), retrying..." + COMPRESSION_RETRY_CONTEXT_REDUCED_STATUS_TEMPLATE.format( + new_ctx=_reduced_ctx, old_ctx=old_ctx + ) ) time.sleep(2) _retry.restart_with_compressed_messages = True @@ -3756,9 +3765,9 @@ def run_conversation( if len(messages) < original_len or (new_tokens > 0 and new_tokens < original_tokens * 0.95): if len(messages) < original_len: - agent._buffer_status(f"πŸ—œοΈ Compressed {original_len} β†’ {len(messages)} messages, retrying...") + agent._buffer_status(COMPRESSION_RETRY_MESSAGES_STATUS_TEMPLATE.format(before=original_len, after=len(messages))) else: - agent._buffer_status(f"πŸ—œοΈ Compressed ~{original_tokens:,} β†’ ~{new_tokens:,} tokens, retrying...") + agent._buffer_status(COMPRESSION_RETRY_TOKENS_STATUS_TEMPLATE.format(before=original_tokens, after=new_tokens)) time.sleep(2) # Brief pause between compression retries _retry.restart_with_compressed_messages = True break @@ -3976,7 +3985,7 @@ def run_conversation( "failed": True, "compression_exhausted": True, } - agent._buffer_status(f"πŸ—œοΈ Context too large (~{approx_tokens:,} tokens) β€” compressing ({compression_attempts}/{max_compression_attempts})...") + agent._buffer_status(COMPRESSION_RETRY_TOO_LARGE_STATUS_TEMPLATE.format(tokens=approx_tokens, attempt=compression_attempts, cap=max_compression_attempts)) original_len = len(messages) original_tokens = estimate_messages_tokens_rough(messages) @@ -3997,9 +4006,9 @@ def run_conversation( if len(messages) < original_len or (new_tokens > 0 and new_tokens < original_tokens * 0.95) or (new_ctx and new_ctx < old_ctx): if len(messages) < original_len: - agent._buffer_status(f"πŸ—œοΈ Compressed {original_len} β†’ {len(messages)} messages, retrying...") + agent._buffer_status(COMPRESSION_RETRY_MESSAGES_STATUS_TEMPLATE.format(before=original_len, after=len(messages))) elif new_tokens > 0 and new_tokens < original_tokens * 0.95: - agent._buffer_status(f"πŸ—œοΈ Compressed ~{original_tokens:,} β†’ ~{new_tokens:,} tokens, retrying...") + agent._buffer_status(COMPRESSION_RETRY_TOKENS_STATUS_TEMPLATE.format(before=original_tokens, after=new_tokens)) time.sleep(2) # Brief pause between compression retries _retry.restart_with_compressed_messages = True break diff --git a/agent/turn_context.py b/agent/turn_context.py index 11f402ba488..59451837092 100644 --- a/agent/turn_context.py +++ b/agent/turn_context.py @@ -31,7 +31,11 @@ import uuid from dataclasses import dataclass from typing import Any, Dict, List, Mapping, Optional -from agent.conversation_compression import conversation_history_after_compression +from agent.conversation_compression import ( + IDLE_COMPACTION_STATUS_TEMPLATE, + PREFLIGHT_COMPRESSION_STATUS_TEMPLATE, + conversation_history_after_compression, +) from agent.iteration_budget import IterationBudget from agent.memory_manager import build_memory_context_block from agent.model_metadata import ( @@ -659,8 +663,9 @@ def build_turn_context( agent.session_id or "none", ) agent._emit_status( - f"πŸ’€ Resumed after {int(_idle_gap)}s idle β€” compacting " - f"~{_idle_tokens:,} tokens before continuing." + IDLE_COMPACTION_STATUS_TEMPLATE.format( + idle_seconds=int(_idle_gap), tokens=_idle_tokens + ) ) _idle_input = messages messages, active_system_prompt = agent._compress_context( @@ -767,9 +772,10 @@ def build_turn_context( f"{_compressor.context_length:,}", ) agent._emit_status( - f"πŸ“¦ Preflight compression: ~{_preflight_tokens:,} tokens " - f">= {_compressor.threshold_tokens:,} threshold. " - "This may take a moment." + PREFLIGHT_COMPRESSION_STATUS_TEMPLATE.format( + tokens=_preflight_tokens, + threshold=_compressor.threshold_tokens, + ) ) # Preflight passes honor the same configured per-turn cap # (compression.max_attempts) as the loop's compression sites; diff --git a/gateway/run.py b/gateway/run.py index 5699a63c2d7..fee4692821e 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -79,10 +79,23 @@ _TELEGRAM_NOISY_STATUS_RE = re.compile( r"|configured\s+compression\s+model\s+.+\s+failed" r"|no\s+auxiliary\s+llm\s+provider\s+configured" r"|auto-lowered\s+compression\s+threshold" + # #69332 reworded the auto-lower notice to "Auto-lowered this session's + # threshold to N tokens" β€” keep both generations covered. + r"|auto-lowered\s+(?:this\s+)?session'?s?\s+threshold" + r"|configured\s+auxiliary\s+compression\s+provider\s+.+\s+unavailable" + r"|skipping\s+concurrent\s+compression" r"|compacting\s+context\s+[β€”-]\s+summarizing\s+earlier\s+conversation" r"|resumed\s+after\s+\d+s\s+idle\s+[β€”-]\s+compacting" r"|preflight\s+compression" r"|pre[- ]api\s+compression" + # Buffered attempt/overflow retry chatter replayed through _emit_status + # when a turn exhausts retries. The ", retrying"/"β€” compressing" anchors + # keep manual /compress feedback ("Compressed: 30 β†’ 12 messages") and + # failure notices out of the match. + r"|context\s+too\s+large\s+\(~[\d,]+\s+tokens\)\s+[β€”-]+\s+compressing" + r"|compressed\s+\d[\d,]*\s+(?:β†’|->)\s+\d[\d,]*\s+messages,\s+retrying" + r"|compressed\s+~[\d,]+\s+(?:β†’|->)\s+~[\d,]+\s+tokens,\s+retrying" + r"|context\s+reduced\s+to\s+[\d,]+\s+tokens\s+\(was\s+[\d,]+\),\s+retrying" r"|session\s+compressed\s+\d+\s+times" r"|rate\s+limited\.\s+waiting\s+\d" r"|retrying\s+in\s+\d"