From dcbcdd6526dc2ebf290dbffabede77967b6eaf6f Mon Sep 17 00:00:00 2001 From: 0z1-ghb <162235745+0z1-ghb@users.noreply.github.com> Date: Thu, 21 May 2026 14:09:30 +0300 Subject: [PATCH] fix(compressor): propagate api_mode and fix root logger calls - Add api_mode to 4 update_model() call sites: - conversation_loop.py: long_context failover and probe stepping - agent_runtime_helpers.py: rollback restore (also saves compressor_api_mode) - chat_completion_helpers.py: fallback activation - Fix 31 root-logger calls across 5 files (logging.warning/error/info -> logger.warning/error/info) to respect module-level log filtering --- agent/agent_runtime_helpers.py | 14 ++++++++------ agent/chat_completion_helpers.py | 17 +++++++++-------- agent/conversation_loop.py | 32 +++++++++++++++++--------------- agent/model_metadata.py | 2 +- agent/tool_executor.py | 2 +- 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index 4175f3e1898..f7c8819eb5e 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -132,7 +132,7 @@ def convert_to_trajectory_format(agent, messages: List[Dict[str, Any]], user_que except json.JSONDecodeError: # This shouldn't happen since we validate and retry during conversation, # but if it does, log warning and use empty dict - logging.warning(f"Unexpected invalid JSON in trajectory conversion: {tool_call['function']['arguments'][:100]}") + logger.warning(f"Unexpected invalid JSON in trajectory conversion: {tool_call['function']['arguments'][:100]}") arguments = {} tool_call_json = { @@ -747,7 +747,7 @@ def try_recover_primary_transport( time.sleep(wait_time) return True except Exception as e: - logging.warning("Primary transport recovery failed: %s", e) + logger.warning("Primary transport recovery failed: %s", e) return False # ── End provider fallback ────────────────────────────────────────────── @@ -910,19 +910,20 @@ def restore_primary_runtime(agent) -> bool: base_url=rt["compressor_base_url"], api_key=rt["compressor_api_key"], provider=rt["compressor_provider"], + api_mode=rt.get("compressor_api_mode", ""), ) # ── Reset fallback chain for the new turn ── agent._fallback_activated = False agent._fallback_index = 0 - logging.info( + logger.info( "Primary runtime restored for new turn: %s (%s)", agent.model, agent.provider, ) return True except Exception as e: - logging.warning("Failed to restore primary runtime: %s", e) + logger.warning("Failed to restore primary runtime: %s", e) return False # Which error types indicate a transient transport failure worth @@ -1093,7 +1094,7 @@ def dump_api_request_debug( return dump_file except Exception as dump_error: if agent.verbose_logging: - logging.warning(f"Failed to dump API request debug payload: {dump_error}") + logger.warning(f"Failed to dump API request debug payload: {dump_error}") return None @@ -1478,6 +1479,7 @@ def switch_model(agent, new_model, new_provider, api_key='', base_url='', api_mo "compressor_api_key": getattr(_cc, "api_key", "") if _cc else "", "compressor_provider": getattr(_cc, "provider", agent.provider) if _cc else agent.provider, "compressor_context_length": _cc.context_length if _cc else 0, + "compressor_api_mode": getattr(_cc, "api_mode", agent.api_mode) if _cc else agent.api_mode, "compressor_threshold_tokens": _cc.threshold_tokens if _cc else 0, } if api_mode == "anthropic_messages": @@ -1509,7 +1511,7 @@ def switch_model(agent, new_model, new_provider, api_key='', base_url='', api_mo agent._fallback_chain = fallback_chain agent._fallback_model = fallback_chain[0] if fallback_chain else None - logging.info( + logger.info( "Model switched in-place: %s (%s) -> %s (%s)", old_model, old_provider, new_model, new_provider, ) diff --git a/agent/chat_completion_helpers.py b/agent/chat_completion_helpers.py index 59e7752a625..602b923a894 100644 --- a/agent/chat_completion_helpers.py +++ b/agent/chat_completion_helpers.py @@ -757,7 +757,7 @@ def try_activate_fallback(agent, reason: "FailoverReason | None" = None) -> bool current_base_url = str(getattr(agent, "base_url", "") or "").rstrip("/").lower() fb_base_url_for_dedup = (fb.get("base_url") or "").strip().rstrip("/").lower() if fb_provider == current_provider and fb_model == current_model: - logging.warning( + logger.warning( "Fallback skip: chain entry %s/%s matches current provider/model", fb_provider, fb_model, ) @@ -768,7 +768,7 @@ def try_activate_fallback(agent, reason: "FailoverReason | None" = None) -> bool and fb_base_url_for_dedup == current_base_url and fb_model == current_model ): - logging.warning( + logger.warning( "Fallback skip: chain entry base_url %s matches current backend", fb_base_url_for_dedup, ) @@ -800,7 +800,7 @@ def try_activate_fallback(agent, reason: "FailoverReason | None" = None) -> bool explicit_base_url=fb_base_url_hint, explicit_api_key=fb_api_key_hint) if fb_client is None: - logging.warning( + logger.warning( "Fallback to %s failed: provider not configured", fb_provider) return agent._try_activate_fallback() # try next in chain @@ -940,19 +940,20 @@ def try_activate_fallback(agent, reason: "FailoverReason | None" = None) -> bool base_url=agent.base_url, api_key=getattr(agent, "api_key", ""), # callable preserved → call_llm provider=agent.provider, + api_mode=agent.api_mode, ) agent._emit_status( f"🔄 Primary model failed — switching to fallback: " f"{fb_model} via {fb_provider}" ) - logging.info( + logger.info( "Fallback activated: %s → %s (%s)", old_model, fb_model, fb_provider, ) return True except Exception as e: - logging.error("Failed to activate fallback %s: %s", fb_model, e) + logger.error("Failed to activate fallback %s: %s", fb_model, e) return agent._try_activate_fallback() # try next in chain @@ -1168,7 +1169,7 @@ def handle_max_iterations(agent, messages: list, api_call_count: int) -> str: final_response = "I reached the iteration limit and couldn't generate a summary." except Exception as e: - logging.warning(f"Failed to get summary response: {e}") + logger.warning(f"Failed to get summary response: {e}") final_response = f"I reached the maximum iterations ({agent.max_iterations}) but couldn't summarize. Error: {str(e)}" return final_response @@ -1197,12 +1198,12 @@ def cleanup_task_resources(agent, task_id: str) -> None: _ra().cleanup_vm(task_id) except Exception as e: if agent.verbose_logging: - logging.warning(f"Failed to cleanup VM for task {task_id}: {e}") + logger.warning(f"Failed to cleanup VM for task {task_id}: {e}") try: _ra().cleanup_browser(task_id) except Exception as e: if agent.verbose_logging: - logging.warning(f"Failed to cleanup browser for task {task_id}: {e}") + logger.warning(f"Failed to cleanup browser for task {task_id}: {e}") diff --git a/agent/conversation_loop.py b/agent/conversation_loop.py index fdf65c07558..c86d1b12425 100644 --- a/agent/conversation_loop.py +++ b/agent/conversation_loop.py @@ -1183,7 +1183,7 @@ def run_conversation( else str(_codex_error_obj) if _codex_error_obj else f"Responses API returned status '{_codex_resp_status}'" ) - logging.warning( + logger.warning( "Codex response status='%s' (error=%s). Routing to fallback. %s", _codex_resp_status, _codex_error_msg, agent._client_log_context(), @@ -1335,7 +1335,7 @@ def run_conversation( primary_recovery_attempted = False continue agent._emit_status(f"❌ Max retries ({max_retries}) exceeded for invalid responses. Giving up.") - logging.error(f"{agent.log_prefix}Invalid API response after {max_retries} retries.") + logger.error(f"{agent.log_prefix}Invalid API response after {max_retries} retries.") agent._persist_session(messages, conversation_history) return { "messages": messages, @@ -1348,7 +1348,7 @@ def run_conversation( # Backoff before retry — jittered exponential: 5s base, 120s cap wait_time = jittered_backoff(retry_count, base_delay=5.0, max_delay=120.0) agent._vprint(f"{agent.log_prefix}⏳ Retrying in {wait_time:.1f}s ({_failure_hint})...", force=True) - logging.warning(f"Invalid API response (retry {retry_count}/{max_retries}): {', '.join(error_details)} | Provider: {provider_name}") + logger.warning(f"Invalid API response (retry {retry_count}/{max_retries}): {', '.join(error_details)} | Provider: {provider_name}") # Sleep in small increments to stay responsive to interrupts sleep_end = time.time() + wait_time @@ -2225,7 +2225,7 @@ def run_conversation( f"stripped all thinking blocks, retrying...", force=True, ) - logging.warning( + logger.warning( "%sThinking block signature recovery: stripped " "reasoning_details from %d messages", agent.log_prefix, len(messages), @@ -2250,7 +2250,7 @@ def run_conversation( from tools.schema_sanitizer import strip_pattern_and_format _, _stripped = strip_pattern_and_format(agent.tools) except Exception as _strip_exc: # pragma: no cover — defensive - logging.warning( + logger.warning( "%sllama.cpp grammar recovery: strip helper failed: %s", agent.log_prefix, _strip_exc, ) @@ -2261,7 +2261,7 @@ def run_conversation( f"stripped {_stripped} pattern/format keyword(s), retrying...", force=True, ) - logging.warning( + logger.warning( "%sllama.cpp grammar recovery: stripped %d " "pattern/format keyword(s) from tool schemas", agent.log_prefix, _stripped, @@ -2269,7 +2269,7 @@ def run_conversation( continue # No keywords found to strip — fall through to normal # retry path rather than loop forever on the same error. - logging.warning( + logger.warning( "%sllama.cpp grammar error but no pattern/format " "keywords to strip — falling through to normal retry", agent.log_prefix, @@ -2370,6 +2370,7 @@ def run_conversation( base_url=agent.base_url, api_key=getattr(agent, "api_key", ""), provider=agent.provider, + api_mode=agent.api_mode, ) # Context probing flags — only set on built-in # compressor (plugin engines manage their own). @@ -2483,7 +2484,7 @@ def run_conversation( error_context=error_context, ) else: - logging.info( + logger.info( "Nous 429 looks like upstream capacity " "(no exhausted bucket in headers or " "last-known state) -- not tripping " @@ -2543,7 +2544,7 @@ def run_conversation( if compression_attempts > max_compression_attempts: agent._vprint(f"{agent.log_prefix}❌ Max compression attempts ({max_compression_attempts}) reached for payload-too-large error.", force=True) agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True) - logging.error(f"{agent.log_prefix}413 compression failed after {max_compression_attempts} attempts.") + logger.error(f"{agent.log_prefix}413 compression failed after {max_compression_attempts} attempts.") agent._persist_session(messages, conversation_history) return { "messages": messages, @@ -2574,7 +2575,7 @@ def run_conversation( else: agent._vprint(f"{agent.log_prefix}❌ Payload too large and cannot compress further.", force=True) agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True) - logging.error(f"{agent.log_prefix}413 payload too large. Cannot compress further.") + logger.error(f"{agent.log_prefix}413 payload too large. Cannot compress further.") agent._persist_session(messages, conversation_history) return { "messages": messages, @@ -2627,7 +2628,7 @@ def run_conversation( if compression_attempts > max_compression_attempts: agent._vprint(f"{agent.log_prefix}❌ Max compression attempts ({max_compression_attempts}) reached.", force=True) agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True) - logging.error(f"{agent.log_prefix}Context compression failed after {max_compression_attempts} attempts.") + logger.error(f"{agent.log_prefix}Context compression failed after {max_compression_attempts} attempts.") agent._persist_session(messages, conversation_history) return { "messages": messages, @@ -2679,6 +2680,7 @@ def run_conversation( base_url=agent.base_url, api_key=getattr(agent, "api_key", ""), provider=agent.provider, + api_mode=agent.api_mode, ) # Context probing flags — only set on built-in # compressor (plugin engines manage their own). @@ -2700,7 +2702,7 @@ def run_conversation( if compression_attempts > max_compression_attempts: agent._vprint(f"{agent.log_prefix}❌ Max compression attempts ({max_compression_attempts}) reached.", force=True) agent._vprint(f"{agent.log_prefix} 💡 Try /new to start a fresh conversation, or /compress to retry compression.", force=True) - logging.error(f"{agent.log_prefix}Context compression failed after {max_compression_attempts} attempts.") + logger.error(f"{agent.log_prefix}Context compression failed after {max_compression_attempts} attempts.") agent._persist_session(messages, conversation_history) return { "messages": messages, @@ -2733,7 +2735,7 @@ def run_conversation( # Can't compress further and already at minimum tier agent._vprint(f"{agent.log_prefix}❌ Context length exceeded and cannot compress further.", force=True) agent._vprint(f"{agent.log_prefix} 💡 The conversation has accumulated too much content. Try /new to start fresh, or /compress to manually trigger compression.", force=True) - logging.error(f"{agent.log_prefix}Context length exceeded: {approx_tokens:,} tokens. Cannot compress further.") + logger.error(f"{agent.log_prefix}Context length exceeded: {approx_tokens:,} tokens. Cannot compress further.") agent._persist_session(messages, conversation_history) return { "messages": messages, @@ -2826,7 +2828,7 @@ def run_conversation( agent._vprint(f"{agent.log_prefix} • Check credits: https://openrouter.ai/settings/credits", force=True) else: agent._vprint(f"{agent.log_prefix} 💡 This type of error won't be fixed by retrying.", force=True) - logging.error(f"{agent.log_prefix}Non-retryable client error: {api_error}") + logger.error(f"{agent.log_prefix}Non-retryable client error: {api_error}") # Skip session persistence when the error is likely # context-overflow related (status 400 + large session). # Persisting the failed user message would make the @@ -2903,7 +2905,7 @@ def run_conversation( force=True, ) - logging.error( + logger.error( "%sAPI call failed after %s retries. %s | provider=%s model=%s msgs=%s tokens=~%s", agent.log_prefix, max_retries, _final_summary, _provider, _model, len(api_messages), f"{approx_tokens:,}", diff --git a/agent/model_metadata.py b/agent/model_metadata.py index 3d6216f6beb..e9ec4bf03a7 100644 --- a/agent/model_metadata.py +++ b/agent/model_metadata.py @@ -641,7 +641,7 @@ def fetch_model_metadata(force_refresh: bool = False) -> Dict[str, Dict[str, Any return cache except Exception as e: - logging.warning(f"Failed to fetch model metadata from OpenRouter: {e}") + logger.warning(f"Failed to fetch model metadata from OpenRouter: {e}") return _model_metadata_cache or {} diff --git a/agent/tool_executor.py b/agent/tool_executor.py index b161b507e8d..e350994b4dc 100644 --- a/agent/tool_executor.py +++ b/agent/tool_executor.py @@ -491,7 +491,7 @@ def execute_tool_calls_sequential(agent, assistant_message, messages: list, effe try: function_args = json.loads(tool_call.function.arguments) except json.JSONDecodeError as e: - logging.warning(f"Unexpected JSON error after validation: {e}") + logger.warning(f"Unexpected JSON error after validation: {e}") function_args = {} if not isinstance(function_args, dict): function_args = {}