diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 41a9341c6cf..f5837abd587 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -2859,9 +2859,10 @@ class ConfigGeneralSettings(LiteLLMPydanticObjectBase): 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." + "When true, `/v1/models` lists wildcard routes such as `openai/*` next to the models they " + "expand to, without the caller passing `return_wildcard_routes=true`. A request that passes " + "`return_wildcard_routes=false` still leaves them out, as do the dashboard's model pickers " + "and `/cursor/v1/models`." ), ) alerting: list | None = Field( diff --git a/litellm/proxy/response_api_endpoints/endpoints.py b/litellm/proxy/response_api_endpoints/endpoints.py index c5d702ad65a..84221da1c79 100644 --- a/litellm/proxy/response_api_endpoints/endpoints.py +++ b/litellm/proxy/response_api_endpoints/endpoints.py @@ -482,7 +482,10 @@ async def cursor_model_list( """ from litellm.proxy.proxy_server import model_list - return await model_list(user_api_key_dict=user_api_key_dict) + # Cursor offers every listed id as a model and a wildcard route such as + # `openai/*` is not callable, so the proxy-wide model_list_return_wildcard_routes + # default is pinned off here; Cursor sends no query params to opt out itself. + return await model_list(user_api_key_dict=user_api_key_dict, return_wildcard_routes=False) @router.post( diff --git a/tests/e2e/management/test_model_list_wildcard_routes_e2e.py b/tests/e2e/management/test_model_list_wildcard_routes_e2e.py index 5aa81821d59..9a9cea73bce 100644 --- a/tests/e2e/management/test_model_list_wildcard_routes_e2e.py +++ b/tests/e2e/management/test_model_list_wildcard_routes_e2e.py @@ -4,9 +4,9 @@ the models it expands to. The setting is written through /config/field/update, the route behind the admin UI's General Settings toggle, and deleted on teardown so the shared proxy goes back to -leaving wildcard routes out. Every other listing the suites run passes -return_wildcard_routes explicitly, so the window with the setting on changes none of -them. The wildcard deployment gets a unique prefix instead of `openai/*`, which would +leaving wildcard routes out. The other listings the suites run either pass +return_wildcard_routes explicitly or only check that a named model is present, so the +window with the setting on changes none of them. The wildcard deployment gets a unique prefix instead of `openai/*`, which would claim every `openai/...` request the other suites send. """ diff --git a/tests/test_litellm/proxy/response_api_endpoints/test_endpoints.py b/tests/test_litellm/proxy/response_api_endpoints/test_endpoints.py index 656dc33e88c..cd470c8879f 100644 --- a/tests/test_litellm/proxy/response_api_endpoints/test_endpoints.py +++ b/tests/test_litellm/proxy/response_api_endpoints/test_endpoints.py @@ -1351,6 +1351,8 @@ def test_cursor_models_route_delegates_to_model_list(): assert response.status_code == 200, f"{path}: {response.text}" assert response.json() == model_payload assert mock_model_list.call_count == 2 + # Cursor lists every id it gets, so the proxy-wide wildcard default must not reach it + assert all(call.kwargs["return_wildcard_routes"] is False for call in mock_model_list.call_args_list) finally: app.dependency_overrides.pop(user_api_key_auth, None) diff --git a/ui/litellm-dashboard/src/lib/http/schema.d.ts b/ui/litellm-dashboard/src/lib/http/schema.d.ts index d0becba1ba1..4f82a475fb8 100644 --- a/ui/litellm-dashboard/src/lib/http/schema.d.ts +++ b/ui/litellm-dashboard/src/lib/http/schema.d.ts @@ -28389,7 +28389,7 @@ export interface components { 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. + * @description When true, `/v1/models` lists wildcard routes such as `openai/*` next to the models they expand to, without the caller passing `return_wildcard_routes=true`. A request that passes `return_wildcard_routes=false` still leaves them out, as do the dashboard's model pickers and `/cursor/v1/models`. */ model_list_return_wildcard_routes?: boolean | null; /**