mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-10 08:28:25 +00:00
feat(gemini): allow disabling thought summaries while keeping thinking on
Both reasoning-effort mappers hardcoded includeThoughts to True whenever thinking was on, so thinking ON with summaries OFF was unreachable even though that is the google SDK's own default. Summaries are the narration rather than the reasoning, and for callers that discard them they are pure added latency. Adds litellm.gemini_include_thoughts_default, defaulting to True so nothing changes for anyone who does not set it. It gates the includeThoughts=True branches in the thinkingBudget mapper, the thinkingLevel mapper, and the anthropic-style thinking param mapper. The disable and none paths still force includeThoughts=False: with thinking off there is nothing to summarise.
This commit is contained in:
parent
9bca9dfbb1
commit
c685b1b1bb
3 changed files with 84 additions and 12 deletions
|
|
@ -371,6 +371,7 @@ enable_key_alias_format_validation: bool = (
|
|||
enable_gemini_default_thinking_level_low: bool = (
|
||||
False # opt-in: force thinkingLevel low/minimal for Gemini 3 thinking param mapping
|
||||
)
|
||||
gemini_include_thoughts_default: bool = True # set False to keep Gemini thinking on while dropping thought summaries
|
||||
####################
|
||||
logging: bool = True
|
||||
enable_loadbalancing_on_batch_endpoints: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -793,6 +793,16 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
# - Requires propertyOrdering
|
||||
optional_params["response_schema"] = self._map_response_schema(value=schema)
|
||||
|
||||
@staticmethod
|
||||
def _include_thoughts() -> bool:
|
||||
"""Whether to ask Gemini for thought summaries when thinking is on.
|
||||
|
||||
Thought summaries are the narration, not the reasoning: turning them off leaves
|
||||
thinkingBudget/thinkingLevel untouched and the model still reasons, the response
|
||||
just does not carry the summary back.
|
||||
"""
|
||||
return litellm.gemini_include_thoughts_default
|
||||
|
||||
@staticmethod
|
||||
def _map_reasoning_effort_to_thinking_budget(
|
||||
reasoning_effort: str,
|
||||
|
|
@ -812,22 +822,22 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
|
||||
return {
|
||||
"thinkingBudget": budget,
|
||||
"includeThoughts": True,
|
||||
"includeThoughts": VertexGeminiConfig._include_thoughts(),
|
||||
}
|
||||
elif reasoning_effort == "low":
|
||||
return {
|
||||
"thinkingBudget": DEFAULT_REASONING_EFFORT_LOW_THINKING_BUDGET,
|
||||
"includeThoughts": True,
|
||||
"includeThoughts": VertexGeminiConfig._include_thoughts(),
|
||||
}
|
||||
elif reasoning_effort == "medium":
|
||||
return {
|
||||
"thinkingBudget": DEFAULT_REASONING_EFFORT_MEDIUM_THINKING_BUDGET,
|
||||
"includeThoughts": True,
|
||||
"includeThoughts": VertexGeminiConfig._include_thoughts(),
|
||||
}
|
||||
elif reasoning_effort == "high":
|
||||
return {
|
||||
"thinkingBudget": DEFAULT_REASONING_EFFORT_HIGH_THINKING_BUDGET,
|
||||
"includeThoughts": True,
|
||||
"includeThoughts": VertexGeminiConfig._include_thoughts(),
|
||||
}
|
||||
elif reasoning_effort == "disable":
|
||||
return {
|
||||
|
|
@ -863,18 +873,18 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
is_gemini31pro: Final = model and ("gemini-3.1-pro-preview" in model.lower())
|
||||
if reasoning_effort == "minimal":
|
||||
if is_gemini3flash:
|
||||
return {"thinkingLevel": "minimal", "includeThoughts": True}
|
||||
return {"thinkingLevel": "minimal", "includeThoughts": VertexGeminiConfig._include_thoughts()}
|
||||
else:
|
||||
return {"thinkingLevel": "low", "includeThoughts": True}
|
||||
return {"thinkingLevel": "low", "includeThoughts": VertexGeminiConfig._include_thoughts()}
|
||||
elif reasoning_effort == "low":
|
||||
return {"thinkingLevel": "low", "includeThoughts": True}
|
||||
return {"thinkingLevel": "low", "includeThoughts": VertexGeminiConfig._include_thoughts()}
|
||||
elif reasoning_effort == "medium":
|
||||
if is_gemini31pro or is_gemini3flash:
|
||||
return {"thinkingLevel": "medium", "includeThoughts": True}
|
||||
return {"thinkingLevel": "medium", "includeThoughts": VertexGeminiConfig._include_thoughts()}
|
||||
else:
|
||||
return {"thinkingLevel": "high", "includeThoughts": True}
|
||||
return {"thinkingLevel": "high", "includeThoughts": VertexGeminiConfig._include_thoughts()}
|
||||
elif reasoning_effort == "high":
|
||||
return {"thinkingLevel": "high", "includeThoughts": True}
|
||||
return {"thinkingLevel": "high", "includeThoughts": VertexGeminiConfig._include_thoughts()}
|
||||
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:
|
||||
|
|
@ -950,7 +960,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
if thinking_budget is None or thinking_budget == 0:
|
||||
params["includeThoughts"] = False
|
||||
else:
|
||||
params["includeThoughts"] = True
|
||||
params["includeThoughts"] = VertexGeminiConfig._include_thoughts()
|
||||
# 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()
|
||||
|
|
@ -961,7 +971,7 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
|
|||
else:
|
||||
# For older Gemini models, use thinkingBudget
|
||||
if thinking_enabled and not VertexGeminiConfig._is_thinking_budget_zero(thinking_budget):
|
||||
params["includeThoughts"] = True
|
||||
params["includeThoughts"] = VertexGeminiConfig._include_thoughts()
|
||||
if thinking_budget is not None and isinstance(thinking_budget, int):
|
||||
params["thinkingBudget"] = thinking_budget
|
||||
|
||||
|
|
|
|||
|
|
@ -5553,3 +5553,64 @@ def test_accumulated_json_skips_non_dict_leading_value():
|
|||
|
||||
assert len(out) == 1
|
||||
assert out[0].choices[0].delta.content == "a"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gemini_thought_summaries_off():
|
||||
original = litellm.gemini_include_thoughts_default
|
||||
litellm.gemini_include_thoughts_default = False
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
litellm.gemini_include_thoughts_default = original
|
||||
|
||||
|
||||
@pytest.mark.parametrize("reasoning_effort", ["minimal", "low", "medium", "high"])
|
||||
def test_thinking_budget_includes_thoughts_by_default(reasoning_effort):
|
||||
config = VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(
|
||||
reasoning_effort=reasoning_effort, model="gemini-2.5-pro"
|
||||
)
|
||||
assert config["includeThoughts"] is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("reasoning_effort", ["minimal", "low", "medium", "high"])
|
||||
def test_thinking_budget_can_drop_thought_summaries_while_still_thinking(
|
||||
reasoning_effort, gemini_thought_summaries_off
|
||||
):
|
||||
config = VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(
|
||||
reasoning_effort=reasoning_effort, model="gemini-2.5-pro"
|
||||
)
|
||||
assert config["includeThoughts"] is False
|
||||
assert config["thinkingBudget"] > 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("reasoning_effort", ["minimal", "low", "medium", "high"])
|
||||
def test_thinking_level_can_drop_thought_summaries_while_still_thinking(
|
||||
reasoning_effort, gemini_thought_summaries_off
|
||||
):
|
||||
config = VertexGeminiConfig._map_reasoning_effort_to_thinking_level(
|
||||
reasoning_effort=reasoning_effort, model="gemini-3-pro-preview"
|
||||
)
|
||||
assert config["includeThoughts"] is False
|
||||
assert config["thinkingLevel"] in ("minimal", "low", "medium", "high")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("reasoning_effort", ["disable", "none"])
|
||||
def test_disabling_thinking_still_disables_thought_summaries(reasoning_effort):
|
||||
budget_config = VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(
|
||||
reasoning_effort=reasoning_effort, model="gemini-2.5-pro"
|
||||
)
|
||||
level_config = VertexGeminiConfig._map_reasoning_effort_to_thinking_level(
|
||||
reasoning_effort=reasoning_effort, model="gemini-3-pro-preview"
|
||||
)
|
||||
assert budget_config["includeThoughts"] is False
|
||||
assert level_config["includeThoughts"] is False
|
||||
|
||||
|
||||
def test_thinking_param_can_drop_thought_summaries(gemini_thought_summaries_off):
|
||||
config = VertexGeminiConfig._map_thinking_param(
|
||||
thinking_param={"type": "enabled", "budget_tokens": 2048},
|
||||
model="gemini-2.5-pro",
|
||||
)
|
||||
assert config["includeThoughts"] is False
|
||||
assert config["thinkingBudget"] == 2048
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue