mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
feat(proxy): add model_list_return_wildcard_routes setting for /v1/models
general_settings.model_list_return_wildcard_routes: true makes /v1/models list wildcard routes such as openai/* for every caller, the same as passing return_wildcard_routes=true. An explicit return_wildcard_routes=false on the request still leaves them out
This commit is contained in:
parent
9fd78ff6f4
commit
b841d9a6c2
4 changed files with 95 additions and 3 deletions
|
|
@ -2856,6 +2856,14 @@ class ConfigGeneralSettings(LiteLLMPydanticObjectBase):
|
|||
"hidden model can still be called."
|
||||
),
|
||||
)
|
||||
model_list_return_wildcard_routes: bool | None = Field(
|
||||
None,
|
||||
description=(
|
||||
"When true, `/models` lists wildcard routes such as `openai/*` next to the models they "
|
||||
"expand to, for every caller, without needing `return_wildcard_routes=true` per request. "
|
||||
"A request can still pass `return_wildcard_routes=false` to leave them out."
|
||||
),
|
||||
)
|
||||
alerting: list | None = Field(
|
||||
None,
|
||||
description="List of alerting integrations - e.g. `alerting: ['slack', 'webhook', 'email']`. 'slack' posts Slack-format messages to any Slack-compatible webhook (Slack, Rocket.Chat, Mattermost); 'webhook' posts structured JSON budget alerts to WEBHOOK_URL",
|
||||
|
|
|
|||
|
|
@ -11349,7 +11349,7 @@ async def _deployment_hidden_by_listing_callbacks(deployment: Deployment, user_a
|
|||
async def model_list(
|
||||
request: Request = None, # pyright: ignore[reportArgumentType] # FastAPI always injects the Request; the None default only serves direct in-process callers
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
|
||||
return_wildcard_routes: bool | None = False,
|
||||
return_wildcard_routes: bool | None = None,
|
||||
team_id: str | None = None,
|
||||
include_model_access_groups: bool | None = False,
|
||||
only_model_access_groups: bool | None = False,
|
||||
|
|
@ -11364,6 +11364,10 @@ async def model_list(
|
|||
This is just for compatibility with openai projects like aider.
|
||||
|
||||
Query Parameters:
|
||||
- return_wildcard_routes: When true, also list wildcard routes (e.g. `openai/*`)
|
||||
next to the models they expand to. Defaults to
|
||||
`general_settings.model_list_return_wildcard_routes`, which is
|
||||
false unless set; pass `false` to leave them out regardless.
|
||||
- include_metadata: Include additional metadata in the response with fallback information
|
||||
- fallback_type: Type of fallbacks to include ("general", "context_window", "content_policy")
|
||||
Defaults to "general" when include_metadata=true
|
||||
|
|
@ -11452,6 +11456,12 @@ async def model_list(
|
|||
|
||||
hidden_names: Final = blocked_names | unhealthy_names
|
||||
|
||||
include_wildcard_routes: Final = (
|
||||
settings.get("model_list_return_wildcard_routes") is True
|
||||
if return_wildcard_routes is None
|
||||
else return_wildcard_routes
|
||||
)
|
||||
|
||||
# If scope=expand and user has admin privileges, return all proxy models
|
||||
if should_expand_scope:
|
||||
# Get all proxy models as if user is a proxy admin
|
||||
|
|
@ -11475,7 +11485,7 @@ async def model_list(
|
|||
proxy_model_list=proxy_model_list,
|
||||
user_model=None,
|
||||
infer_model_from_keys=False,
|
||||
return_wildcard_routes=return_wildcard_routes or False,
|
||||
return_wildcard_routes=include_wildcard_routes,
|
||||
llm_router=llm_router,
|
||||
model_access_groups=model_access_groups,
|
||||
include_model_access_groups=include_model_access_groups or False,
|
||||
|
|
@ -11535,7 +11545,7 @@ async def model_list(
|
|||
team_id=team_id,
|
||||
include_model_access_groups=include_model_access_groups or False,
|
||||
only_model_access_groups=only_model_access_groups or False,
|
||||
return_wildcard_routes=return_wildcard_routes or False,
|
||||
return_wildcard_routes=include_wildcard_routes,
|
||||
user_api_key_cache=user_api_key_cache,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3108,3 +3108,64 @@ def test_get_litellm_model_info(data):
|
|||
):
|
||||
get_litellm_model_info(model=model)
|
||||
get_info_mock.assert_called_once_with(data["expected"])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def openai_wildcard_router(monkeypatch: pytest.MonkeyPatch) -> litellm.Router:
|
||||
router = litellm.Router(
|
||||
model_list=[
|
||||
{"model_name": "gpt-4o", "litellm_params": {"model": "openai/gpt-4o", "api_key": "sk-fake"}},
|
||||
{"model_name": "openai/*", "litellm_params": {"model": "openai/*", "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)
|
||||
return router
|
||||
|
||||
|
||||
async def _listed_model_ids(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
general_settings: dict[str, object],
|
||||
user_role: LitellmUserRoles,
|
||||
**query: str | bool,
|
||||
) -> list[str]:
|
||||
monkeypatch.setattr(litellm.proxy.proxy_server, "general_settings", general_settings)
|
||||
response = await litellm.proxy.proxy_server.model_list(
|
||||
user_api_key_dict=UserAPIKeyAuth(api_key="sk-test", user_role=user_role), **query
|
||||
)
|
||||
return [model["id"] for model in response["data"]]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"user_role, query",
|
||||
[(LitellmUserRoles.INTERNAL_USER, {}), (LitellmUserRoles.PROXY_ADMIN, {"scope": "expand"})],
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_list_return_wildcard_routes_setting_matches_query_param(
|
||||
openai_wildcard_router, monkeypatch, user_role, query
|
||||
):
|
||||
requested = await _listed_model_ids(monkeypatch, {}, user_role, return_wildcard_routes=True, **query)
|
||||
from_setting = await _listed_model_ids(monkeypatch, {"model_list_return_wildcard_routes": True}, user_role, **query)
|
||||
|
||||
assert "openai/*" in from_setting, from_setting
|
||||
assert from_setting == requested
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"general_settings, query",
|
||||
[
|
||||
({}, {}),
|
||||
({"model_list_return_wildcard_routes": "false"}, {}),
|
||||
({"model_list_return_wildcard_routes": True}, {"return_wildcard_routes": False}),
|
||||
],
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_model_list_leaves_out_wildcard_routes_unless_enabled(
|
||||
openai_wildcard_router, monkeypatch, general_settings, query
|
||||
):
|
||||
listed = await _listed_model_ids(monkeypatch, general_settings, LitellmUserRoles.INTERNAL_USER, **query)
|
||||
|
||||
assert "gpt-4o" in listed, listed
|
||||
assert "openai/*" not in listed, listed
|
||||
|
|
|
|||
13
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
13
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -9779,6 +9779,10 @@ export interface paths {
|
|||
* This is just for compatibility with openai projects like aider.
|
||||
*
|
||||
* Query Parameters:
|
||||
* - return_wildcard_routes: When true, also list wildcard routes (e.g. `openai/*`)
|
||||
* next to the models they expand to. Defaults to
|
||||
* `general_settings.model_list_return_wildcard_routes`, which is
|
||||
* false unless set; pass `false` to leave them out regardless.
|
||||
* - include_metadata: Include additional metadata in the response with fallback information
|
||||
* - fallback_type: Type of fallbacks to include ("general", "context_window", "content_policy")
|
||||
* Defaults to "general" when include_metadata=true
|
||||
|
|
@ -20059,6 +20063,10 @@ export interface paths {
|
|||
* This is just for compatibility with openai projects like aider.
|
||||
*
|
||||
* Query Parameters:
|
||||
* - return_wildcard_routes: When true, also list wildcard routes (e.g. `openai/*`)
|
||||
* next to the models they expand to. Defaults to
|
||||
* `general_settings.model_list_return_wildcard_routes`, which is
|
||||
* false unless set; pass `false` to leave them out regardless.
|
||||
* - include_metadata: Include additional metadata in the response with fallback information
|
||||
* - fallback_type: Type of fallbacks to include ("general", "context_window", "content_policy")
|
||||
* Defaults to "general" when include_metadata=true
|
||||
|
|
@ -28379,6 +28387,11 @@ export interface components {
|
|||
* @description When true, `/models`, `/v1/models/{id}` and `/model/info` hide models whose backing deployments are all unhealthy, for every caller, without needing `healthy_only=true` per request. Requires `background_health_checks: true`, and keeps deployment health state cached without turning on `enable_health_check_routing`, so routing is unaffected. With no health state nothing is hidden. Hiding is presentation-only, a hidden model can still be called.
|
||||
*/
|
||||
model_list_healthy_only?: boolean | null;
|
||||
/**
|
||||
* Model List Return Wildcard Routes
|
||||
* @description When true, `/models` lists wildcard routes such as `openai/*` next to the models they expand to, for every caller, without needing `return_wildcard_routes=true` per request. A request can still pass `return_wildcard_routes=false` to leave them out.
|
||||
*/
|
||||
model_list_return_wildcard_routes?: boolean | null;
|
||||
/**
|
||||
* Otel
|
||||
* @description [BETA] OpenTelemetry support - this might change, use with caution.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue