"""``auth_type`` dispatch table for the auxiliary registry branch. ``_resolve_registry_branch`` in ``agent/auxiliary_client`` routes every ``PROVIDER_REGISTRY`` provider here on its registered ``auth_type``; this table is the registry twin of the facade's ``_EXPLICIT_PROVIDER_BRANCHES``. Arms late-import the facade (siblings never form a module-level cycle) so the seam every test patches — ``agent.auxiliary_client.*`` — is the module production reads. """ from __future__ import annotations import logging from typing import TYPE_CHECKING, Callable, Dict if TYPE_CHECKING: from agent.auxiliary_client import _ResolveRequest, _ResolveResult logger = logging.getLogger("agent.auxiliary_client") # First occurrence surfaces for diagnostics; per-call retries stay silent (the # contract test_auxiliary_client_resolve_dedup.py pins for every fall-through). _LOGGED_MINIMAX_ABSENT_KEYS: set = set() _LOGGED_MINIMAX_UNEXPECTED_KEYS: set = set() def _resolve_vertex_arm(req: _ResolveRequest) -> _ResolveResult: from agent.auxiliary_client import _build_vertex_client, _route_client client, final_model = _build_vertex_client(req.provider, req.model) return _route_client(req, client, final_model) if client is not None else (None, None) def _resolve_bedrock_arm(req: _ResolveRequest) -> _ResolveResult: from agent.auxiliary_client import _build_bedrock_client, _route_client client, final_model = _build_bedrock_client(req.provider, req.model, raw_codex=req.raw_codex) return _route_client(req, client, final_model) if client is not None else (None, None) def _log_once_debug(seen: set, key: str, msg: str, *args: object) -> None: if key not in seen: seen.add(key) logger.debug(msg, *args) def _resolve_minimax_oauth_arm(req: _ResolveRequest) -> _ResolveResult: """``minimax-oauth`` → AnthropicAuxiliaryClient over a callable bearer; (None, None) when absent. MiniMax OAuth resolves to an Anthropic-compatible inference endpoint with a callable bearer: tokens live ~15 minutes and the Anthropic SDK re-invokes the provider on each request, so a static string would 401 mid-session. ``is_oauth`` comes from ``anthropic_route_is_oauth`` — the MiniMax host is a third-party Anthropic-protocol endpoint, so the wrapper must NOT carry the native Claude Code OAuth identity (mcp__ tool-name wire transforms, identity rewrites, response prefix stripping); those are api.anthropic.com-only (#114967). """ from hermes_cli.auth_constants import AuthError from agent.auxiliary_client import ( AnthropicAuxiliaryClient, _AuxProbeClientStub, _aux_probe_active, _get_aux_model_for_provider, _normalize_resolved_model, _route_client, ) from agent.anthropic_credentials import anthropic_route_is_oauth from hermes_cli.auth import get_provider_auth_state, resolve_minimax_oauth_runtime_credentials # Probe mode answers "resolvable?" for availability gates and must not touch the # network: read the raw persisted state (access_token + inference_base_url present → # stub) and skip the refresh an expired token would otherwise trigger (mirrors # credential_pool.py::_seed_minimax_singleton). if _aux_probe_active(): state = get_provider_auth_state("minimax-oauth") base_url = str((state or {}).get("inference_base_url") or "").strip().rstrip("/") if not ((state or {}).get("access_token") and base_url): _log_once_debug(_LOGGED_MINIMAX_ABSENT_KEYS, "minimax-oauth", "resolve_provider_client: minimax-oauth not logged in") return None, None final_model = _normalize_resolved_model( req.model or _get_aux_model_for_provider(req.provider) or "MiniMax-M3", req.provider, ) return _route_client(req, _AuxProbeClientStub(api_key="", base_url=base_url), final_model) try: credentials = resolve_minimax_oauth_runtime_credentials(as_token_provider=True) except AuthError as exc: # Expected absent/not-logged-in/quarantined states: the resolver contract is # "absent → (None, None), never an exception" (the aux ladder then falls through # to its Step-2 chain). Debug-once, like every other fall-through — a per-call # WARNING would recreate the #21521 log spam once a quarantine wipes the tokens. _log_once_debug(_LOGGED_MINIMAX_ABSENT_KEYS, "minimax-oauth", "resolve_provider_client: minimax-oauth unavailable: %s", exc) return None, None except Exception as exc: # Deliberate boundary (BLE001): a genuinely unexpected failure still ends the arm # with (None, None) — never an exception into the aux ladder — but keeps the # traceback, logged once. if "minimax-oauth" not in _LOGGED_MINIMAX_UNEXPECTED_KEYS: _LOGGED_MINIMAX_UNEXPECTED_KEYS.add("minimax-oauth") logger.warning( "resolve_provider_client: unexpected minimax-oauth resolution failure: %s", exc, exc_info=True) return None, None token_provider = credentials.get("api_key") base_url = str(credentials.get("base_url") or "").strip().rstrip("/") if not callable(token_provider) or not base_url: _log_once_debug(_LOGGED_MINIMAX_ABSENT_KEYS, "minimax-oauth", "resolve_provider_client: minimax-oauth credentials incomplete") return None, None final_model = _normalize_resolved_model( req.model or _get_aux_model_for_provider(req.provider) or "MiniMax-M3", req.provider, ) from agent.anthropic_adapter import build_anthropic_client # SDK-absent boundary, like _try_anthropic try: real_client = build_anthropic_client(token_provider, base_url) except ImportError: return None, None client = AnthropicAuxiliaryClient( real_client, final_model, token_provider, base_url, is_oauth=anthropic_route_is_oauth(base_url, token_provider)) return _route_client(req, client, final_model) def _resolve_plugin_oauth_arm(req: _ResolveRequest) -> _ResolveResult: from agent.auxiliary_plugin_oauth import resolve_plugin_oauth_client return resolve_plugin_oauth_client(req) # ``api_key`` / ``external_process`` arms stay on the facade (they share its credential # resolvers); the table maps the auth types whose arms are build-and-route one-liners # or live here as topical arms. REGISTRY_AUTHTYPE_ARMS: dict[str, Callable[[_ResolveRequest], _ResolveResult]] = { "vertex": _resolve_vertex_arm, "aws_sdk": _resolve_bedrock_arm, "oauth_minimax": _resolve_minimax_oauth_arm, # Plugin OAuth: nous / openai-codex / xai-oauth returned from their explicit branches. "oauth_device_code": _resolve_plugin_oauth_arm, "oauth_external": _resolve_plugin_oauth_arm, }