litellm/tests/unit/router_utils
tavren27 4e29aea11c
fix(responses): accept a string or tuple allowed_openai_params on Responses models instead of answering 500 (#51751)
* fix(responses): accept any sequence for allowed_openai_params and give UnsupportedParamsError a response

A deployment whose allowed_openai_params is a string (or an SDK caller passing a tuple) made every
Responses-mode request answer 500 "can only concatenate list". The Responses path now builds the
allowlist from any sequence, matching the chat path.

UnsupportedParamsError now runs BadRequestError's constructor, so it carries response, body and
request like every other 400 instead of raising AttributeError on .response.

* fix(params): read a bare-string allowed_openai_params as one param name on every path

A deployment or request with allowed_openai_params: "presence_penalty" now allowlists presence_penalty
on chat completions, embeddings, the Responses API, the chat-to-Responses bridge, the router's tier
and precall filters, and Mistral's prompt_cache_key check. Before, chat and Responses read the string
letter by letter, so it allowlisted nothing, and the router ignored it.

UnsupportedParamsError's args now hold its own message instead of the BadRequestError one.

* fix(params): read a dict or comma-separated allowed_openai_params the way chat and embeddings did

A dict allowlist is read for its keys and a string is split on commas, so configs that worked on
chat or embeddings before keep working, and the router reads them the same way. The fallback errors
header names an error by its class when its type is empty, so UnsupportedParamsError still shows up
there by name.

* fix(params): read every param name in a string allowed_openai_params

A string allowlist now yields every name in it, whether the names are split by commas or spaces or
written as a list inside the string, so embeddings configs like "dimensions encoding_format" keep
working. A request with no allowlist returns early instead of raising and catching a validation error.

* fix(fallbacks): keep the fallback errors header type for errors other than UnsupportedParamsError

The header named an error by its class whenever its type was empty, which changed "None" to the class name for
timeouts and other errors built without a provider body. Only UnsupportedParamsError needs its class name now that
it inherits an empty type, so every other error keeps the type it carries.

* perf(params): read a string allowed_openai_params with one regex scan

The string reader walked every character in Python and ran twice per request, so a 1 MB allowlist added about
300 ms of event-loop time. `\w+` matches exactly the alphanumeric-or-underscore runs the old loop kept, checked
over every Unicode code point, and runs in C.

* test(params): cover an int allowed_openai_params and an admin request for a model two teams share

An allowlist that is no string, mapping, or sequence now allowlists nothing instead of raising TypeError, and an admin request with no team for a model name two teams share answers the multiple-teams 400 with the model name

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-11-14 04:32:38 -05:00
..
pre_call_checks feat(redis): serve the router's session pins from a native store (#50870) 2026-11-13 03:22:28 +00:00
__init__.py test: add __init__.py to intermediate tests/unit packages 2026-09-20 12:55:27 +00:00
test_access_windows.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_add_retry_fallback_headers.py fix(responses): accept a string or tuple allowed_openai_params on Responses models instead of answering 500 (#51751) 2026-11-14 04:32:38 -05:00
test_client_initalization_utils.py refactor(router): delete the python router core, the rust core is the only core (#50178) 2026-11-05 10:40:46 -08:00
test_cooldown_cache.py feat(redis): serve the proxy's common Redis call with Rust stores (#50170) 2026-11-06 06:01:11 +00:00
test_cooldown_handlers.py fix(completion)!: answer 400 for a chat message without a role (#51124) 2026-11-11 20:59:19 +00:00
test_deployment_pricing.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_embedding_batch_size_check.py feat(embeddings): enforce per-request input batch limit (#44574) 2026-10-20 11:35:18 +00:00
test_endpoint_eligibility.py feat(router): opt in to non-chat deployment filtering (#46257) 2026-10-29 08:33:36 -07:00
test_fallback_event_handlers.py feat(messages): serve anthropic messages on rust only (#51119) 2026-11-12 00:07:20 +00:00
test_fallback_event_v2_dispatch.py feat(custom-logger-v2): add types, dispatcher and route callback call sites (step 0) (#51214) 2026-11-13 22:08:05 +00:00
test_get_retry_from_policy.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_handle_error.py fix(completion)!: answer 400 for a chat message without a role (#51124) 2026-11-11 20:59:19 +00:00
test_health_check_allowed_fails_integration.py feat(redis): serve the proxy's common Redis call with Rust stores (#50170) 2026-11-06 06:01:11 +00:00
test_health_state_cache.py feat(redis): serve the health checks' deployment states from a native store (#50357) 2026-11-13 03:22:28 +00:00
test_kubernetes_pod_discovery.py refactor(router): delete the python router core, the rust core is the only core (#50178) 2026-11-05 10:40:46 -08:00
test_pattern_match_deployments.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_prompt_caching_cache.py fix(anthropic)!: carry prompt_cache_breakpoint to cache_control on chat completions to Claude (#49783) 2026-11-03 12:56:22 +00:00
test_ptu_shares.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_reasoning_effort_capability.py refactor(router): route the router family through RoutingContext and close the outside surface (#49118) 2026-10-30 19:18:54 -07:00
test_request_priority.py fix(router)!: schedule default_priority requests once and reject a malformed priority (#47498) 2026-10-20 08:00:57 +00:00
test_router_health_check_routing.py refactor(router): delete the python router core, the rust core is the only core (#50178) 2026-11-05 10:40:46 -08:00
test_router_interactions_endpoints.py refactor(router): delete the python router core, the rust core is the only core (#50178) 2026-11-05 10:40:46 -08:00
test_router_utils_common_utils.py fix(responses): accept a string or tuple allowed_openai_params on Responses models instead of answering 500 (#51751) 2026-11-14 04:32:38 -05:00
test_routing_read_batch.py refactor(redis): delete the Python RedisBatch now that every request op is native (#51383) 2026-11-13 03:22:28 +00:00