mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(gemini): read the Flash tier off the version too, not "gemini-3"
`_map_reasoning_effort_to_thinking_level` and `_map_thinking_param` each re-derived the Flash tier with the same substring the outer gate just stopped using, so a rolling alias reached the Gemini 3 branch and was then demoted inside it: `reasoning_effort="minimal"` on `gemini-flash-latest` returned `thinkingLevel="low"`, and `"none"` / `"disable"` likewise, so the caller silently got more thinking than it asked for. Closes #18245. Both sites now share `_is_gemini_3_flash_or_newer`, which reuses the major version read and so covers Gemini 4 Flash without a code change. Flash-Lite counts; Pro does not, since MINIMAL is a Flash-tier level. Pro keeps "low" for minimal and "high" for medium, unchanged.
This commit is contained in:
parent
a686f36f0c
commit
a190e6bc11
2 changed files with 158 additions and 5 deletions
|
|
@ -282,6 +282,16 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
return int(major_version.group(1)) >= 3
|
||||
return model.split("/")[-1] in GEMINI_ROLLING_LATEST_ALIASES
|
||||
|
||||
@staticmethod
|
||||
def _is_gemini_3_flash_or_newer(model: str | None) -> bool:
|
||||
"""
|
||||
Check if the model is a Gemini 3 or newer Flash, the tier that accepts
|
||||
the MINIMAL thinking level. Flash-Lite counts, Pro does not.
|
||||
"""
|
||||
if not model:
|
||||
return False
|
||||
return VertexGeminiConfig._is_gemini_3_or_newer(model) and "flash" in model.lower()
|
||||
|
||||
@staticmethod
|
||||
def _forward_gemini_function_call_id(model: str) -> bool:
|
||||
"""
|
||||
|
|
@ -866,10 +876,7 @@ 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())
|
||||
is_gemini3flash: Final = VertexGeminiConfig._is_gemini_3_flash_or_newer(model)
|
||||
is_gemini31pro: Final = model and ("gemini-3.1-pro-preview" in model.lower())
|
||||
if reasoning_effort == "minimal":
|
||||
if is_gemini3flash:
|
||||
|
|
@ -963,7 +970,7 @@ 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()
|
||||
is_gemini3flash: Final = VertexGeminiConfig._is_gemini_3_flash_or_newer(model)
|
||||
params["thinkingLevel"] = "minimal" if is_gemini3flash else "low"
|
||||
else:
|
||||
# Thinking disabled
|
||||
|
|
|
|||
|
|
@ -2349,6 +2349,152 @@ def test_thought_signature_fallback_for_rolling_latest_alias():
|
|||
assert not any("thoughtSignature" in part for part in parts)
|
||||
|
||||
|
||||
def test_is_gemini_3_flash_or_newer():
|
||||
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
|
||||
VertexGeminiConfig,
|
||||
)
|
||||
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-3-flash") == True
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-3-flash-preview") == True
|
||||
)
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-3.1-flash") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-3.5-flash") == True
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer(
|
||||
"gemini-3.1-flash-lite-preview"
|
||||
)
|
||||
== True
|
||||
)
|
||||
|
||||
# Rolling aliases resolving to a Flash tier
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-flash-latest") == True
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-flash-lite-latest")
|
||||
== True
|
||||
)
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini/gemini-flash-latest")
|
||||
== True
|
||||
)
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer("vertex_ai/gemini-flash-latest")
|
||||
== True
|
||||
)
|
||||
|
||||
# Later major versions, without a code change
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-4-flash") == True
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini/gemini-10-flash") == True
|
||||
|
||||
# MINIMAL is a Flash-tier level, so Pro is excluded
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-pro-latest") == False
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-3-pro-preview") == False
|
||||
)
|
||||
|
||||
# Older majors are excluded
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("gemini-2.5-flash") == False
|
||||
assert (
|
||||
VertexGeminiConfig._is_gemini_3_flash_or_newer(
|
||||
"gemini-2.5-flash-native-audio-latest"
|
||||
)
|
||||
== False
|
||||
)
|
||||
|
||||
# Edge cases
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer(None) == False
|
||||
assert VertexGeminiConfig._is_gemini_3_flash_or_newer("") == False
|
||||
|
||||
|
||||
def test_reasoning_effort_minimal_reaches_minimal_on_rolling_flash_alias():
|
||||
"""
|
||||
`reasoning_effort="minimal"` must reach `thinkingLevel="minimal"` on the
|
||||
Flash tier. `gemini-flash-latest` serves Gemini 3.x Flash, so it was
|
||||
demoted to "low" and the caller silently got more thinking than it asked
|
||||
for.
|
||||
"""
|
||||
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
|
||||
VertexGeminiConfig,
|
||||
)
|
||||
|
||||
v = VertexGeminiConfig()
|
||||
|
||||
for model in [
|
||||
"gemini-flash-latest",
|
||||
"gemini/gemini-flash-latest",
|
||||
"gemini-flash-lite-latest",
|
||||
"gemini-3.5-flash",
|
||||
]:
|
||||
result = v.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "minimal"},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "minimal", model
|
||||
assert result["thinkingConfig"]["includeThoughts"] is True
|
||||
|
||||
# Pro keeps "low" — MINIMAL is a Flash-tier level
|
||||
result = v.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "minimal"},
|
||||
optional_params={},
|
||||
model="gemini-pro-latest",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "low"
|
||||
|
||||
|
||||
def test_reasoning_effort_medium_reaches_medium_on_rolling_flash_alias():
|
||||
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
|
||||
VertexGeminiConfig,
|
||||
)
|
||||
|
||||
v = VertexGeminiConfig()
|
||||
|
||||
result = v.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "medium"},
|
||||
optional_params={},
|
||||
model="gemini-flash-latest",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "medium"
|
||||
|
||||
# Pro (other than 3.1) still escalates to "high"
|
||||
result = v.map_openai_params(
|
||||
non_default_params={"reasoning_effort": "medium"},
|
||||
optional_params={},
|
||||
model="gemini-pro-latest",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "high"
|
||||
|
||||
|
||||
def test_default_thinking_level_reaches_minimal_on_rolling_flash_alias(monkeypatch):
|
||||
"""
|
||||
The `enable_gemini_default_thinking_level_low` opt-in reads the Flash tier
|
||||
off the same helper, so a rolling alias is not demoted to "low" there
|
||||
either.
|
||||
"""
|
||||
import litellm
|
||||
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
|
||||
VertexGeminiConfig,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
litellm, "enable_gemini_default_thinking_level_low", True, raising=False
|
||||
)
|
||||
|
||||
params = VertexGeminiConfig._map_thinking_param(
|
||||
{"type": "enabled", "budget_tokens": 2048}, model="gemini-flash-latest"
|
||||
)
|
||||
assert params["thinkingLevel"] == "minimal"
|
||||
|
||||
params = VertexGeminiConfig._map_thinking_param(
|
||||
{"type": "enabled", "budget_tokens": 2048}, model="gemini-pro-latest"
|
||||
)
|
||||
assert params["thinkingLevel"] == "low"
|
||||
|
||||
|
||||
def _tool_call_messages(tool_call_id: str):
|
||||
return [
|
||||
{"role": "user", "content": "hi"},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue