fix(responses): drop top_p for gpt-5 reasoning models when drop_params is set

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Devin AI 2026-09-16 18:35:49 +00:00
parent 4e996400e2
commit 4f585d3931
3 changed files with 86 additions and 6 deletions

View file

@ -208,8 +208,9 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig):
) -> dict:
"""No mapping applied since inputs are in OpenAI spec already.
GPT-5 models have restrictions on temperature (only temperature=1
is accepted unless reasoning_effort='none' on models that support it).
GPT-5 models have restrictions on temperature and top_p (only temperature=1
is accepted, and top_p is rejected, unless reasoning.effort resolves to
'none' on models that support it).
Apply the same validation used by the chat completions path.
"""
params: Final = dict(response_api_optional_params)
@ -235,12 +236,14 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig):
)
if self._is_gpt_5_model(model=model):
reasoning: Final = params.get("reasoning") or {}
effort: Final = reasoning.get("effort") if isinstance(reasoning, dict) else None
supports_none: Final = self._supports_reasoning_effort_none(model=model)
effort_is_none: Final = supports_none and self._effort_resolves_to_none(model, effort)
temperature: Final = params.get("temperature")
if temperature is not None and temperature != 1:
reasoning: Final = params.get("reasoning") or {}
effort: Final = reasoning.get("effort") if isinstance(reasoning, dict) else None
supports_none: Final = self._supports_reasoning_effort_none(model=model)
if supports_none and self._effort_resolves_to_none(model, effort):
if effort_is_none:
pass # flexible temperature allowed
elif drop_params or litellm.drop_params:
params.pop("temperature", None)
@ -256,6 +259,20 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig):
status_code=400,
)
if "top_p" in params and not effort_is_none:
if drop_params or litellm.drop_params:
params.pop("top_p", None)
else:
raise litellm.UnsupportedParamsError(
message=(
f"{model} only supports top_p when reasoning.effort resolves to 'none', "
"either set explicitly on the request or declared as the model's "
"default_reasoning_effort. "
"To drop unsupported params set `litellm.drop_params = True`"
),
status_code=400,
)
return params
def transform_responses_api_request(

View file

@ -369,6 +369,29 @@ class TestBedrockMantleResponsesTools:
assert "file_search" in str(mock_warning.call_args)
class TestBedrockMantleSamplingParams:
"""Mantle rejects top_p on its gpt-5 reasoning models and non-default temperature
while reasoning is active, the same rule the OpenAI Responses surface applies, so
drop_params must strip both before the request leaves."""
@pytest.mark.parametrize(
"model",
[
"openai.gpt-5.4",
"openai.gpt-5.5",
"openai.gpt-5.6-luna",
],
)
def test_map_openai_params_drops_top_p_and_temperature(self, local_cost_map, model):
params = BedrockMantleResponsesAPIConfig().map_openai_params(
response_api_optional_params={"top_p": 0.9, "temperature": 0.2},
model=model,
drop_params=True,
)
assert "top_p" not in params
assert "temperature" not in params
class TestBedrockMantleResponsesWebSearch:
"""Web Search on Amazon Bedrock is a server-side built-in tool that Mantle runs
itself when the caller passes {"type": "web_search"} on the Responses path, so

View file

@ -1835,6 +1835,46 @@ class TestResponsesSurfaceSharesTheEffortRule:
)
assert ("temperature" in mapped) is temperature_survives
@pytest.mark.parametrize(
"model, effort, top_p_survives",
[
("gpt-5.1", None, True),
("gpt-5.4", None, True),
("gpt-5.5", None, False),
("gpt-5.6-terra", None, False),
("gpt-5.6-sol", None, False),
("gpt-5.6-terra", "none", True),
("gpt-5.6-terra", "medium", False),
("gpt-6-astra", None, False),
("gpt-6-astra", "low", False),
],
)
def test_top_p_follows_the_resolved_effort(self, local_model_cost_map, model, effort, top_p_survives):
params = {"top_p": 0.9}
if effort is not None:
params["reasoning"] = {"effort": effort}
mapped = OpenAIResponsesAPIConfig().map_openai_params(
response_api_optional_params=params,
model=model,
drop_params=True,
)
assert ("top_p" in mapped) is top_p_survives
def test_top_p_raises_without_drop_params(self, local_model_cost_map):
with pytest.raises(litellm.UnsupportedParamsError):
OpenAIResponsesAPIConfig().map_openai_params(
response_api_optional_params={"top_p": 0.9},
model="gpt-5.5",
drop_params=False,
)
mapped = OpenAIResponsesAPIConfig().map_openai_params(
response_api_optional_params={"top_p": 0.9, "reasoning": {"effort": "none"}},
model="gpt-5.6-terra",
drop_params=False,
)
assert mapped["top_p"] == 0.9
class TestFlattenToolSchemaCombinatorsWiring:
"""Regression tests for MCP tools with a top-level anyOf schema (Codex Desktop).