mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
Merge pull request #41062 from BerriAI/litellm_mistral_codex_reasoning_effort_client_metadata
fix(mistral): accept reasoning_effort on all models and drop client_metadata for Codex compatibility
This commit is contained in:
commit
d45e04a9fd
12 changed files with 358 additions and 20 deletions
|
|
@ -1700,6 +1700,9 @@ if TYPE_CHECKING:
|
|||
from .llms.vertex_ai.vertex_ai_partner_models.ai21.transformation import (
|
||||
VertexAIAi21Config as VertexAIAi21Config,
|
||||
)
|
||||
from .llms.vertex_ai.vertex_ai_partner_models.mistral.transformation import (
|
||||
VertexAIMistralConfig as VertexAIMistralConfig,
|
||||
)
|
||||
from .llms.bedrock.chat.invoke_handler import (
|
||||
AmazonCohereChatConfig as AmazonCohereChatConfig,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ LLM_CONFIG_NAMES: Final = (
|
|||
"VertexAIAnthropicConfig",
|
||||
"VertexAILlama3Config",
|
||||
"VertexAIAi21Config",
|
||||
"VertexAIMistralConfig",
|
||||
"AmazonCohereChatConfig",
|
||||
"AmazonBedrockGlobalConfig",
|
||||
"AmazonAI21Config",
|
||||
|
|
@ -771,6 +772,10 @@ _LLM_CONFIGS_IMPORT_MAP: Final = {
|
|||
".llms.vertex_ai.vertex_ai_partner_models.ai21.transformation",
|
||||
"VertexAIAi21Config",
|
||||
),
|
||||
"VertexAIMistralConfig": (
|
||||
".llms.vertex_ai.vertex_ai_partner_models.mistral.transformation",
|
||||
"VertexAIMistralConfig",
|
||||
),
|
||||
"AmazonCohereChatConfig": (
|
||||
".llms.bedrock.chat.invoke_handler",
|
||||
"AmazonCohereChatConfig",
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ def get_supported_openai_params(
|
|||
elif custom_llm_provider == "vertex_ai" or custom_llm_provider == "vertex_ai_beta":
|
||||
if request_type == "chat_completion":
|
||||
if model.startswith("mistral"):
|
||||
return litellm.MistralConfig().get_supported_openai_params(model=model)
|
||||
return litellm.VertexAIMistralConfig().get_supported_openai_params(model=model)
|
||||
elif model.startswith("codestral"):
|
||||
return litellm.CodestralTextCompletionConfig().get_supported_openai_params(model=model)
|
||||
elif model.startswith("claude"):
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from typing import TYPE_CHECKING, Any, Final, Literal, cast, get_type_hints, ove
|
|||
|
||||
import httpx
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
from litellm.litellm_core_utils.prompt_templates.common_utils import (
|
||||
handle_messages_with_content_list_to_str_conversion,
|
||||
|
|
@ -20,16 +21,37 @@ from litellm.llms.openai.chat.gpt_transformation import (
|
|||
OpenAIChatCompletionStreamingHandler,
|
||||
OpenAIGPTConfig,
|
||||
)
|
||||
from litellm.router_utils.reasoning_effort_capability import (
|
||||
declared_reasoning_efforts_for_model,
|
||||
nearest_declared_reasoning_effort,
|
||||
)
|
||||
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
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import tiktoken
|
||||
|
||||
|
||||
def _accepted_reasoning_effort(model: str, requested: str, custom_llm_provider: str) -> str:
|
||||
declared: Final = declared_reasoning_efforts_for_model(model, custom_llm_provider)
|
||||
if declared is None:
|
||||
return requested
|
||||
accepted: Final = nearest_declared_reasoning_effort(requested, declared)
|
||||
if accepted != requested:
|
||||
verbose_logger.debug(
|
||||
"%s: %s takes reasoning_effort %s, sending %s in place of %s",
|
||||
custom_llm_provider,
|
||||
model,
|
||||
declared,
|
||||
accepted,
|
||||
requested,
|
||||
)
|
||||
return accepted
|
||||
|
||||
|
||||
class MistralConfig(OpenAIGPTConfig):
|
||||
"""
|
||||
Reference: https://docs.mistral.ai/api/
|
||||
|
|
@ -86,8 +108,16 @@ class MistralConfig(OpenAIGPTConfig):
|
|||
def get_config(cls):
|
||||
return super().get_config()
|
||||
|
||||
@property
|
||||
def custom_llm_provider(self) -> str:
|
||||
return "mistral"
|
||||
|
||||
def get_supported_openai_params(self, model: str) -> list[str]:
|
||||
supported_params: Final = [
|
||||
is_magistral: Final = "magistral" in model.lower()
|
||||
accepts_reasoning_effort: Final = is_magistral or supports_reasoning(
|
||||
model=model, custom_llm_provider=self.custom_llm_provider
|
||||
)
|
||||
return [
|
||||
"stream",
|
||||
"temperature",
|
||||
"top_p",
|
||||
|
|
@ -99,14 +129,10 @@ class MistralConfig(OpenAIGPTConfig):
|
|||
"stop",
|
||||
"response_format",
|
||||
"parallel_tool_calls",
|
||||
*(("thinking",) if is_magistral else ()),
|
||||
*(("reasoning_effort",) if accepts_reasoning_effort else ()),
|
||||
]
|
||||
|
||||
# Add reasoning support for magistral models
|
||||
if "magistral" in model.lower():
|
||||
supported_params.extend(["thinking", "reasoning_effort"])
|
||||
|
||||
return supported_params
|
||||
|
||||
def _map_tool_choice(self, tool_choice: str) -> str:
|
||||
if tool_choice == "auto" or tool_choice == "none":
|
||||
return tool_choice
|
||||
|
|
@ -171,10 +197,9 @@ 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 "magistral" not in model.lower():
|
||||
optional_params["reasoning_effort"] = _accepted_reasoning_effort(model, value, self.custom_llm_provider)
|
||||
if param in ("reasoning_effort", "thinking") and "magistral" in model.lower():
|
||||
# Flag that we need to add reasoning system prompt
|
||||
optional_params["_add_reasoning_prompt"] = True
|
||||
if param == "parallel_tool_calls":
|
||||
|
|
@ -534,11 +559,13 @@ class MistralConfig(OpenAIGPTConfig):
|
|||
if "magistral" in model.lower() and optional_params.get("_add_reasoning_prompt", False):
|
||||
messages = self._add_reasoning_system_prompt_if_needed(messages, optional_params)
|
||||
|
||||
upstream_params: Final = {key: value for key, value in optional_params.items() if key != "client_metadata"}
|
||||
|
||||
# Call parent transform_request which handles _transform_messages
|
||||
return super().transform_request(
|
||||
model=model,
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
optional_params=upstream_params,
|
||||
litellm_params=litellm_params,
|
||||
headers=headers,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
from litellm.llms.mistral.chat.transformation import MistralConfig
|
||||
|
||||
|
||||
class VertexAIMistralConfig(MistralConfig):
|
||||
@property
|
||||
def custom_llm_provider(self) -> str:
|
||||
return "vertex_ai"
|
||||
|
|
@ -37097,6 +37097,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37178,6 +37182,15 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-2",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37195,6 +37208,11 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-3",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37212,6 +37230,11 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-3",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37229,6 +37252,11 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-3",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37246,6 +37274,15 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-2",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37541,6 +37578,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37601,6 +37642,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37618,6 +37663,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37651,6 +37700,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37682,6 +37735,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -60027,6 +60084,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63352,6 +63413,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63369,6 +63434,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63386,6 +63455,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63403,6 +63476,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
|
|||
|
|
@ -103,6 +103,25 @@ def declared_reasoning_efforts_for_model(model: str, custom_llm_provider: str) -
|
|||
return declared_reasoning_efforts(entry)
|
||||
|
||||
|
||||
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. 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]
|
||||
)
|
||||
if requested in ranked or requested not in _STRENGTH_RANK or not ranked:
|
||||
return requested
|
||||
return next((effort for effort in ranked if _STRENGTH_RANK[effort] >= _STRENGTH_RANK[requested]), ranked[-1])
|
||||
|
||||
|
||||
def _supports_none_reasoning_effort(model_info: Mapping[str, object], flag: object) -> bool:
|
||||
"""Opt-in only where a request path refuses the level. AzureOpenAIGPT5Config raises
|
||||
UnsupportedParamsError on reasoning_effort='none' without an explicit true, and it is selected
|
||||
|
|
|
|||
|
|
@ -4526,7 +4526,7 @@ def get_optional_params(
|
|||
drop_params=bool(drop_params),
|
||||
)
|
||||
else:
|
||||
optional_params = litellm.MistralConfig().map_openai_params(
|
||||
optional_params = litellm.VertexAIMistralConfig().map_openai_params(
|
||||
model=model,
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
|
|
@ -8396,7 +8396,7 @@ class ProviderConfigManager:
|
|||
elif model in litellm.vertex_mistral_models:
|
||||
if "codestral" in model:
|
||||
return litellm.CodestralTextCompletionConfig()
|
||||
return litellm.MistralConfig()
|
||||
return litellm.VertexAIMistralConfig()
|
||||
elif model in litellm.vertex_ai_ai21_models:
|
||||
return litellm.VertexAIAi21Config()
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -37097,6 +37097,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37178,6 +37182,15 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-2",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37195,6 +37208,11 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-3",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37212,6 +37230,11 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-3",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37229,6 +37252,11 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"low",
|
||||
"high",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-3",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37246,6 +37274,15 @@
|
|||
"max_tokens": 131072,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 4.4e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"minimal",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"xhigh",
|
||||
"max"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/zai-glm-5-2",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37541,6 +37578,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37601,6 +37642,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37618,6 +37663,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37651,6 +37700,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -37682,6 +37735,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -60027,6 +60084,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63352,6 +63413,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63369,6 +63434,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63386,6 +63455,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 7.5e-06,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-medium-3-5-26-04",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63403,6 +63476,10 @@
|
|||
"max_tokens": 262144,
|
||||
"mode": "chat",
|
||||
"output_cost_per_token": 6e-07,
|
||||
"reasoning_effort_levels": [
|
||||
"none",
|
||||
"high"
|
||||
],
|
||||
"source": "https://docs.mistral.ai/models/model-cards/mistral-small-4-0-26-03",
|
||||
"supports_assistant_prefill": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
|
|||
|
|
@ -51,14 +51,19 @@ class TestMistralReasoningSupport:
|
|||
assert "reasoning_effort" in supported_params
|
||||
assert "thinking" in supported_params
|
||||
|
||||
# Test non-magistral model doesn't include reasoning parameters
|
||||
supported_params_reasoning = mistral_config.get_supported_openai_params(
|
||||
"mistral/mistral-medium-latest"
|
||||
)
|
||||
assert "reasoning_effort" in supported_params_reasoning
|
||||
assert "thinking" not in supported_params_reasoning
|
||||
|
||||
supported_params_normal = mistral_config.get_supported_openai_params(
|
||||
"mistral/mistral-large-latest"
|
||||
)
|
||||
assert "reasoning_effort" not in supported_params_normal
|
||||
assert "thinking" not in supported_params_normal
|
||||
|
||||
def test_map_openai_params_reasoning_effort(self):
|
||||
def test_map_openai_params_reasoning_effort(self, local_model_cost_map):
|
||||
"""Test that reasoning_effort parameter is properly mapped for magistral models."""
|
||||
mistral_config = MistralConfig()
|
||||
|
||||
|
|
@ -73,16 +78,93 @@ class TestMistralReasoningSupport:
|
|||
|
||||
assert result.get("_add_reasoning_prompt") is True
|
||||
|
||||
# Test reasoning_effort ignored for non-magistral model
|
||||
optional_params_normal = {}
|
||||
result_normal = mistral_config.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "low"},
|
||||
optional_params=optional_params_normal,
|
||||
model="mistral/mistral-large-latest",
|
||||
model="mistral/mistral-medium-latest",
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert "_add_reasoning_prompt" not in result_normal
|
||||
assert result_normal["reasoning_effort"] == "high"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "requested", "sent"),
|
||||
[
|
||||
("mistral-medium-latest", "high", "high"),
|
||||
("mistral-medium-latest", "none", "none"),
|
||||
("mistral-medium-latest", "low", "high"),
|
||||
("mistral-medium-latest", "medium", "high"),
|
||||
("mistral-medium-latest", "xhigh", "high"),
|
||||
("mistral-small-latest", "medium", "high"),
|
||||
("mistral-vibe-cli-latest", "medium", "high"),
|
||||
("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"),
|
||||
("zai-glm-5-2", "xhigh", "xhigh"),
|
||||
],
|
||||
)
|
||||
def test_reasoning_effort_is_sent_as_a_level_the_model_accepts(self, local_model_cost_map, model, requested, sent):
|
||||
import litellm
|
||||
|
||||
optional_params = litellm.get_optional_params(
|
||||
model=model,
|
||||
custom_llm_provider="mistral",
|
||||
reasoning_effort=requested,
|
||||
)
|
||||
assert optional_params["reasoning_effort"] == sent
|
||||
|
||||
def test_reasoning_effort_is_forwarded_verbatim_when_the_map_declares_no_levels(
|
||||
self, local_model_cost_map, monkeypatch
|
||||
):
|
||||
import litellm
|
||||
|
||||
monkeypatch.setitem(
|
||||
litellm.model_cost,
|
||||
"mistral/undeclared-reasoner",
|
||||
{"litellm_provider": "mistral", "mode": "chat", "supports_reasoning": True},
|
||||
)
|
||||
optional_params = litellm.get_optional_params(
|
||||
model="undeclared-reasoner",
|
||||
custom_llm_provider="mistral",
|
||||
reasoning_effort="medium",
|
||||
)
|
||||
assert optional_params["reasoning_effort"] == "medium"
|
||||
|
||||
def test_reasoning_effort_stays_unsupported_for_non_reasoning_models(self):
|
||||
import litellm
|
||||
|
||||
with pytest.raises(litellm.UnsupportedParamsError):
|
||||
litellm.get_optional_params(
|
||||
model="codestral-latest",
|
||||
custom_llm_provider="mistral",
|
||||
reasoning_effort="high",
|
||||
)
|
||||
|
||||
dropped = litellm.get_optional_params(
|
||||
model="codestral-latest",
|
||||
custom_llm_provider="mistral",
|
||||
reasoning_effort="high",
|
||||
drop_params=True,
|
||||
)
|
||||
assert "reasoning_effort" not in dropped
|
||||
|
||||
def test_client_metadata_stripped_from_request(self):
|
||||
mistral_config = MistralConfig()
|
||||
|
||||
request = mistral_config.transform_request(
|
||||
model="mistral-medium-latest",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
optional_params={"client_metadata": {"originator": "codex_cli_rs"}, "temperature": 0.2},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert "client_metadata" not in request
|
||||
assert request["temperature"] == 0.2
|
||||
|
||||
def test_map_openai_params_thinking(self):
|
||||
"""Test that thinking parameter is properly mapped for magistral models."""
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import litellm
|
||||
|
||||
|
||||
def test_reasoning_effort_stays_unsupported_on_vertex_partner_models(local_model_cost_map):
|
||||
assert "reasoning_effort" in litellm.get_supported_openai_params(
|
||||
model="mistral-medium-3", custom_llm_provider="mistral"
|
||||
)
|
||||
assert "reasoning_effort" not in litellm.get_supported_openai_params(
|
||||
model="mistral-medium-3", custom_llm_provider="vertex_ai"
|
||||
)
|
||||
dropped = litellm.get_optional_params(
|
||||
model="mistral-medium-3",
|
||||
custom_llm_provider="vertex_ai",
|
||||
reasoning_effort="high",
|
||||
drop_params=True,
|
||||
)
|
||||
assert "reasoning_effort" not in dropped
|
||||
|
|
@ -4,6 +4,7 @@ import litellm
|
|||
from litellm.router_utils.reasoning_effort_capability import (
|
||||
deployment_is_catalog_mapped,
|
||||
intersect_supported_reasoning_efforts,
|
||||
nearest_declared_reasoning_effort,
|
||||
resolve_supported_reasoning_efforts,
|
||||
)
|
||||
|
||||
|
|
@ -415,3 +416,26 @@ class TestGpt6AstraAdvertisesItsDocumentedLevels:
|
|||
"high",
|
||||
"xhigh",
|
||||
)
|
||||
|
||||
|
||||
class TestNearestDeclaredReasoningEffort:
|
||||
def test_a_declared_level_is_kept(self):
|
||||
assert nearest_declared_reasoning_effort("high", ("none", "high")) == "high"
|
||||
assert nearest_declared_reasoning_effort("none", ("none", "high")) == "none"
|
||||
|
||||
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("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"
|
||||
|
||||
def test_a_level_outside_the_strength_order_is_left_for_upstream(self):
|
||||
assert nearest_declared_reasoning_effort("turbo", ("none", "high")) == "turbo"
|
||||
assert nearest_declared_reasoning_effort("medium", ()) == "medium"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue