fix(providers): pin all Actual routes to chat completions (E-1047)
This commit is contained in:
@@ -936,6 +936,9 @@ def _to_openai_base_url(base_url: str) -> str:
|
||||
without it). Anthropic-only gateways keep their path.
|
||||
"""
|
||||
url = str(base_url or "").strip().rstrip("/")
|
||||
if base_url_hostname(url) == "api.actual.inc":
|
||||
from hermes_cli.auth import normalize_actual_base_url
|
||||
return normalize_actual_base_url(url)
|
||||
if url.endswith("/anthropic"):
|
||||
if base_url_host_matches(url, "open.bigmodel.cn") or base_url_host_matches(url, "api.z.ai"):
|
||||
rewritten = url[: -len("/anthropic")] + "/coding/paas/v4"
|
||||
@@ -4469,12 +4472,32 @@ def _log_once_debug(seen: set, key: Any, msg: str, *args: Any) -> None:
|
||||
logger.debug(msg, *args)
|
||||
|
||||
|
||||
def _is_actual_auxiliary_route(req: _ResolveRequest, base_url: str) -> bool:
|
||||
from hermes_cli.auth import normalize_actual_base_url
|
||||
from hermes_cli.providers import is_actual_route
|
||||
from hermes_cli.route_identity import normalize_route_base_url
|
||||
|
||||
if is_actual_route(req.provider, base_url):
|
||||
return True
|
||||
runtime = _normalize_main_runtime(req.main_runtime)
|
||||
return bool(
|
||||
base_url
|
||||
and is_actual_route(runtime.get("provider", ""), runtime.get("base_url", ""))
|
||||
and normalize_route_base_url(normalize_actual_base_url(base_url))
|
||||
== normalize_route_base_url(
|
||||
normalize_actual_base_url(runtime.get("base_url", ""))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _wrap_transport(req: _ResolveRequest, client_obj: Any, final_model_str: str,
|
||||
base_url_str: str = "", api_key_str: str = ""):
|
||||
"""Wrap a plain OpenAI client in the right transport adapter; specialized wrappers pass through.
|
||||
Codex (Responses API): explicit ``api_mode=codex_responses``, else — with no
|
||||
explicit api_mode — api.openai.com + codex model. Anthropic (Messages): ``api_mode=anthropic_messages``,
|
||||
any ``/anthropic`` suffix, ``api.kimi.com/coding``, or ``api.anthropic.com``."""
|
||||
if _is_actual_auxiliary_route(req, base_url_str):
|
||||
return client_obj._real_client if isinstance(client_obj, CodexAuxiliaryClient) else client_obj
|
||||
needs_codex = not (isinstance(client_obj, CodexAuxiliaryClient) or req.raw_codex) and (
|
||||
req.api_mode == "codex_responses"
|
||||
or (not req.api_mode and base_url_hostname(base_url_str) == "api.openai.com"
|
||||
@@ -4616,6 +4639,9 @@ def _resolve_custom_branch(req: _ResolveRequest) -> _ResolveResult:
|
||||
if _main_base and _main_key:
|
||||
custom_base, custom_key = _main_base, _main_key
|
||||
if custom_base and custom_key:
|
||||
if _is_actual_auxiliary_route(req, custom_base):
|
||||
from hermes_cli.auth import normalize_actual_base_url
|
||||
custom_base = normalize_actual_base_url(custom_base)
|
||||
final_model = _normalize_resolved_model(
|
||||
model or (main_runtime.get("model") if main_runtime else None) or "gpt-4o-mini", provider,
|
||||
)
|
||||
@@ -4678,8 +4704,12 @@ def _resolve_named_custom_branch(req: _ResolveRequest) -> Optional[_ResolveResul
|
||||
logger.warning("resolve_provider_client: named custom provider %r has no resolvable "
|
||||
"api_key — request will be sent with placeholder no-key-required "
|
||||
"and will 401 on auth-required endpoints", custom_entry.get("name") or provider)
|
||||
# Explicit per-task api_mode override wins over the provider entry's.
|
||||
# Actual's wire protocol takes precedence over persisted task/provider modes.
|
||||
entry_api_mode = (req.api_mode or custom_entry.get("api_mode") or "").strip()
|
||||
if _is_actual_auxiliary_route(req, custom_base):
|
||||
from hermes_cli.auth import normalize_actual_base_url
|
||||
custom_base = normalize_actual_base_url(custom_base)
|
||||
entry_api_mode = "chat_completions"
|
||||
if not custom_base:
|
||||
logger.warning("resolve_provider_client: named custom provider %r has no base_url", provider)
|
||||
return None, None
|
||||
@@ -4766,7 +4796,7 @@ def _resolve_api_key_branch(req: _ResolveRequest, pconfig: Any, resolve_creds: C
|
||||
return None, None
|
||||
base_url = _to_openai_base_url(raw_base_url)
|
||||
# Explicit base_url override: a fallback_model/custom_providers entry pointing a built-in name elsewhere.
|
||||
if req.explicit_base_url:
|
||||
if req.explicit_base_url and provider != "actual":
|
||||
base_url = _to_openai_base_url(req.explicit_base_url.strip().rstrip("/"))
|
||||
final_model = _normalize_resolved_model(req.model or _get_aux_model_for_provider(provider), provider)
|
||||
if provider == "gemini":
|
||||
|
||||
Reference in New Issue
Block a user