fix(agent): keep MoA verdicts fallback-free; nest the gated fallback under one if

Two CI regressions from the previous commit, both mine:

- `_moa_special_cases` was switched to `_ABORT_FALLBACK`, which flips
  `should_fallback` to True for the MoA adapter-shape and missing-preset
  verdicts. #55933 made those deliberately NOT fall back (a fallback would
  silently replace the MoA route with a single model); restore
  `retryable=False` only. The gate in `settle_unrecovered_error` now honours
  that for real: on main these verdicts never reached the fallback branch
  because the flag was never consulted.
- `tests/agent/test_prompt_cache_ttl_propagation.py` pins every
  `_try_activate_fallback` reference to a direct `if agent._try_activate_fallback():`
  site (#84733 restart discipline); `fallback_allowed and agent._try_activate_fallback()`
  broke that shape. Nest the two calls under one `if should_fallback or local_validation:`
  block instead.
This commit is contained in:
teknium1
2026-09-12 07:45:27 -07:00
committed by Teknium
parent dfd4aa4a94
commit 293cb54f28
2 changed files with 14 additions and 14 deletions

View File

@@ -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]:

View File

@@ -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,