mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-28 01:32:17 +00:00
fix(gemini): map minimal thinking to low for Gemini 3.7 and 3.8 Flash
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
7e3ca1421e
commit
e7454e52e6
2 changed files with 95 additions and 18 deletions
|
|
@ -110,6 +110,7 @@ else:
|
|||
|
||||
|
||||
SUPPORTED_REASONING_EFFORTS: Final = ("minimal", "low", "medium", "high", "none", "disable")
|
||||
GEMINI_FLASH_MODELS_WITHOUT_MINIMAL_THINKING: Final = ("gemini-3.7-flash", "gemini-3.8-flash")
|
||||
|
||||
|
||||
def _unsupported_reasoning_effort(reasoning_effort: str) -> UnsupportedParamsError:
|
||||
|
|
@ -860,6 +861,12 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
else:
|
||||
raise _unsupported_reasoning_effort(reasoning_effort)
|
||||
|
||||
@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 any(m in lowered for m in GEMINI_FLASH_MODELS_WITHOUT_MINIMAL_THINKING)
|
||||
|
||||
@staticmethod
|
||||
def _map_reasoning_effort_to_thinking_level(
|
||||
reasoning_effort: str,
|
||||
|
|
@ -874,13 +881,11 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
Returns:
|
||||
GeminiThinkingConfig with thinkingLevel and includeThoughts
|
||||
"""
|
||||
# Check if this is gemini-3-flash which supports MINIMAL thinking level
|
||||
# Covers gemini-3-flash, gemini-3-flash-preview, gemini-3.1-flash, gemini-3.1-flash-lite-preview,
|
||||
# gemini-3.5-flash, and any future 3.x-flash variants.
|
||||
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 is_gemini3flash:
|
||||
if supports_minimal:
|
||||
return {"thinkingLevel": "minimal", "includeThoughts": True}
|
||||
else:
|
||||
return {"thinkingLevel": "low", "includeThoughts": True}
|
||||
|
|
@ -893,18 +898,11 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
return {"thinkingLevel": "high", "includeThoughts": True}
|
||||
elif reasoning_effort == "high":
|
||||
return {"thinkingLevel": "high", "includeThoughts": True}
|
||||
elif reasoning_effort == "disable":
|
||||
# Gemini 3 cannot fully disable thinking, so we use "minimal" for gemini-3-flash-preview, "low" for others
|
||||
if is_gemini3flash:
|
||||
return {"thinkingLevel": "minimal", "includeThoughts": False}
|
||||
else:
|
||||
return {"thinkingLevel": "low", "includeThoughts": False}
|
||||
elif reasoning_effort == "none":
|
||||
# For gemini-3-flash-preview, use "minimal" instead of "low"
|
||||
if is_gemini3flash:
|
||||
return {"thinkingLevel": "minimal", "includeThoughts": False}
|
||||
else:
|
||||
return {"thinkingLevel": "low", "includeThoughts": False}
|
||||
elif reasoning_effort in ("disable", "none"):
|
||||
return {
|
||||
"thinkingLevel": "minimal" if supports_minimal else "low",
|
||||
"includeThoughts": False,
|
||||
}
|
||||
else:
|
||||
raise _unsupported_reasoning_effort(reasoning_effort)
|
||||
|
||||
|
|
@ -971,8 +969,9 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
params["includeThoughts"] = True
|
||||
# Follow provider defaults unless explicitly opted into legacy behavior.
|
||||
if litellm.enable_gemini_default_thinking_level_low is True:
|
||||
is_gemini3flash: Final = "gemini-3" in model.lower() and "flash" in model.lower()
|
||||
params["thinkingLevel"] = "minimal" if is_gemini3flash else "low"
|
||||
params["thinkingLevel"] = (
|
||||
"minimal" if VertexGeminiConfig._supports_minimal_thinking_level(model) else "low"
|
||||
)
|
||||
else:
|
||||
# Thinking disabled
|
||||
params["includeThoughts"] = False
|
||||
|
|
|
|||
|
|
@ -2678,6 +2678,84 @@ def test_reasoning_effort_maps_to_thinking_level_gemini_3():
|
|||
assert result["thinkingConfig"]["includeThoughts"] is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
[
|
||||
"gemini-3.7-flash",
|
||||
"vertex_ai/gemini-3.8-flash",
|
||||
"gemini-3.8-flash-preview",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("reasoning_effort", "include_thoughts"),
|
||||
[("minimal", True), ("none", False), ("disable", False)],
|
||||
)
|
||||
def test_gemini_37_38_flash_floor_minimal_thinking_level(
|
||||
model, reasoning_effort, include_thoughts
|
||||
):
|
||||
result = VertexGeminiConfig._map_reasoning_effort_to_thinking_level(
|
||||
reasoning_effort, model
|
||||
)
|
||||
|
||||
assert result["thinkingLevel"] == "low"
|
||||
assert result["includeThoughts"] is include_thoughts
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "reasoning_effort", "expected_level", "include_thoughts"),
|
||||
[
|
||||
("gemini-3-flash-preview", "minimal", "minimal", True),
|
||||
("gemini-3-flash-preview", "none", "minimal", False),
|
||||
("gemini-3-flash-preview", "disable", "minimal", False),
|
||||
("gemini-3.6-flash", "minimal", "minimal", True),
|
||||
("gemini-3.6-flash", "none", "minimal", False),
|
||||
("gemini-3.6-flash", "disable", "minimal", False),
|
||||
("gemini-3.5-flash", "minimal", "minimal", True),
|
||||
("gemini-3.5-flash", "none", "minimal", False),
|
||||
("gemini-3.5-flash", "disable", "minimal", False),
|
||||
("gemini-3.8-flash", "medium", "medium", True),
|
||||
],
|
||||
)
|
||||
def test_gemini_flash_minimal_thinking_support(
|
||||
model, reasoning_effort, expected_level, include_thoughts
|
||||
):
|
||||
result = VertexGeminiConfig._map_reasoning_effort_to_thinking_level(
|
||||
reasoning_effort, model
|
||||
)
|
||||
|
||||
assert result["thinkingLevel"] == expected_level
|
||||
assert result["includeThoughts"] is include_thoughts
|
||||
|
||||
|
||||
def test_gemini_38_flash_feature_flag_uses_low_thinking_level(monkeypatch):
|
||||
monkeypatch.setattr(litellm, "enable_gemini_default_thinking_level_low", True)
|
||||
thinking_param = {"type": "enabled", "budget_tokens": 1024}
|
||||
|
||||
result_38 = VertexGeminiConfig._map_thinking_param(
|
||||
thinking_param, model="gemini-3.8-flash"
|
||||
)
|
||||
result_36 = VertexGeminiConfig._map_thinking_param(
|
||||
thinking_param, model="gemini-3.6-flash"
|
||||
)
|
||||
|
||||
assert result_38["thinkingLevel"] == "low"
|
||||
assert result_36["thinkingLevel"] == "minimal"
|
||||
|
||||
|
||||
def test_gemini_38_flash_public_reasoning_effort_none_uses_low():
|
||||
result = VertexGeminiConfig().map_openai_params(
|
||||
non_default_params={"reasoning_effort": "none"},
|
||||
optional_params={},
|
||||
model="gemini-3.8-flash",
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert result["thinkingConfig"] == {
|
||||
"thinkingLevel": "low",
|
||||
"includeThoughts": False,
|
||||
}
|
||||
|
||||
|
||||
def test_reasoning_effort_dict_format_gemini_3():
|
||||
"""
|
||||
Test that reasoning_effort works when passed as dict format from OpenAI Agents SDK.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue