Merge pull request #121614 from NousResearch/austin/fix/121347-base-url-resolution

fix(providers): honor a configured base_url instead of the vendor host across runtime, fallback, listing and validation
This commit is contained in:
Austin Pickett
2026-09-25 14:15:01 -04:00
committed by GitHub
9 changed files with 421 additions and 24 deletions

View File

@@ -2296,7 +2296,8 @@ def _warn_paid_lane_once(model: str) -> None:
)
def _try_openrouter(explicit_api_key: Optional[Union[str, Callable[[], str]]] = None, model: str = None) -> Tuple[Optional[OpenAI], Optional[str]]:
def _try_openrouter(explicit_api_key: Optional[Union[str, Callable[[], str]]] = None, model: str = None,
explicit_base_url: Optional[str] = None) -> Tuple[Optional[OpenAI], Optional[str]]:
free_only, cfg_model = _aux_openrouter_settings()
or_model = model or cfg_model
if free_only and not _is_free_model(or_model):
@@ -2309,11 +2310,14 @@ def _try_openrouter(explicit_api_key: Optional[Union[str, Callable[[], str]]] =
return None, None
if not _is_free_model(or_model):
_warn_paid_lane_once(or_model)
# A caller-supplied endpoint (fallback_providers entry, custom_providers entry) is
# authoritative over both the pool row and the canonical host (#121359).
override_url = (explicit_base_url or "").strip().rstrip("/")
pool_present, entry = _select_pool_entry("openrouter")
if pool_present:
or_key = explicit_api_key or _pool_runtime_api_key(entry)
if or_key:
base_url = _pool_runtime_base_url(entry, OPENROUTER_BASE_URL) or OPENROUTER_BASE_URL
base_url = override_url or _pool_runtime_base_url(entry, OPENROUTER_BASE_URL) or OPENROUTER_BASE_URL
logger.debug("Auxiliary client: OpenRouter via pool")
return _create_openai_client(
api_key=or_key, base_url=base_url, default_headers=build_or_headers()
@@ -2327,7 +2331,7 @@ def _try_openrouter(explicit_api_key: Optional[Union[str, Callable[[], str]]] =
return None, None
logger.debug("Auxiliary client: OpenRouter")
return _create_openai_client(
api_key=or_key, base_url=OPENROUTER_BASE_URL, default_headers=build_or_headers()
api_key=or_key, base_url=override_url or OPENROUTER_BASE_URL, default_headers=build_or_headers()
), or_model
@@ -3009,7 +3013,8 @@ def _try_azure_foundry(
return client, final_model
def _try_anthropic(explicit_api_key: Optional[Union[str, Callable[[], str]]] = None) -> Tuple[Optional[Any], Optional[str]]:
def _try_anthropic(explicit_api_key: Optional[Union[str, Callable[[], str]]] = None,
explicit_base_url: Optional[str] = None) -> Tuple[Optional[Any], Optional[str]]:
try:
from agent.anthropic_adapter import build_anthropic_client
from agent.anthropic_credentials import resolve_anthropic_token
@@ -3037,6 +3042,21 @@ def _try_anthropic(explicit_api_key: Optional[Union[str, Callable[[], str]]] = N
cfg_base_url = (model_cfg.get("base_url") or "").strip().rstrip("/")
if cfg_base_url and _is_anthropic_compatible_host(cfg_base_url):
base_url = cfg_base_url
# A caller-supplied endpoint (fallback_providers entry, custom_providers entry) wins over
# both the pool row and config.yaml, under the same Anthropic-compatible host rule the
# primary path applies. A foreign host is REFUSED outright rather than silently demoted to
# the canonical host: continuing would send the explicit credential to a target the caller
# did not ask for (#121359).
override_url = (explicit_base_url or "").strip().rstrip("/")
if override_url:
if not _is_anthropic_compatible_host(override_url):
logger.warning(
"Auxiliary client: refusing anthropic explicit base_url %r — not an "
"Anthropic-compatible host; no client built and no request sent.",
override_url,
)
return None, None
base_url = override_url
from agent.anthropic_credentials import _is_oauth_token
is_oauth = _is_oauth_token(token)
model = _get_aux_model_for_provider("anthropic") or "claude-haiku-4-5-20251001"
@@ -4968,7 +4988,8 @@ def _resolve_auto_branch(req: _ResolveRequest) -> _ResolveResult:
def _resolve_openrouter_branch(req: _ResolveRequest) -> _ResolveResult:
"""OpenRouter."""
client, default = _try_openrouter(explicit_api_key=req.explicit_api_key, model=req.model)
client, default = _try_openrouter(explicit_api_key=req.explicit_api_key, model=req.model,
explicit_base_url=req.explicit_base_url)
if client is None:
logger.warning("resolve_provider_client: openrouter requested but %s",
_describe_openrouter_unavailable(model=req.model))
@@ -5230,7 +5251,8 @@ def _resolve_api_key_branch(req: _ResolveRequest, pconfig: Any, resolve_creds: C
"""PROVIDER_REGISTRY ``api_key`` providers (Anthropic via its own resolver), honouring explicit overrides."""
provider = req.provider
if provider == "anthropic":
client, default_model = _try_anthropic(explicit_api_key=req.explicit_api_key)
client, default_model = _try_anthropic(explicit_api_key=req.explicit_api_key,
explicit_base_url=req.explicit_base_url)
return _route_or_warn(req, client, default_model,
"resolve_provider_client: anthropic requested but no Anthropic credentials found")
creds = resolve_creds(provider)

View File

@@ -0,0 +1,2 @@
ahisblessed
# PR #121591 salvage (/model picker probes model.base_url)

View File

@@ -1602,26 +1602,66 @@ def _chat_catalog_rows(models):
return without_generation_models(models)
def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False) -> list[str]:
"""Best known model catalog for a provider: per-provider live fetchers, then the generic profile
fetch, then the static list (merged with models.dev for ``_MODELS_DEV_PREFERRED`` providers)."""
requested = str(provider or "").strip().lower()
if requested == "ollama":
return _ollama_local_catalog(force_refresh)
def _configured_relay_base_url(provider: str) -> str:
"""``model.base_url`` when it points the *configured* provider at a relay/proxy, else "".
normalized = normalize_provider(provider)
fetcher = _PROVIDER_CATALOG_FETCHERS.get(normalized)
if fetcher is not None:
models = fetcher(normalized, force_refresh)
if models is not None:
return _chat_catalog_rows(models)
Discovery must probe the same endpoint inference uses (#121387): with ``model.base_url``
set for the configured provider, the vendor's canonical host is NOT the catalog to list.
Mirrors the ``$OPENAI_BASE_URL`` -> ``model.base_url`` -> canonical precedence of
``_openai_discovery_base_url`` for every built-in provider, not just OpenAI.
"""
try:
models = _profile_live_catalog(normalized)
model_cfg = _get_model_config_dict()
except Exception:
models = None
if models is not None:
return _chat_catalog_rows(models)
return ""
cfg_provider = str(model_cfg.get("provider") or "").strip().lower()
if not cfg_provider or not provider:
return ""
try:
if normalize_provider(provider) != normalize_provider(cfg_provider):
return ""
except Exception:
return ""
return str(model_cfg.get("base_url") or "").strip().rstrip("/")
def _relay_model_catalog(normalized: str, relay: str) -> Optional[list[str]]:
"""Live catalog probed at a configured ``model.base_url`` relay, or None to fall through.
Returns only the relay's live ids (no curated merge): a relay user must see the relay's
catalog, and a failed/empty probe degrades to the canonical fetchers untouched.
"""
try:
from providers import get_provider_profile
profile = get_provider_profile(normalized)
if profile is None or getattr(profile, "auth_type", "") != "api_key":
return None
api_key, _ = _api_key_credentials(normalized)
live = profile.fetch_models(api_key=api_key, base_url=relay)
return [str(m) for m in (live or []) if m] or None
except Exception:
return None
# Canonical fetchers that already resolve `model.base_url` themselves for the configured
# provider AND degrade to their curated list when that relay fails — `_anthropic_catalog`,
# `_custom_catalog`, `_openai_catalog` (via `_openai_discovery_base_url`) and the simple
# api-key fetchers (via `resolve_api_key_provider_credentials`). They already satisfy the
# "no vendor egress when a relay is configured" invariant, so intercepting them would only
# override correct, better-merged behaviour. Everything else is vendor-pinned (#121387).
_RELAY_AWARE_CATALOG_FETCHERS = frozenset(
{"anthropic", "custom", "openai", "openai-api", "stepfun", "gmi"}
)
def _static_catalog(normalized: str, fetcher: Any) -> list[str]:
"""The local, no-egress catalog tail: curated static list (+ models.dev merge where preferred).
Shared by the normal path's final fallback and by the configured-relay degrade path, which
must never reach a live vendor fetcher (#121387).
"""
# Merge static curated list with live API results so models that the live endpoint omits (stale cache,
# partial rollout) still appear in the picker. Single providers (kimi, zai) use curated-first (commit
# 658ac1d86) to surface newest models even when live API lags (#46309). OpenCode Zen / Go are different:
@@ -1640,6 +1680,40 @@ def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False)
return _chat_catalog_rows(_xai_finalize_catalog(merged) if normalized in {"xai", "xai-oauth"} else merged)
def provider_model_ids(provider: Optional[str], *, force_refresh: bool = False) -> list[str]:
"""Best known model catalog for a provider: per-provider live fetchers, then the generic profile
fetch, then the static list (merged with models.dev for ``_MODELS_DEV_PREFERRED`` providers)."""
requested = str(provider or "").strip().lower()
if requested == "ollama":
return _ollama_local_catalog(force_refresh)
normalized = normalize_provider(provider)
# A configured `model.base_url` relay is TERMINAL for live catalog egress: the picker must
# list what the configured endpoint serves and must never touch the vendor host (#121387).
# A failed or empty probe degrades to the local curated list — falling through to the
# canonical fetchers would send the provider credential to exactly the host the user
# deliberately routed away from, recreating the bug on the failure path.
relay = _configured_relay_base_url(provider or "")
if relay and normalized not in _RELAY_AWARE_CATALOG_FETCHERS:
relayed = _relay_model_catalog(normalized, relay)
if relayed:
return _chat_catalog_rows(relayed)
return _static_catalog(normalized, _PROVIDER_CATALOG_FETCHERS.get(normalized))
fetcher = _PROVIDER_CATALOG_FETCHERS.get(normalized)
if fetcher is not None:
models = fetcher(normalized, force_refresh)
if models is not None:
return _chat_catalog_rows(models)
try:
models = _profile_live_catalog(normalized)
except Exception:
models = None
if models is not None:
return _chat_catalog_rows(models)
return _static_catalog(normalized, fetcher)
# ---------------------------------------------------------------------------
# Disk cache for provider_model_ids() — keeps /model picker fast (otherwise every open re-fetches
# every authed provider's /v1/models). One JSON file at $HERMES_HOME/provider_models_cache.json;

View File

@@ -589,7 +589,7 @@ def _validate_managed_local(req: _Request) -> Optional[dict[str, Any]]:
return None
def _profile_catalog(normalized: str) -> tuple[list[str], bool]:
def _profile_catalog(normalized: str, base_url: Optional[str] = None) -> tuple[list[str], bool]:
"""``(catalog, authoritative)`` for a profile whose catalog is not the generic
``{base_url}/models`` listing — it overrides ``fetch_models`` or points ``models_url``
elsewhere — so that listing is not authoritative for it (a relay may 200 with a different
@@ -604,6 +604,10 @@ def _profile_catalog(normalized: str) -> tuple[list[str], bool]:
profile = get_provider_profile(normalized)
if profile is None:
return [], False
# A non-default runtime base_url is a user-configured relay/proxy; its own /models listing
# decides validation, not the provider profile's canonical catalog endpoint.
if base_url and (base_url.rstrip("/") != (profile.base_url or "").rstrip("/")):
return [], False
generic = (profile.base_url or "").rstrip("/") + "/models"
own_endpoint = bool(profile.models_url) and profile.models_url.rstrip("/") != generic
if not own_endpoint and type(profile).fetch_models is ProviderProfile.fetch_models:
@@ -618,7 +622,7 @@ def _validate_live_listing(req: _Request) -> Optional[dict[str, Any]]:
against that catalog (``provider_model_ids`` — the picker's list) before the generic listing."""
from hermes_cli import models as _m
catalog, authoritative = _profile_catalog(req.normalized)
catalog, authoritative = _profile_catalog(req.normalized, req.base_url)
if catalog:
match = _match_in_catalog(req.lookup, catalog, suggest_query=req.requested)
if match.exact:

View File

@@ -534,6 +534,13 @@ def _pool_entry_mode_and_url(provider, entry, model_cfg, effective_model, base_u
# only when the pool row still carries the canonical URL).
if base_url in ("", default_url):
base_url = _config_base_url_for_provider(model_cfg, provider) or base_url
if provider == "xai":
# Env-seeded rows keep the registry host. model.base_url is the relay
# override, and only while the row is still that host — an explicit
# per-credential endpoint stays authoritative (#121347).
canonical = (PROVIDER_REGISTRY["xai"].inference_base_url or "").rstrip("/")
if base_url.rstrip("/") in ("", canonical):
base_url = _config_base_url_for_provider(model_cfg, provider) or base_url
return api_mode, base_url or (default_url() if callable(default_url) else default_url)
if provider == "anthropic":
return "anthropic_messages", _anthropic_cfg_base_url(model_cfg) or base_url or _ANTHROPIC_DEFAULT_BASE_URL

View File

@@ -0,0 +1,96 @@
"""A ``fallback_providers`` entry's ``base_url`` must reach the client (#121359).
``try_activate_fallback`` forwards the entry's ``base_url`` to
``resolve_provider_client(explicit_base_url=...)``. Every registry API-key provider honours
that override, but the two providers with their own resolver branches — ``anthropic`` and
``openrouter`` — dropped it and built the client on the vendor's canonical host, sending the
fallback turn (and the key) somewhere the user never configured.
These assert the RELATIONSHIP: given an explicit endpoint, the resolved client's base URL is
that endpoint. No live request is made; all hosts here are loopback/``.invalid``.
"""
from __future__ import annotations
from unittest.mock import MagicMock, patch
import pytest
@pytest.fixture(autouse=True)
def _clean_env(monkeypatch):
for key in ("OPENAI_API_KEY", "OPENAI_BASE_URL", "ANTHROPIC_API_KEY", "ANTHROPIC_TOKEN",
"ANTHROPIC_BASE_URL", "OPENROUTER_API_KEY", "OPENROUTER_BASE_URL"):
monkeypatch.delenv(key, raising=False)
_RELAY_ANTHROPIC = "http://127.0.0.1:9002/anthropic"
_RELAY_OPENROUTER = "http://127.0.0.1:9002/openrouter/v1"
def _client_base_url(client) -> str:
for chain in (("base_url",), ("_real_client", "base_url"), ("_client", "base_url")):
obj = client
try:
for attr in chain:
obj = getattr(obj, attr)
return str(obj)
except AttributeError:
continue
return ""
def test_anthropic_fallback_entry_base_url_is_the_resolved_endpoint():
"""A fallback entry pointing anthropic at an Anthropic-protocol relay must be honoured."""
from agent.auxiliary_client import resolve_provider_client
fake_anthropic = MagicMock(name="anthropic_sdk_client")
with patch("agent.anthropic_adapter.build_anthropic_client", return_value=fake_anthropic) as mock_build:
client, _model = resolve_provider_client(
"anthropic", model="claude-haiku-4-5-20251001", raw_codex=True,
explicit_base_url=_RELAY_ANTHROPIC, explicit_api_key="sk-test-not-a-real-key")
assert client is not None
assert mock_build.call_args[0][1] == _RELAY_ANTHROPIC
assert client.base_url == _RELAY_ANTHROPIC
def test_anthropic_fallback_entry_refuses_a_non_anthropic_endpoint():
"""An explicit target mismatch is REFUSED — never silently demoted to the canonical host.
Continuing with `base_url` reset to api.anthropic.com would send the caller's explicit
credential to a host the caller did not ask for. No client is produced and the SDK
builder is never reached.
"""
from agent.auxiliary_client import resolve_provider_client
with patch("agent.anthropic_adapter.build_anthropic_client", return_value=MagicMock()) as mock_build:
client, _model = resolve_provider_client(
"anthropic", model="claude-haiku-4-5-20251001", raw_codex=True,
explicit_base_url="http://127.0.0.1:9002/openai/v1", explicit_api_key="sk-test-not-a-real-key")
assert client is None, "an incompatible explicit endpoint must not yield a client"
assert mock_build.call_count == 0, "no canonical client may be constructed on refusal"
def test_openrouter_fallback_entry_base_url_is_the_resolved_endpoint():
"""A fallback entry pointing openrouter at a relay must not resolve to openrouter.ai."""
from agent.auxiliary_client import resolve_provider_client
client, _model = resolve_provider_client(
"openrouter", model="some/model", raw_codex=True,
explicit_base_url=_RELAY_OPENROUTER, explicit_api_key="sk-test-not-a-real-key")
assert client is not None
assert _client_base_url(client).rstrip("/") == _RELAY_OPENROUTER
def test_openrouter_without_an_entry_base_url_keeps_the_configured_default():
"""No override: resolution is unchanged (no relay invented)."""
from agent.auxiliary_client import OPENROUTER_BASE_URL, resolve_provider_client
client, _model = resolve_provider_client(
"openrouter", model="some/model", raw_codex=True, explicit_api_key="sk-test-not-a-real-key")
assert client is not None
assert _client_base_url(client).rstrip("/") == OPENROUTER_BASE_URL.rstrip("/")

View File

@@ -833,6 +833,25 @@ class TestProfileCatalogAuthoritative:
assert result["accepted"] is True
assert result["recognized"] is True
def test_nebius_relay_base_url_validates_against_relay_listing(self, monkeypatch):
"""A configured relay base URL must decide Nebius Token Factory validation (#121388)."""
relay_base_url = "https://relay.example.invalid/v1"
calls = []
def fetch_relay_models(_api_key, base_url, **_kwargs):
calls.append(base_url)
return ["relay-only/model"] if base_url == relay_base_url else ["canonical-only/model"]
monkeypatch.setattr("hermes_cli.models.provider_model_ids", lambda _provider: ["canonical-only/model"])
monkeypatch.setattr("hermes_cli.models.fetch_api_models", fetch_relay_models)
result = validate_requested_model(
"relay-only/model", "nebius-token-factory", api_key="k", base_url=relay_base_url)
assert result["accepted"] is True
assert result["recognized"] is True
assert calls == [relay_base_url]
# -- validate — whitespace in self-hosted / user-configured ids --------------

View File

@@ -0,0 +1,113 @@
"""`model.base_url` relays must be probed instead of the vendor's canonical host (#121387)."""
from types import SimpleNamespace
import pytest
import hermes_cli.models as models
class _RecordingProfile:
auth_type = "api_key"
fallback_models = []
def __init__(self):
self.calls = []
def fetch_models(self, api_key=None, base_url=None):
self.calls.append((api_key, base_url))
return ["relay-only-model"]
def test_relay_base_url_is_probed_for_configured_provider(monkeypatch):
monkeypatch.setattr(
models,
"_get_model_config_dict",
lambda: {
"provider": "deepseek",
"base_url": "http://127.0.0.1:9001/deepseek/v1",
},
)
profile = _RecordingProfile()
import providers
monkeypatch.setattr(providers, "get_provider_profile", lambda name: profile)
monkeypatch.setattr(models, "_api_key_credentials", lambda name: (None, None))
monkeypatch.setattr(
models,
"_PROVIDER_CATALOG_FETCHERS",
{
"deepseek": lambda n, f: (_ for _ in ()).throw(
AssertionError("canonical host touched")
)
},
)
assert models.provider_model_ids("deepseek", force_refresh=True) == [
"relay-only-model"
]
assert profile.calls == [(None, "http://127.0.0.1:9001/deepseek/v1")]
def test_base_url_for_a_different_provider_is_ignored(monkeypatch):
monkeypatch.setattr(
models,
"_get_model_config_dict",
lambda: {
"provider": "deepseek",
"base_url": "http://127.0.0.1:9001/deepseek/v1",
},
)
assert models._configured_relay_base_url("openai") == ""
@pytest.mark.parametrize(
"probe_result",
[
pytest.param("raise", id="relay-hangs-or-errors"),
pytest.param([], id="relay-404-empty-catalog"),
],
)
def test_a_failed_relay_probe_never_falls_back_to_the_vendor_host(monkeypatch, probe_result):
"""Egress sentinel: a configured relay is TERMINAL for live catalog egress.
A relay that 404s, hangs or returns nothing must degrade to the LOCAL curated list.
Falling through to the canonical fetcher would send the provider credential to exactly
the vendor host the user routed away from, recreating #121387 on the failure path.
"""
monkeypatch.setattr(
models,
"_get_model_config_dict",
lambda: {
"provider": "deepseek",
"base_url": "http://127.0.0.1:9001/deepseek/v1",
},
)
def _probe(**kwargs):
if probe_result == "raise":
raise RuntimeError("relay down")
return probe_result
import providers
monkeypatch.setattr(
providers,
"get_provider_profile",
lambda name: SimpleNamespace(
auth_type="api_key", fetch_models=_probe, fallback_models=[]
),
)
monkeypatch.setattr(models, "_api_key_credentials", lambda name: (None, None))
# Sentinels on EVERY live-egress seam below the relay probe.
def _egress(*a, **k):
raise AssertionError("vendor host touched after a failed relay probe")
monkeypatch.setattr(models, "_PROVIDER_CATALOG_FETCHERS", {"deepseek": _egress})
monkeypatch.setattr(models, "_profile_live_catalog", _egress)
monkeypatch.setattr(models, "_merge_with_models_dev", _egress)
monkeypatch.setattr(models, "_PROVIDER_MODELS", {"deepseek": ["curated-local"]})
# Degrades locally to the curated list, with no vendor egress at all.
assert models.provider_model_ids("deepseek") == ["curated-local"]

View File

@@ -163,6 +163,66 @@ def test_codex_pool_honors_model_base_url(monkeypatch):
assert resolved["api_mode"] == "codex_responses"
def _xai_pool(url):
class _Entry:
access_token = "pool-token"
source = "env:XAI_API_KEY"
base_url = url
class _Pool:
def has_credentials(self):
return True
def select(self, **_kwargs):
return _Entry()
return _Pool()
def test_xai_pool_honors_model_base_url_when_row_is_registry_host(monkeypatch):
"""#121347: an env-seeded xAI row keeps https://api.x.ai/v1. model.base_url is the
relay override, same as the other API-key providers, and must not be shadowed."""
monkeypatch.setattr(rp, "resolve_provider", lambda *a, **k: "xai")
monkeypatch.setattr(rp, "load_pool", lambda provider: _xai_pool("https://api.x.ai/v1"))
monkeypatch.delenv("XAI_BASE_URL", raising=False)
monkeypatch.setattr(rp, "_get_model_config", lambda: {
"provider": "xai", "default": "grok-4", "base_url": "http://127.0.0.1:8765/v1/"})
resolved = rp.resolve_runtime_provider(requested="xai")
assert resolved["provider"] == "xai"
assert resolved["api_key"] == "pool-token"
assert resolved["base_url"] == "http://127.0.0.1:8765/v1"
assert resolved["api_mode"] == "codex_responses"
def test_xai_pool_keeps_explicit_credential_endpoint(monkeypatch):
"""A pool row that is not the registry host is an explicit endpoint and wins over model.base_url."""
monkeypatch.setattr(rp, "resolve_provider", lambda *a, **k: "xai")
monkeypatch.setattr(rp, "load_pool", lambda provider: _xai_pool("https://relay.example/v1"))
monkeypatch.delenv("XAI_BASE_URL", raising=False)
monkeypatch.setattr(rp, "_get_model_config", lambda: {
"provider": "xai", "default": "grok-4", "base_url": "http://127.0.0.1:8765/v1"})
resolved = rp.resolve_runtime_provider(requested="xai")
assert resolved["base_url"] == "https://relay.example/v1"
assert resolved["api_mode"] == "codex_responses"
def test_xai_pool_ignores_another_providers_base_url(monkeypatch):
"""A stale model.base_url saved for a different provider must not receive the xAI key."""
monkeypatch.setattr(rp, "resolve_provider", lambda *a, **k: "xai")
monkeypatch.setattr(rp, "load_pool", lambda provider: _xai_pool("https://api.x.ai/v1"))
monkeypatch.delenv("XAI_BASE_URL", raising=False)
monkeypatch.setattr(rp, "_get_model_config", lambda: {
"provider": "deepseek", "default": "deepseek-v4-pro", "base_url": "http://127.0.0.1:8765/v1"})
resolved = rp.resolve_runtime_provider(requested="xai")
assert resolved["base_url"] == "https://api.x.ai/v1"
class TestCustomProviderPoolLoopbackNoKeyExemption:
"""Regression for issue #86864: legacy custom_providers configs often
used short/placeholder api_keys ('123', 'm') for local no-auth