fix(vertex_ai): keep reasoning_effort unsupported on Vertex AI Mistral partner models

Vertex AI Mistral models reused MistralConfig, whose reasoning_effort
advertisement checks the mistral provider entry of the cost map, so
vertex_ai/mistral-medium-3 started advertising reasoning_effort and
drop_params stopped dropping it, turning a 200 into a Vertex 400.
VertexAIMistralConfig scopes that lookup to the vertex_ai provider, and
MistralConfig now reads the provider from its custom_llm_provider
property instead of a hardcoded "mistral".
This commit is contained in:
mateo-berri 2026-09-18 13:16:56 -07:00
parent b4dc081c27
commit c54c0b049d
7 changed files with 51 additions and 8 deletions

View file

@ -1704,6 +1704,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,
)

View file

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

View file

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

View file

@ -35,14 +35,19 @@ if TYPE_CHECKING:
import tiktoken
def _accepted_reasoning_effort(model: str, requested: str) -> str:
declared: Final = declared_reasoning_efforts_for_model(model, "mistral")
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(
"mistral: %s takes reasoning_effort %s, sending %s in place of %s", model, declared, accepted, requested
"%s: %s takes reasoning_effort %s, sending %s in place of %s",
custom_llm_provider,
model,
declared,
accepted,
requested,
)
return accepted
@ -103,9 +108,15 @@ 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]:
is_magistral: Final = "magistral" in model.lower()
accepts_reasoning_effort: Final = is_magistral or supports_reasoning(model=model, custom_llm_provider="mistral")
accepts_reasoning_effort: Final = is_magistral or supports_reasoning(
model=model, custom_llm_provider=self.custom_llm_provider
)
return [
"stream",
"temperature",
@ -187,7 +198,7 @@ class MistralConfig(OpenAIGPTConfig):
if param == "response_format":
optional_params["response_format"] = value
if param == "reasoning_effort" and "magistral" not in model.lower():
optional_params["reasoning_effort"] = _accepted_reasoning_effort(model, value)
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

View file

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

View file

@ -4510,7 +4510,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,
@ -8380,7 +8380,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:

View file

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