diff --git a/agent/error_classifier.py b/agent/error_classifier.py index bd62005c4c..59b244b7b9 100644 --- a/agent/error_classifier.py +++ b/agent/error_classifier.py @@ -609,10 +609,10 @@ def _moa_special_cases(c: _Ctx) -> Optional[Verdict]: # Local MoA streaming adapter-shape bugs are not a provider outage; falling # back would silently replace the MoA route with a single model (#55933). if c.provider_slug == "moa" and any(s in str(c.error) for s in _MOA_ADAPTER_SHAPE_BUGS): - return _v(_R.format_error, **_ABORT_FALLBACK) + return _v(_R.format_error, retryable=False) # Persisted MoA preset name that was renamed/deleted — deterministic config error. from agent.errors import MoAPresetNotFoundError - return _v(_R.model_not_found, **_ABORT_FALLBACK) if isinstance(c.error, MoAPresetNotFoundError) else None + return _v(_R.model_not_found, retryable=False) if isinstance(c.error, MoAPresetNotFoundError) else None def _by_error_code(c: _Ctx) -> Optional[Verdict]: diff --git a/agent/turn_api_error.py b/agent/turn_api_error.py index df539e8dce..2500048196 100644 --- a/agent/turn_api_error.py +++ b/agent/turn_api_error.py @@ -308,18 +308,18 @@ def settle_unrecovered_error( # ``should_fallback=False`` marks a deterministic failure no other provider can fix (the # model's own malformed tool-call JSON, #12770): skip the cascade. Local validation errors # carry no classifier verdict and keep their historical fallback. - fallback_allowed = classified.should_fallback or is_local_validation_error - # Announce the fallback only when a chain exists, else "trying fallback..." lies - # before a silent abort. - if fallback_allowed and agent._has_pending_fallback(): - _label = _NONRETRYABLE_LABELS.get(classified.reason, f"Non-retryable error (HTTP {status_code})") - agent._buffer_status(f"⚠️ {_label} — trying fallback...") - if fallback_allowed and agent._try_activate_fallback(): - # Direct ``return _verdict("break")`` is load-bearing: the restart handler - # re-runs the pre-API preflight against the fallback's context window. - active_system_prompt = _arm_fallback_restart(agent, api_messages, active_system_prompt, _retry) - retry_count = compression_attempts = 0 - return _verdict("break") + if classified.should_fallback or is_local_validation_error: + # Announce the fallback only when a chain exists, else "trying fallback..." lies + # before a silent abort. + if agent._has_pending_fallback(): + _label = _NONRETRYABLE_LABELS.get(classified.reason, f"Non-retryable error (HTTP {status_code})") + agent._buffer_status(f"⚠️ {_label} — trying fallback...") + if agent._try_activate_fallback(): + # Direct ``return _verdict("break")`` is load-bearing: the restart handler + # re-runs the pre-API preflight against the fallback's context window. + active_system_prompt = _arm_fallback_restart(agent, api_messages, active_system_prompt, _retry) + retry_count = compression_attempts = 0 + return _verdict("break") return _verdict("return", nonretryable_client_error_result( agent, api_error, classified, status_code=status_code, api_kwargs=api_kwargs, api_messages=api_messages, messages=messages, conversation_history=conversation_history,