fix(proxy): keep /cursor/v1/models off the wildcard routes default

Cursor offers every id /cursor/v1/models returns and sends no query params,
so with model_list_return_wildcard_routes on it would list openai/* with no
way to opt out. Pin return_wildcard_routes=False there, as before the setting,
and say which listings the setting leaves alone in its description.
This commit is contained in:
shrey kharbanda 2026-09-28 14:06:19 -07:00
parent 7eb134a14c
commit 249a9184bd
5 changed files with 14 additions and 8 deletions

View file

@ -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(

View file

@ -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(

View file

@ -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.
"""

View file

@ -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)

View file

@ -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;
/**