This commit is contained in:
shrey 2026-10-28 21:25:22 +00:00 • committed by GitHub
commit 07c7bd638c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 105 additions and 8 deletions

View file

@ -12263,6 +12263,25 @@ async def _deployment_hidden_by_listing_callbacks(deployment: Deployment, user_a
return listed_name in await _names_hidden_by_listing_callbacks(user_api_key_dict, (listed_name,))
def _model_list_provider(model_id: str, router: Router | None, team_id: str | None) -> str:
if router is None:
return "openai"
model_group: Final = router.routable_model_group(model_id)
deployment: Final = router.get_deployment_by_model_group_name(model_group) or next(
(Deployment.model_validate(row) for row in router.wildcard_route_deployments(model_group, team_id)), None
)
if deployment is None:
return "openai"
try:
return litellm.get_llm_provider(
model=deployment.litellm_params.model,
custom_llm_provider=deployment.litellm_params.custom_llm_provider,
api_base=deployment.litellm_params.api_base,
)[1]
except litellm.BadRequestError:
return "openai"
@router.get("/v1/models", dependencies=[Depends(user_api_key_auth)], tags=["model management"])
@router.get(
"/models", dependencies=[Depends(user_api_key_auth)], tags=["model management"]
@ -12432,7 +12451,7 @@ async def model_list(
for response_id, lookup_id in admin_entries:
model_info = create_model_info_response(
model_id=lookup_id,
provider="openai",
provider=_model_list_provider(lookup_id, llm_router, team_id or user_api_key_dict.team_id),
include_metadata=include_metadata or False,
fallback_type=fallback_type,
llm_router=llm_router,
@ -12503,7 +12522,7 @@ async def model_list(
for response_id, lookup_id in entries:
model_info = create_model_info_response(
model_id=lookup_id,
provider="openai",
provider=_model_list_provider(lookup_id, llm_router, team_id or user_api_key_dict.team_id),
include_metadata=include_metadata or False,
fallback_type=fallback_type,
llm_router=llm_router,

View file

@ -74,7 +74,7 @@ def patched_models(monkeypatch):
monkeypatch.setattr(
litellm,
"get_llm_provider",
lambda model: (model, "openai", None, None),
lambda model, **kwargs: (model, "openai", None, None),
)
return router

View file

@ -28,7 +28,7 @@ from litellm.proxy.proxy_server import (
_get_proxy_model_info,
_translate_model_name_for_response,
)
from litellm.types.router import DeploymentModelListingInfo
from litellm.types.router import Deployment, DeploymentModelListingInfo
def _team_row() -> dict:
@ -880,6 +880,7 @@ async def test_v1_models_translates_team_model_for_access_group_key(monkeypatch)
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_dep)
router.get_model_names.return_value = ["model_name_teamX_uuid9"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_uuid9"]}
router.get_fully_blocked_model_names.return_value = set()
@ -922,6 +923,7 @@ async def test_v1_models_keeps_internal_names_when_public_name_flag_disabled(
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_dep)
router.get_model_names.return_value = ["model_name_teamX_uuid9"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_uuid9"]}
router.get_fully_blocked_model_names.return_value = set()
@ -957,6 +959,7 @@ async def test_v1_models_translates_team_model_with_metadata(monkeypatch):
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_dep)
router.get_model_names.return_value = ["model_name_teamX_uuid9"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_uuid9"]}
router.get_fully_blocked_model_names.return_value = set()
@ -979,7 +982,7 @@ async def test_v1_models_translates_team_model_with_metadata(monkeypatch):
"id": "tushar-gpt-4.1",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"owned_by": team_dep["litellm_params"]["model"].split("/")[0],
"metadata": {"fallbacks": []},
}
]
@ -1003,6 +1006,7 @@ async def test_v1_models_metadata_fallbacks_use_internal_routing_key(monkeypatch
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_dep)
router.get_model_names.return_value = ["model_name_teamX_uuid9"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_uuid9"]}
router.get_fully_blocked_model_names.return_value = set()
@ -1027,7 +1031,7 @@ async def test_v1_models_metadata_fallbacks_use_internal_routing_key(monkeypatch
"id": "tushar-gpt-4.1",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"owned_by": team_dep["litellm_params"]["model"].split("/")[0],
"metadata": {"fallbacks": ["gpt-4o-backup"]},
}
]
@ -1060,6 +1064,7 @@ async def test_v1_models_metadata_does_not_leak_other_team_fallbacks(monkeypatch
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_x)
router.get_model_names.return_value = ["model_name_teamX_uuid9"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_uuid9"]}
router.get_fully_blocked_model_names.return_value = set()
@ -1086,7 +1091,7 @@ async def test_v1_models_metadata_does_not_leak_other_team_fallbacks(monkeypatch
"id": "tushar-gpt-4.1",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"owned_by": team_x["litellm_params"]["model"].split("/")[0],
"metadata": {"fallbacks": ["teamX-backup"]},
}
]
@ -1108,6 +1113,7 @@ async def test_v1_models_team_alias_inherits_token_limits_and_chat_mode(monkeypa
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_dep)
router.get_model_names.return_value = ["model_name_teamX_terra_uuid"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_terra_uuid"]}
router.get_fully_blocked_model_names.return_value = set()
@ -1133,7 +1139,7 @@ async def test_v1_models_team_alias_inherits_token_limits_and_chat_mode(monkeypa
"id": "GPT Terra",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"owned_by": team_dep["litellm_params"]["model"].split("/")[0],
"mode": "chat",
"max_input_tokens": 876000,
"max_output_tokens": 128000,
@ -1156,6 +1162,7 @@ async def test_v1_models_team_image_alias_inherits_image_generation_mode(monkeyp
},
}
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = Deployment.model_validate(team_dep)
router.get_model_names.return_value = ["model_name_teamX_image_uuid"]
router.get_model_access_groups.return_value = {"grp-a": ["model_name_teamX_image_uuid"]}
router.get_fully_blocked_model_names.return_value = set()

View file

@ -24,6 +24,7 @@ def patched_model_list(monkeypatch):
from litellm.proxy import utils as proxy_utils
router = MagicMock()
router.get_deployment_by_model_group_name.return_value = None
router.get_fully_blocked_model_names = MagicMock(return_value=set())
router.async_get_fully_unhealthy_model_names = AsyncMock(
return_value={"claude-sonnet"}

View file

@ -3857,3 +3857,73 @@ async def test_model_list_return_wildcard_routes_defaults_to_general_setting(
assert "gpt-6.1-sol" in listed, listed
assert ("openai/*" in listed) is wildcard_listed, listed
@pytest.mark.parametrize("scope", [None, "expand"])
@pytest.mark.parametrize("provider", ["azure", "anthropic", "openai"])
@pytest.mark.asyncio
async def test_model_list_provider_matches_retrieval(
monkeypatch: pytest.MonkeyPatch, scope: str | None, provider: str
) -> None:
router: Final = litellm.Router(
model_list=[
{
"model_name": "hosted-model",
"litellm_params": {
"model": f"{provider}/deployment-model",
"api_key": "sk-fake",
"api_base": "https://provider.example.com",
},
},
{
"model_name": "prompt-model",
"litellm_params": {"model": "gitlab/test-prompt"},
},
],
model_group_alias={"friendly-name": "hosted-model"},
)
monkeypatch.setattr(litellm.proxy.proxy_server, "llm_router", router)
monkeypatch.setattr(litellm.proxy.proxy_server, "llm_model_list", router.model_list)
monkeypatch.setattr(litellm.proxy.proxy_server, "prisma_client", None)
monkeypatch.setattr(litellm.proxy.proxy_server, "user_model", None)
monkeypatch.setattr(litellm.proxy.proxy_server, "general_settings", {})
caller: Final = UserAPIKeyAuth(api_key="sk-test", user_role=LitellmUserRoles.PROXY_ADMIN)
listing: Final = await litellm.proxy.proxy_server.model_list(user_api_key_dict=caller, scope=scope)
owners: Final = {row["id"]: row["owned_by"] for row in listing["data"]}
assert owners == {"hosted-model": provider, "friendly-name": provider, "prompt-model": "openai"}
for model_id in ("hosted-model", "friendly-name"):
retrieved: Final = await litellm.proxy.proxy_server.model_info(model_id=model_id, user_api_key_dict=caller)
assert owners[model_id] == retrieved["owned_by"]
@pytest.mark.parametrize("scope", [None, "expand"])
@pytest.mark.parametrize("prefix", ["anthropic", "public"])
@pytest.mark.asyncio
async def test_model_list_expanded_names_use_wildcard_provider(
monkeypatch: pytest.MonkeyPatch, scope: str | None, prefix: str
) -> None:
exact_name: Final = f"{prefix}/configured-model"
router: Final = litellm.Router(
model_list=[
{"model_name": f"{prefix}/*", "litellm_params": {"model": "anthropic/*", "api_key": "sk-fake"}},
{"model_name": exact_name, "litellm_params": {"model": "openai/configured-model", "api_key": "sk-fake"}},
]
)
monkeypatch.setattr(litellm.proxy.proxy_server, "llm_router", router)
monkeypatch.setattr(litellm.proxy.proxy_server, "llm_model_list", router.model_list)
monkeypatch.setattr(litellm.proxy.proxy_server, "prisma_client", None)
monkeypatch.setattr(litellm.proxy.proxy_server, "user_model", None)
monkeypatch.setattr(litellm.proxy.proxy_server, "general_settings", {})
listing: Final = await litellm.proxy.proxy_server.model_list(
user_api_key_dict=UserAPIKeyAuth(api_key="sk-test", user_role=LitellmUserRoles.PROXY_ADMIN),
scope=scope,
)
owners: Final = {row["id"]: row["owned_by"] for row in listing["data"]}
expanded_owners: Final = {owner for name, owner in owners.items() if name != exact_name}
assert expanded_owners == {"anthropic"}
assert all(name.startswith(f"{prefix}/") and "*" not in name for name in owners)
assert owners[exact_name] == "openai"