mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-24 00:52:24 +00:00
fix(gemini): simplify model version check (#42465)
This commit is contained in:
parent
c835a1a982
commit
7056151b91
4 changed files with 68 additions and 28 deletions
|
|
@ -102,7 +102,7 @@ class GoogleAIStudioGeminiConfig(VertexGeminiConfig):
|
|||
"include_server_side_tool_invocations",
|
||||
"service_tier",
|
||||
]
|
||||
if supports_reasoning(model, custom_llm_provider="gemini"):
|
||||
if supports_reasoning(model, custom_llm_provider="gemini") or self._is_gemini_3_or_newer(model):
|
||||
supported_params.append("reasoning_effort")
|
||||
supported_params.append("thinking")
|
||||
if self.is_model_gemini_audio_model(model):
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
## httpx client for vertex ai calls
|
||||
## Initial implementation - covers gemini + image gen calls
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from copy import deepcopy
|
||||
|
|
@ -283,20 +284,15 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
@staticmethod
|
||||
def _is_gemini_3_or_newer(model: str) -> bool:
|
||||
"""
|
||||
Check if the model is Gemini 3 Pro or newer.
|
||||
|
||||
Gemini 3 models include:
|
||||
- gemini-3-pro-preview
|
||||
- gemini-3-flash
|
||||
- gemini-3-flash-preview (Gemini 3 Flash)
|
||||
- gemini-3.1-pro-preview, gemini-3.1-flash, gemini-3.1-flash-lite-preview
|
||||
- gemini-3.5-flash
|
||||
- Any future Gemini 3.x models
|
||||
Check if the model is Gemini 3 or newer.
|
||||
"""
|
||||
# Check for Gemini 3 models
|
||||
if "gemini-3" in model:
|
||||
return True
|
||||
return False
|
||||
model_name = model.split("/")[-1].lower()
|
||||
if not model_name:
|
||||
return False
|
||||
# Pre-Gemini 3 models: gemini-1.x, gemini-2.x, gemini-pro, gemini-flash, gemini-exp
|
||||
if re.match(r"^gemini-(?:[12](?:\.\d+)?|exp|(?:pro|flash)(?!-(?:lite-)?latest$))(?:-|$)", model_name):
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _forward_gemini_function_call_id(model: str) -> bool:
|
||||
|
|
@ -347,9 +343,10 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
if self._supports_penalty_parameters(model):
|
||||
supported_params.extend(["frequency_penalty", "presence_penalty"])
|
||||
|
||||
if supports_reasoning(model):
|
||||
if supports_reasoning(model) or self._is_gemini_3_or_newer(model):
|
||||
supported_params.append("reasoning_effort")
|
||||
supported_params.append("thinking")
|
||||
|
||||
return supported_params
|
||||
|
||||
def map_tool_choice_values(self, model: str, tool_choice: str | dict) -> ToolConfig | None:
|
||||
|
|
@ -871,8 +868,8 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
@staticmethod
|
||||
def _supports_minimal_thinking_level(model: str) -> bool:
|
||||
lowered: Final = model.lower()
|
||||
is_gemini3flash: Final = "gemini-3" in lowered and "flash" in lowered
|
||||
return is_gemini3flash and not is_explicitly_disabled_factory(
|
||||
is_gemini3_or_newer_flash: Final = VertexGeminiConfig._is_gemini_3_or_newer(model) and "flash" in lowered
|
||||
return is_gemini3_or_newer_flash and not is_explicitly_disabled_factory(
|
||||
model=model, custom_llm_provider=None, key="supports_minimal_reasoning_effort"
|
||||
)
|
||||
|
||||
|
|
@ -890,9 +887,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
Returns:
|
||||
GeminiThinkingConfig with thinkingLevel and includeThoughts
|
||||
"""
|
||||
is_gemini3flash: Final = model and ("flash" in model.lower() and "gemini-3" in model.lower())
|
||||
supports_minimal: Final = bool(model) and VertexGeminiConfig._supports_minimal_thinking_level(model)
|
||||
is_gemini31pro: Final = model and ("gemini-3.1-pro-preview" in model.lower())
|
||||
if reasoning_effort == "minimal":
|
||||
if supports_minimal:
|
||||
return {"thinkingLevel": "minimal", "includeThoughts": True}
|
||||
|
|
@ -901,10 +896,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
elif reasoning_effort == "low":
|
||||
return {"thinkingLevel": "low", "includeThoughts": True}
|
||||
elif reasoning_effort == "medium":
|
||||
if is_gemini31pro or is_gemini3flash:
|
||||
return {"thinkingLevel": "medium", "includeThoughts": True}
|
||||
else:
|
||||
return {"thinkingLevel": "high", "includeThoughts": True}
|
||||
return {"thinkingLevel": "medium", "includeThoughts": True}
|
||||
elif reasoning_effort == "high":
|
||||
return {"thinkingLevel": "high", "includeThoughts": True}
|
||||
elif reasoning_effort in ("disable", "none"):
|
||||
|
|
|
|||
|
|
@ -517,7 +517,7 @@ def test_shipped_gemini_chat_baseline_keeps_reasoning_effort_on_unmapped_model(s
|
|||
drop_params=False,
|
||||
)
|
||||
assert isinstance(optional_params, dict)
|
||||
assert optional_params["thinkingConfig"]["thinkingBudget"] > 0
|
||||
assert optional_params["thinkingConfig"]["thinkingLevel"] == "medium"
|
||||
assert optional_params["thinkingConfig"]["includeThoughts"] is True
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2435,10 +2435,16 @@ def test_is_gemini_3_or_newer():
|
|||
VertexGeminiConfig,
|
||||
)
|
||||
|
||||
# Gemini 3 models
|
||||
# Gemini 3+ models
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-3-pro-preview") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-3-flash") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-3-pro") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-3.1-pro-preview") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-test-id-bla") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("test-id-bla") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-flash-latest") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-flash-lite-latest") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-pro-latest") == True
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_or_newer("vertex_ai/gemini-3-pro-preview")
|
||||
== True
|
||||
|
|
@ -2453,11 +2459,53 @@ def test_is_gemini_3_or_newer():
|
|||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-2.0-flash") == False
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-1.5-pro") == False
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-pro") == False
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("gemini-flash") == False
|
||||
|
||||
# Edge cases
|
||||
assert VertexGeminiConfig._is_gemini_3_or_newer("") == False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
[
|
||||
"gemini-3.1-pro-preview",
|
||||
"gemini-3-flash",
|
||||
"gemini-test-id-bla",
|
||||
"test-id-bla",
|
||||
],
|
||||
)
|
||||
def test_gemini_3_reasoning_effort_maps_to_thinking_level(model: str):
|
||||
"""Test that reasoning_effort maps to thinkingLevel and default temperature=1.0"""
|
||||
from litellm.llms.gemini.chat.transformation import GoogleAIStudioGeminiConfig
|
||||
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
|
||||
VertexGeminiConfig,
|
||||
)
|
||||
|
||||
vertex_cfg = VertexGeminiConfig()
|
||||
studio_cfg = GoogleAIStudioGeminiConfig()
|
||||
|
||||
for cfg in (vertex_cfg, studio_cfg):
|
||||
supported = cfg.get_supported_openai_params(model)
|
||||
assert "reasoning_effort" in supported
|
||||
assert "thinking" in supported
|
||||
|
||||
for effort in ("low", "medium", "high"):
|
||||
mapped = vertex_cfg.map_openai_params(
|
||||
non_default_params={"reasoning_effort": effort},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert mapped["thinkingConfig"] == {
|
||||
"thinkingLevel": effort,
|
||||
"includeThoughts": True,
|
||||
}
|
||||
assert mapped["temperature"] == 1.0
|
||||
assert "thinkingBudget" not in mapped["thinkingConfig"]
|
||||
|
||||
|
||||
|
||||
|
||||
def _tool_call_messages(tool_call_id: str):
|
||||
return [
|
||||
{"role": "user", "content": "hi"},
|
||||
|
|
@ -2643,7 +2691,7 @@ def test_reasoning_effort_maps_to_thinking_level_gemini_3():
|
|||
assert result["thinkingConfig"]["thinkingLevel"] == "low"
|
||||
assert result["thinkingConfig"]["includeThoughts"] is True
|
||||
|
||||
# Test medium -> high + includeThoughts=True (medium not available yet)
|
||||
# Test medium -> medium + includeThoughts=True
|
||||
optional_params = {}
|
||||
non_default_params = {"reasoning_effort": "medium"}
|
||||
result = v.map_openai_params(
|
||||
|
|
@ -2652,7 +2700,7 @@ def test_reasoning_effort_maps_to_thinking_level_gemini_3():
|
|||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "high"
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "medium"
|
||||
assert result["thinkingConfig"]["includeThoughts"] is True
|
||||
|
||||
# Test high -> high + includeThoughts=True
|
||||
|
|
@ -2853,7 +2901,7 @@ def test_reasoning_effort_dict_format_gemini_3():
|
|||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "high"
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "medium"
|
||||
assert result["thinkingConfig"]["includeThoughts"] is True
|
||||
|
||||
# Test dict format without effort key - no thinkingConfig should be set
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue