fix(proxy): drop fragment ids for a catch-all over a partial wildcard and route bare aliases through the deployment pattern

A * catch-all over a partial deployment now lists no catalog ids, a bare alias like my-cf/* over cloudflare/@cf/* names ids by the deployment pattern, an alias whose wildcard count differs from its deployment lists nothing, and /model/info rows show the model each listed id routes to
This commit is contained in:
mateo-berri 2026-10-17 16:36:30 -07:00
parent 6ff82d13b0
commit c096b69788
2 changed files with 85 additions and 16 deletions

View file

@ -274,6 +274,8 @@ def _hydrate_litellm_credential_name(
def _ids_routing_to_catalog_models(
name_pattern: str, deployment_pattern: str, provider: str, catalog_ids: Sequence[str]
) -> tuple[str, ...]:
if name_pattern.count("*") != deployment_pattern.count("*"):
return ()
deployment_regex: Final = re.compile(PatternMatchRouter().pattern_to_regex(deployment_pattern))
provider_id_prefix: Final = f"{provider}/"
catalog_matches: Final = (
@ -291,6 +293,13 @@ def _ids_routing_to_catalog_models(
)
def _deployment_pattern_naming_listed_ids(wildcard_suffix: str, litellm_params: LiteLLM_Params | None) -> str | None:
if litellm_params is None or not _check_wildcard_routing(litellm_params.model):
return None
deployment_suffix: Final = litellm_params.model.partition("/")[2]
return litellm_params.model if wildcard_suffix != "*" or deployment_suffix != "*" else None
def get_known_models_from_wildcard(wildcard_model: str, litellm_params: LiteLLM_Params | None = None) -> list[str]:
wildcard_model_to_expand: Final = (
litellm_params.model
@ -304,6 +313,9 @@ def get_known_models_from_wildcard(wildcard_model: str, litellm_params: LiteLLM_
wildcard_provider_prefix, wildcard_suffix = wildcard_model_to_expand.split("/", 1)
except ValueError: # safely fail
return []
deployment_pattern_naming_listed_ids: Final = _deployment_pattern_naming_listed_ids(wildcard_suffix, litellm_params)
if deployment_pattern_naming_listed_ids is not None and wildcard_model == "*":
return []
# Use provider from litellm_params when available, otherwise from wildcard prefix
# (e.g., "openai" from "openai/*" - needed for BYOK where wildcard isn't in router)
@ -321,16 +333,16 @@ def get_known_models_from_wildcard(wildcard_model: str, litellm_params: LiteLLM_
if wildcard_models is None:
return []
if wildcard_suffix != "*":
if litellm_params is not None and _check_wildcard_routing(litellm_params.model):
return list(
_ids_routing_to_catalog_models(
name_pattern=wildcard_model,
deployment_pattern=litellm_params.model,
provider=provider,
catalog_ids=wildcard_models,
)
if deployment_pattern_naming_listed_ids is not None:
return list(
_ids_routing_to_catalog_models(
name_pattern=wildcard_model,
deployment_pattern=deployment_pattern_naming_listed_ids,
provider=provider,
catalog_ids=wildcard_models,
)
)
if wildcard_suffix != "*":
model_prefix: Final = wildcard_suffix.replace("*", "")
provider_id_prefix: Final = f"{provider}/"
filtered_wildcard_models: Final = [
@ -363,6 +375,17 @@ def get_known_models_from_wildcard(wildcard_model: str, litellm_params: LiteLLM_
return list(dict.fromkeys(suffix_appended_wildcard_models))
def _deployment_model_serving(listed_id: str, name_pattern: str, deployment_model: str) -> str:
listed_match: Final = (
None if name_pattern == "*" else re.fullmatch(PatternMatchRouter().pattern_to_regex(name_pattern), listed_id)
)
if listed_match is None:
return listed_id
return PatternMatchRouter.set_deployment_model_name(
matched_pattern=listed_match, litellm_deployment_litellm_model=deployment_model
)
def expand_wildcard_deployments_for_model_info(
deployments: list[dict[str, object]],
) -> list[dict[str, object]]:
@ -411,7 +434,9 @@ def expand_wildcard_deployments_for_model_info(
row["model_name"] = name
params = row.get("litellm_params")
if isinstance(params, dict):
params["model"] = name
params["model"] = _deployment_model_serving(
name, name_pattern=model_name, deployment_model=litellm_model
)
expanded.append(row)
return expanded

View file

@ -1284,11 +1284,13 @@ _ROUTE_CF_IDS: Final = {_ROUTE_CF_ID, _ROUTE_CF_SUFFIXED_ID}
),
pytest.param("cloudflare/team-*", "cloudflare/*", None, {*_ROUTE_CF_IDS, _ROUTE_HF_ID}, id="alias"),
pytest.param("cloudflare/cf-*", "cloudflare/@cf/*", None, _ROUTE_CF_IDS, id="alias-over-partial-deployment"),
pytest.param("*", "cloudflare/@cf/*", None, _ROUTE_CF_IDS, id="catch-all-over-partial-deployment"),
pytest.param("my-cf/*", "cloudflare/@cf/*", None, _ROUTE_CF_IDS, id="bare-alias-over-partial-deployment"),
pytest.param(
"cloudflare/team-*", "cloudflare/@cf/*/*", None, set(), id="alias-with-fewer-wildcards-than-its-deployment"
),
pytest.param(
"cloudflare/*", "cloudflare/*", "cloudflare/@cf/*", _ROUTE_CF_IDS, id="key-filter-over-provider-wildcard"
),
pytest.param("*", "gemini/gemini-partial-route-9*", None, {_ROUTE_GEMINI_ID}, id="catch-all-over-bare-id"),
pytest.param("gemini/gemini-*", "gemini/*", None, {_ROUTE_GEMINI_ID}, id="alias-over-bare-id"),
pytest.param(
"gemini/*", "gemini/*", "gemini/gemini-partial-route-9*", {_ROUTE_GEMINI_ID}, id="key-filter-over-bare-id"
@ -1337,15 +1339,57 @@ def test_every_listed_partial_wildcard_id_routes_to_the_catalog_model_it_names(
infer_model_from_keys=False,
llm_router=router,
)
model_info_names: Final = [
str(row["model_name"])
model_info_rows: Final = tuple(
(str(row["model_name"]), TypeAdapter(LiteLLM_Params).validate_python(row["litellm_params"]).model)
for row in expand_wildcard_deployments_for_model_info(
[dict(deployment) for deployment in router.get_model_list() or []]
)
]
)
listed_v1_models: Final = routed_catalog_ids(v1_models)
listed_model_info_names: Final = routed_catalog_ids(model_info_names)
listed_model_info_names: Final = routed_catalog_ids([name for name, _ in model_info_rows])
assert listed_v1_models == sorted(reachable)
assert [shown_model for _, shown_model in model_info_rows] == [routed_model(name) for name, _ in model_info_rows]
if key_model is None:
assert listed_model_info_names == sorted(reachable)
@pytest.mark.parametrize("deployment_model", ["cloudflare/@cf/*", "gemini/gemini-partial-route-9*"])
def test_catch_all_over_a_partial_deployment_lists_no_catalog_ids(deployment_model: str) -> None:
from litellm import Router
from litellm.proxy.auth.model_checks import expand_wildcard_deployments_for_model_info, get_complete_model_list
router: Final = Router(model_list=[{"model_name": "*", "litellm_params": {"model": deployment_model}}])
deployments: Final = [dict(deployment) for deployment in router.get_model_list() or []]
with _registered_chat_models({_ROUTE_CF_ID: "cloudflare", _ROUTE_GEMINI_ID: "gemini"}):
v1_models: Final = get_complete_model_list(
key_models=[],
team_models=[],
proxy_model_list=["*"],
user_model=None,
infer_model_from_keys=False,
llm_router=router,
)
model_info_rows: Final = expand_wildcard_deployments_for_model_info(deployments)
assert v1_models == []
assert model_info_rows == deployments
def test_catch_all_model_info_rows_show_the_listed_provider_model() -> None:
from pydantic import TypeAdapter
from litellm.proxy.auth.model_checks import expand_wildcard_deployments_for_model_info
from litellm.types.router import LiteLLM_Params
listed_id: Final = "openai/partial-route-catch-all-model"
with _registered_chat_models({listed_id.removeprefix("openai/"): "openai"}):
model_info_rows: Final = expand_wildcard_deployments_for_model_info(
[{"model_name": "*", "litellm_params": {"model": "openai/*"}}]
)
shown_models: Final = {
str(row["model_name"]): TypeAdapter(LiteLLM_Params).validate_python(row["litellm_params"]).model
for row in model_info_rows
}
assert shown_models[listed_id] == listed_id