mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
fix(mistral): forward reasoning_effort on native hybrid reasoning models
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
f6b9518ddb
commit
7e4d59e2d5
2 changed files with 65 additions and 7 deletions
|
|
@ -24,7 +24,7 @@ from litellm.secret_managers.main import get_secret_str
|
|||
from litellm.types.llms.mistral import MistralThinkingBlock, MistralToolCallMessage
|
||||
from litellm.types.llms.openai import AllMessageValues
|
||||
from litellm.types.utils import ModelResponse, ModelResponseStream
|
||||
from litellm.utils import convert_to_model_response_object
|
||||
from litellm.utils import convert_to_model_response_object, supports_reasoning
|
||||
|
||||
|
||||
class MistralConfig(OpenAIGPTConfig):
|
||||
|
|
@ -98,12 +98,26 @@ class MistralConfig(OpenAIGPTConfig):
|
|||
"parallel_tool_calls",
|
||||
]
|
||||
|
||||
# Add reasoning support for magistral models
|
||||
if "magistral" in model.lower():
|
||||
if self._is_magistral_model(model):
|
||||
supported_params.extend(["thinking", "reasoning_effort"])
|
||||
elif self._supports_native_reasoning_effort(model):
|
||||
supported_params.append("reasoning_effort")
|
||||
|
||||
return supported_params
|
||||
|
||||
@staticmethod
|
||||
def _is_magistral_model(model: str) -> bool:
|
||||
return "magistral" in model.lower()
|
||||
|
||||
@staticmethod
|
||||
def _supports_native_reasoning_effort(model: str) -> bool:
|
||||
"""
|
||||
Mistral's hybrid reasoning models (mistral-medium-3-5 and newer) take ``reasoning_effort``
|
||||
directly on /chat/completions, so it is forwarded as-is instead of being emulated with the
|
||||
magistral system prompt: https://docs.mistral.ai/capabilities/reasoning
|
||||
"""
|
||||
return supports_reasoning(model=model, custom_llm_provider="mistral")
|
||||
|
||||
def _map_tool_choice(self, tool_choice: str) -> str:
|
||||
if tool_choice == "auto" or tool_choice == "none":
|
||||
return tool_choice
|
||||
|
|
@ -168,10 +182,12 @@ class MistralConfig(OpenAIGPTConfig):
|
|||
optional_params["extra_body"] = {"random_seed": value}
|
||||
if param == "response_format":
|
||||
optional_params["response_format"] = value
|
||||
if param == "reasoning_effort" and "magistral" in model.lower():
|
||||
# Flag that we need to add reasoning system prompt
|
||||
optional_params["_add_reasoning_prompt"] = True
|
||||
if param == "thinking" and "magistral" in model.lower():
|
||||
if param == "reasoning_effort" and value is not None:
|
||||
if self._is_magistral_model(model):
|
||||
optional_params["_add_reasoning_prompt"] = True
|
||||
elif self._supports_native_reasoning_effort(model):
|
||||
optional_params["reasoning_effort"] = value
|
||||
if param == "thinking" and self._is_magistral_model(model):
|
||||
# Flag that we need to add reasoning system prompt
|
||||
optional_params["_add_reasoning_prompt"] = True
|
||||
if param == "parallel_tool_calls":
|
||||
|
|
|
|||
|
|
@ -311,6 +311,48 @@ class TestMistralReasoningSupport:
|
|||
assert len(result["messages"]) == 1
|
||||
assert result["messages"][0]["role"] == "user"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
["mistral/mistral-medium-3-5", "mistral-medium-3-5", "mistral/mistral-medium-latest"],
|
||||
)
|
||||
def test_native_reasoning_model_supports_reasoning_effort(self, model):
|
||||
"""Hybrid reasoning models take reasoning_effort natively, see https://github.com/BerriAI/litellm/issues/36407"""
|
||||
supported_params = MistralConfig().get_supported_openai_params(model)
|
||||
|
||||
assert "reasoning_effort" in supported_params
|
||||
assert "thinking" not in supported_params
|
||||
|
||||
def test_native_reasoning_effort_forwarded_to_request_body(self):
|
||||
mistral_config = MistralConfig()
|
||||
|
||||
optional_params = mistral_config.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "high"},
|
||||
optional_params={},
|
||||
model="mistral/mistral-medium-3-5",
|
||||
drop_params=False,
|
||||
)
|
||||
assert optional_params == {"reasoning_effort": "high"}
|
||||
|
||||
request = mistral_config.transform_request(
|
||||
model="mistral/mistral-medium-3-5",
|
||||
messages=[{"role": "user", "content": "What is 15 * 7?"}],
|
||||
optional_params=optional_params,
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert request["reasoning_effort"] == "high"
|
||||
assert len(request["messages"]) == 1
|
||||
|
||||
def test_magistral_reasoning_effort_stays_prompt_based(self):
|
||||
optional_params = MistralConfig().map_openai_params(
|
||||
non_default_params={"reasoning_effort": "high"},
|
||||
optional_params={},
|
||||
model="mistral/magistral-medium-2506",
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert optional_params == {"_add_reasoning_prompt": True}
|
||||
|
||||
def test_case_insensitive_magistral_detection(self):
|
||||
"""Test that magistral model detection is case-insensitive."""
|
||||
mistral_config = MistralConfig()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue