diff --git a/hermes_cli/model_switch.py b/hermes_cli/model_switch.py index 22721f9a4..5b26f5b8b 100644 --- a/hermes_cli/model_switch.py +++ b/hermes_cli/model_switch.py @@ -678,6 +678,7 @@ def switch_model( _da = DIRECT_ALIASES.get(resolved_alias) if _da is not None and _da.base_url: base_url = _da.base_url + api_mode = "" # clear so determine_api_mode re-detects from URL if not api_key: api_key = "no-key-required" diff --git a/hermes_cli/providers.py b/hermes_cli/providers.py index 1764474aa..00c3f64bc 100644 --- a/hermes_cli/providers.py +++ b/hermes_cli/providers.py @@ -427,6 +427,16 @@ def determine_api_mode(provider: str, base_url: str = "") -> str: """ pdef = get_provider(provider) if pdef is not None: + # Even for known providers, check URL heuristics for special endpoints + # (e.g. kimi /coding endpoint needs anthropic_messages even on 'custom') + if base_url: + url_lower = base_url.rstrip("/").lower() + if "api.kimi.com/coding" in url_lower: + return "anthropic_messages" + if url_lower.endswith("/anthropic") or "api.anthropic.com" in url_lower: + return "anthropic_messages" + if "api.openai.com" in url_lower: + return "codex_responses" return TRANSPORT_TO_API_MODE.get(pdef.transport, "chat_completions") # Direct provider checks for providers not in HERMES_OVERLAYS @@ -439,6 +449,8 @@ def determine_api_mode(provider: str, base_url: str = "") -> str: hostname = base_url_hostname(base_url) if url_lower.endswith("/anthropic") or hostname == "api.anthropic.com": return "anthropic_messages" + if hostname == "api.kimi.com" and "/coding" in url_lower: + return "anthropic_messages" if hostname == "api.openai.com": return "codex_responses" if hostname.startswith("bedrock-runtime.") and base_url_host_matches(base_url, "amazonaws.com"): diff --git a/run_agent.py b/run_agent.py index c5966a173..4f431bb6a 100644 --- a/run_agent.py +++ b/run_agent.py @@ -1175,7 +1175,7 @@ class AIAgent: client_kwargs["default_headers"] = copilot_default_headers() elif base_url_host_matches(effective_base, "api.kimi.com"): client_kwargs["default_headers"] = { - "User-Agent": "KimiCLI/1.30.0", + "User-Agent": "claude-code/0.1.0", } elif base_url_host_matches(effective_base, "portal.qwen.ai"): client_kwargs["default_headers"] = _qwen_portal_headers() @@ -5049,7 +5049,7 @@ class AIAgent: self._client_kwargs["default_headers"] = copilot_default_headers() elif base_url_host_matches(base_url, "api.kimi.com"): - self._client_kwargs["default_headers"] = {"User-Agent": "KimiCLI/1.30.0"} + self._client_kwargs["default_headers"] = {"User-Agent": "claude-code/0.1.0"} elif base_url_host_matches(base_url, "portal.qwen.ai"): self._client_kwargs["default_headers"] = _qwen_portal_headers() elif base_url_host_matches(base_url, "chatgpt.com"):