fix(router): bare authenticating-provider names declare nothing

This commit is contained in:
mateo-berri 2026-08-31 13:34:14 -07:00
parent b134dbfe73
commit ec02c9a6d2
5 changed files with 38 additions and 6 deletions

View file

@ -135,7 +135,7 @@ def declared_authenticating_provider(model: str, custom_llm_provider: str | None
and for a declared pair the resolver's answer is the declaration itself, so metadata callers
adopt the declaration instead of resolving.
"""
declared: Final = custom_llm_provider or model.split("/", 1)[0]
declared: Final = custom_llm_provider or (model.split("/", 1)[0] if "/" in model else None)
return declared if declared in PROVIDERS_THAT_AUTHENTICATE_ON_PROVIDER_INFO else None

View file

@ -12482,11 +12482,7 @@ async def supported_openai_params(model: str):
global llm_router
try:
resolved_models: Final = (
llm_router.resolved_litellm_models(model)
if llm_router is not None and declared_authenticating_provider(model) is None
else ()
)
resolved_models: Final = llm_router.resolved_litellm_models(model) if llm_router is not None else ()
target_model: Final = resolved_models[0] if resolved_models else model
declared_provider: Final = declared_authenticating_provider(target_model)
litellm_model, custom_llm_provider = (

View file

@ -188,6 +188,8 @@ class TestDeclaredAuthenticatingProvider:
("gpt-4o", "github_copilot", "github_copilot"),
("openai/gpt-4o", None, None),
("gpt-4o", "openai", None),
("github_copilot", None, None),
("chatgpt", None, None),
],
)
def test_names_only_the_providers_whose_resolution_authenticates(self, model, provider, expected):

View file

@ -147,6 +147,27 @@ def test_supported_openai_params_resolves_router_alias(client, auth_as, monkeypa
assert "max_tokens" in response.json()["supported_openai_params"]
def test_supported_openai_params_declared_prefix_alias_resolves_through_router(client, auth_as, monkeypatch):
"""Regression: an alias whose name starts with an authenticating provider's prefix skipped
router resolution and answered with that provider's params instead of the deployment's."""
router = litellm.Router(
model_list=[
{
"model_name": "github_copilot/gpt-4o",
"litellm_params": {"model": "anthropic/claude-opus-4-6", "api_key": "sk-test"},
}
]
)
monkeypatch.setattr(proxy_server, "llm_router", router)
with auth_as():
response = client.get("/utils/supported_openai_params", params={"model": "github_copilot/gpt-4o"})
assert response.status_code == 200
expected = litellm.get_supported_openai_params(model="claude-opus-4-6", custom_llm_provider="anthropic")
assert response.json() == {"supported_openai_params": expected}
def test_supported_openai_params_never_runs_oauth_for_authenticating_providers(client, auth_as, monkeypatch, tmp_path):
"""Regression: github_copilot/chatgpt names answer from their declaration; resolving them
through ``get_llm_provider`` would run the provider's OAuth device flow and block the event loop."""

View file

@ -40,6 +40,19 @@ def test_get_pattern_never_resolves_declared_authenticating_providers(monkeypatc
assert resolution_attempts == []
def test_get_pattern_bare_provider_name_never_matches_that_providers_wildcard(monkeypatch):
"""Regression: a bare ``github_copilot`` adopted itself as its provider and retried as
``github_copilot/github_copilot``, false-matching the wildcard for a name no deployment serves."""
def _unknown_provider(model, *args, **kwargs):
raise ValueError(f"unknown provider for {model}")
monkeypatch.setattr(pattern_match_deployments, "get_llm_provider", _unknown_provider)
router = PatternMatchRouter()
router.add_pattern("github_copilot/*", _wildcard_deployment("github_copilot/*"))
assert router.get_pattern("github_copilot") is None
def test_get_pattern_still_resolves_unqualified_names(monkeypatch):
monkeypatch.setattr(
pattern_match_deployments,