From b4dc081c275da7b631faa9cf59782a3cb5452141 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Fri, 18 Sep 2026 12:22:34 -0700 Subject: [PATCH] fix(mistral): never round reasoning_effort none onto the strength ladder --- litellm/router_utils/reasoning_effort_capability.py | 8 +++++--- .../llms/mistral/test_mistral_chat_transformation.py | 3 ++- .../router_utils/test_reasoning_effort_capability.py | 6 +++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/litellm/router_utils/reasoning_effort_capability.py b/litellm/router_utils/reasoning_effort_capability.py index f880c846500..1d7656f253e 100644 --- a/litellm/router_utils/reasoning_effort_capability.py +++ b/litellm/router_utils/reasoning_effort_capability.py @@ -103,15 +103,17 @@ def declared_reasoning_efforts_for_model(model: str, custom_llm_provider: str) - return declared_reasoning_efforts(entry) -REASONING_EFFORT_STRENGTH_ORDER: Final = ("none", "minimal", "low", "medium", "high", "xhigh", "max") +REASONING_EFFORT_STRENGTH_ORDER: Final = ("minimal", "low", "medium", "high", "xhigh", "max") _STRENGTH_RANK: Final = MappingProxyType({effort: rank for rank, effort in enumerate(REASONING_EFFORT_STRENGTH_ORDER)}) def nearest_declared_reasoning_effort(requested: str, declared: Sequence[str]) -> str: """Rounds a request up to the weakest declared level at least as strong as it, and down to the strongest declared level when it asks for more than the model has, so the caller gets no less - reasoning than it asked for instead of a rejected call. A level outside the strength order is - returned as is for upstream to judge.""" + reasoning than it asked for instead of a rejected call. none is the off switch rather than a + strength, so it is never rounded onto the ladder and no level is rounded down to it: a caller + who turned reasoning off must not be billed for it, and a model that cannot turn it off says so + itself. A level outside the strength order is likewise returned as is for upstream to judge.""" ranked: Final = sorted( (effort for effort in declared if effort in _STRENGTH_RANK), key=lambda effort: _STRENGTH_RANK[effort] ) diff --git a/tests/test_litellm/llms/mistral/test_mistral_chat_transformation.py b/tests/test_litellm/llms/mistral/test_mistral_chat_transformation.py index a68ba9f570c..8fb3b3c43df 100644 --- a/tests/test_litellm/llms/mistral/test_mistral_chat_transformation.py +++ b/tests/test_litellm/llms/mistral/test_mistral_chat_transformation.py @@ -99,7 +99,8 @@ class TestMistralReasoningSupport: ("mistral-medium-latest", "xhigh", "high"), ("mistral-small-latest", "medium", "high"), ("mistral-vibe-cli-latest", "medium", "high"), - ("zai-glm-5", "none", "low"), + ("zai-glm-5", "none", "none"), + ("zai-glm-5", "minimal", "low"), ("zai-glm-5", "medium", "high"), ("zai-glm-5", "xhigh", "max"), ("zai-glm-5-2", "medium", "medium"), diff --git a/tests/test_litellm/router_utils/test_reasoning_effort_capability.py b/tests/test_litellm/router_utils/test_reasoning_effort_capability.py index ca4a3517bfc..adee44aa8a3 100644 --- a/tests/test_litellm/router_utils/test_reasoning_effort_capability.py +++ b/tests/test_litellm/router_utils/test_reasoning_effort_capability.py @@ -425,9 +425,13 @@ class TestNearestDeclaredReasoningEffort: def test_an_undeclared_level_rounds_up_to_the_next_declared_one(self): assert nearest_declared_reasoning_effort("medium", ("none", "high")) == "high" - assert nearest_declared_reasoning_effort("none", ("low", "high", "max")) == "low" + assert nearest_declared_reasoning_effort("minimal", ("low", "high", "max")) == "low" assert nearest_declared_reasoning_effort("xhigh", ("low", "high", "max")) == "max" + def test_none_is_a_switch_that_is_never_rounded_in_either_direction(self): + assert nearest_declared_reasoning_effort("none", ("low", "high", "max")) == "none" + assert nearest_declared_reasoning_effort("medium", ("none",)) == "medium" + def test_a_level_above_the_ceiling_takes_the_strongest_declared_one(self): assert nearest_declared_reasoning_effort("max", ("none", "high")) == "high" assert nearest_declared_reasoning_effort("xhigh", ("none", "low", "medium", "high")) == "high"