fix(agent): Kimi Code fallbacks use the Anthropic Messages wire (#77256)

`try_activate_fallback` derived the fallback api_mode with its own host
heuristic (api.anthropic.com / trailing `/anthropic`) that lagged the
primary path's `_detect_api_mode_for_url()`: a `fallback_providers` entry
pointing at `api.kimi.com/coding` activated but POSTed OpenAI-shaped
`/chat/completions`, which that endpoint 404s, so every fallback turn
failed after the chain had correctly switched.

Route `_is_anthropic_wire_url` through `providers.host_mandated_api_mode`
— the single Messages-only host table the primary path already uses — so
the fallback path can never drift from it again. Exact-hostname match
rejects `api.kimi.com.attacker.test`.

Salvaged from #77304 by @RelaxJonh (original detection branch).
This commit is contained in:
RelaxJonh
2026-09-05 14:29:10 +05:30
committed by kshitij
parent d20a8e4475
commit 4ee2c78324
+4 -2
View File
@@ -1797,8 +1797,10 @@ def _fallback_reason_text(reason: "FailoverReason | None") -> str:
def _is_anthropic_wire_url(url: str) -> bool:
"""Same host match as determine_api_mode() / _detect_api_mode_for_url()."""
return url.rstrip("/").lower().endswith("/anthropic") or base_url_hostname(url) == "api.anthropic.com"
"""Same Messages-only host match as determine_api_mode() / _detect_api_mode_for_url(): api.anthropic.com,
a /anthropic suffix, or Kimi Code's api.kimi.com/coding (its /chat/completions 404s — #77256)."""
from hermes_cli.providers import host_mandated_api_mode
return host_mandated_api_mode(url) == "anthropic_messages"
def _fallback_api_mode_hint(fb: dict, fb_provider: str, fb_base_url_hint: Optional[str]) -> tuple[bool, str]: