fix(router): guard the declared-provider check for requests without a model

This commit is contained in:
mateo-berri 2026-09-01 14:06:14 -07:00
parent 19ca4cd4a9
commit 28d0ac5339
3 changed files with 19 additions and 5 deletions

View file

@ -127,7 +127,7 @@ def handle_anthropic_text_model_custom_llm_provider(
return model, custom_llm_provider
def declared_authenticating_provider(model: str, custom_llm_provider: str | None = None) -> str | None:
def declared_authenticating_provider(model: str | None, custom_llm_provider: str | None = None) -> str | None:
"""The authenticating provider this pair already names, or None.
get_llm_provider runs the OAuth device flow for github_copilot and chatgpt, because their
@ -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] if "/" in model else None)
declared: Final = custom_llm_provider or (model.split("/", 1)[0] if model and "/" in model else None)
return declared if declared in PROVIDERS_THAT_AUTHENTICATE_ON_PROVIDER_INFO else None

View file

@ -204,7 +204,7 @@ class PatternMatchRouter:
return litellm_deployment_litellm_model
def get_pattern(self, model: str, custom_llm_provider: str | None = None) -> list[dict] | None:
def get_pattern(self, model: str | None, custom_llm_provider: str | None = None) -> list[dict] | None:
"""
Check if a pattern exists for the given model and custom llm provider
@ -221,9 +221,9 @@ class PatternMatchRouter:
return self.route(model) or self.route(f"{provider}/{model}")
@staticmethod
def _resolved_provider(model: str) -> str | None:
def _resolved_provider(model: str | None) -> str | None:
try:
return get_llm_provider(model=model)[1]
return get_llm_provider(model=model)[1] if model else None
except Exception: # noqa: BLE001 # get_llm_provider raises when the provider is unknown; the name then routes as-is
return None

View file

@ -53,6 +53,20 @@ def test_get_pattern_bare_provider_name_never_matches_that_providers_wildcard(mo
assert router.get_pattern("github_copilot") is None
def test_get_pattern_missing_model_returns_none(monkeypatch):
"""Regression: a request without a model reaches the auth layer's pattern walk as ``None``; the
declared-provider guard raised ``TypeError`` where the old inline resolve swallowed every
resolver error, so the proxy's missing-model 400 became a crash."""
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("openai/*", _wildcard_deployment("openai/*"))
assert router.get_pattern(None) is None
def test_get_pattern_still_resolves_unqualified_names(monkeypatch):
monkeypatch.setattr(
pattern_match_deployments,