From 4ee2c783244f52f9ffd6fbf40904cc148c199240 Mon Sep 17 00:00:00 2001 From: RelaxJonh <92573950+RelaxJonh@users.noreply.github.com> Date: Sat, 5 Sep 2026 14:29:10 +0530 Subject: [PATCH] fix(agent): Kimi Code fallbacks use the Anthropic Messages wire (#77256) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `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). --- agent/chat_completion_helpers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/agent/chat_completion_helpers.py b/agent/chat_completion_helpers.py index 366931ed95..98f4f25677 100644 --- a/agent/chat_completion_helpers.py +++ b/agent/chat_completion_helpers.py @@ -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]: