fix(vertex_ai): handle reasoning_effort as dict from OpenAI Agents SDK (#19419)

The OpenAI Agents SDK (v0.6.9+) now passes reasoning_effort as a dict
when summary is specified: {"effort": "high", "summary": "auto"}

This change extracts the "effort" value from the dict for Vertex AI,
which only supports thinkingLevel (not summary).

Before: reasoning_effort={"effort": "high"} was silently ignored
After: reasoning_effort={"effort": "high"} correctly maps to thinkingLevel

Fixes #19411
This commit is contained in:
Cesar Garcia 2026-01-21 00:31:25 -03:00 • committed by GitHub
parent b36e704e06
commit b4ed387d24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 91 additions and 17 deletions

View file

@ -988,25 +988,34 @@ class VertexGeminiConfig(VertexAIBaseConfig, BaseConfig):
optional_params["parallel_tool_calls"] = value
elif param == "seed":
optional_params["seed"] = value
elif param == "reasoning_effort" and isinstance(value, str):
# Validate no conflict with thinking_level
VertexGeminiConfig._validate_thinking_config_conflicts(
optional_params=optional_params,
param_name="reasoning_effort",
param_description="thinking_budget",
)
if VertexGeminiConfig._is_gemini_3_or_newer(model):
optional_params["thinkingConfig"] = (
VertexGeminiConfig._map_reasoning_effort_to_thinking_level(
value, model
)
elif param == "reasoning_effort":
# Extract effort value - handle both string and dict formats
# Dict format comes from OpenAI Agents SDK: {"effort": "high", "summary": "auto"}
effort_value: Optional[str] = None
if isinstance(value, str):
effort_value = value
elif isinstance(value, dict):
effort_value = value.get("effort")
if effort_value is not None:
# Validate no conflict with thinking_level
VertexGeminiConfig._validate_thinking_config_conflicts(
optional_params=optional_params,
param_name="reasoning_effort",
param_description="thinking_budget",
)
else:
optional_params["thinkingConfig"] = (
VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(
value, model
if VertexGeminiConfig._is_gemini_3_or_newer(model):
optional_params["thinkingConfig"] = (
VertexGeminiConfig._map_reasoning_effort_to_thinking_level(
effort_value, model
)
)
else:
optional_params["thinkingConfig"] = (
VertexGeminiConfig._map_reasoning_effort_to_thinking_budget(
effort_value, model
)
)
)
elif param == "thinking":
# Validate no conflict with thinking_level
VertexGeminiConfig._validate_thinking_config_conflicts(

View file

@ -1887,6 +1887,71 @@ def test_reasoning_effort_maps_to_thinking_level_gemini_3():
assert result["thinkingConfig"]["includeThoughts"] is False
def test_reasoning_effort_dict_format_gemini_3():
"""
Test that reasoning_effort works when passed as dict format from OpenAI Agents SDK.
The OpenAI Agents SDK passes reasoning_effort as {"effort": "high", "summary": "auto"}
instead of just a string. This test verifies that we correctly extract the effort value.
Related issue: https://github.com/BerriAI/litellm/issues/19411
"""
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (
VertexGeminiConfig,
)
v = VertexGeminiConfig()
model = "gemini-3-pro-preview"
# Test dict format with effort="high" (OpenAI Agents SDK format)
optional_params = {}
non_default_params = {"reasoning_effort": {"effort": "high", "summary": "auto"}}
result = v.map_openai_params(
non_default_params=non_default_params,
optional_params=optional_params,
model=model,
drop_params=False,
)
assert result["thinkingConfig"]["thinkingLevel"] == "high"
assert result["thinkingConfig"]["includeThoughts"] is True
# Test dict format with effort="low"
optional_params = {}
non_default_params = {"reasoning_effort": {"effort": "low"}}
result = v.map_openai_params(
non_default_params=non_default_params,
optional_params=optional_params,
model=model,
drop_params=False,
)
assert result["thinkingConfig"]["thinkingLevel"] == "low"
assert result["thinkingConfig"]["includeThoughts"] is True
# Test dict format with effort="medium"
optional_params = {}
non_default_params = {"reasoning_effort": {"effort": "medium"}}
result = v.map_openai_params(
non_default_params=non_default_params,
optional_params=optional_params,
model=model,
drop_params=False,
)
assert result["thinkingConfig"]["thinkingLevel"] == "high"
assert result["thinkingConfig"]["includeThoughts"] is True
# Test dict format without effort key - should fall back to Gemini 3 default (low)
optional_params = {}
non_default_params = {"reasoning_effort": {"summary": "auto"}}
result = v.map_openai_params(
non_default_params=non_default_params,
optional_params=optional_params,
model=model,
drop_params=False,
)
# Gemini 3 defaults to thinkingLevel="low" when no explicit effort is set
assert result["thinkingConfig"]["thinkingLevel"] == "low"
def test_temperature_default_for_gemini_3():
"""Test that temperature defaults to 1.0 for Gemini 3+ models when not specified"""
from litellm.llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import (