From 7b2597a3983ea0b2e89c5db015b86740461ada67 Mon Sep 17 00:00:00 2001 From: Xinmin Zeng <135568692+fancyboi999@users.noreply.github.com> Date: Wed, 4 Nov 2026 10:23:49 +0800 Subject: [PATCH] fix(responses): apply the chat o-series temperature rule to openai responses --- .../llms/openai/responses/transformation.py | 16 ++++++++++++ .../test_openai_responses_transformation.py | 25 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index 6bbf3598bd8..194dfb680cd 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -519,6 +519,22 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): status_code=400, ) + o_series_temperature: Final = params.get("temperature") + if ( + self.custom_llm_provider == LlmProviders.OPENAI + and o_series_temperature not in (None, 1) + and litellm.openaiOSeriesConfig.is_model_o_series_model(model=model) + ): + if not (drop_params or litellm.drop_params): + raise litellm.UnsupportedParamsError( + message=( + f"O-series models don't support temperature={o_series_temperature}. Only temperature=1 is " + "supported. To drop unsupported params set `litellm.drop_params = True`" + ), + status_code=400, + ) + params.pop("temperature", None) + lookup_name: Final = self._model_map_lookup_name(model) if self._is_gpt_5_model(model=lookup_name): reasoning: Final = params.get("reasoning") or {} diff --git a/tests/unit/llms/openai/responses/test_openai_responses_transformation.py b/tests/unit/llms/openai/responses/test_openai_responses_transformation.py index 6b36a683df7..244fed6fd86 100644 --- a/tests/unit/llms/openai/responses/test_openai_responses_transformation.py +++ b/tests/unit/llms/openai/responses/test_openai_responses_transformation.py @@ -2383,6 +2383,31 @@ class TestPromptCacheOptionsOnResponsesPath: } +@pytest.mark.parametrize("model", ["o1", "o3", "o3-mini", "o4-mini"]) +@pytest.mark.parametrize("temperature", [0, 0.5, 1]) +def test_o_series_temperature_is_dropped_like_chat_completions(model, temperature): + chat = litellm.get_optional_params( + model=model, custom_llm_provider="openai", temperature=temperature, drop_params=True + ) + mapped = OpenAIResponsesAPIConfig().map_openai_params( + response_api_optional_params={"temperature": temperature}, + model=model, + drop_params=True, + ) + assert mapped.get("temperature") == chat.get("temperature") + + +def test_o_series_temperature_raises_like_chat_completions_without_drop_params(): + with pytest.raises(litellm.UnsupportedParamsError): + litellm.get_optional_params(model="o3-mini", custom_llm_provider="openai", temperature=0.5) + with pytest.raises(litellm.UnsupportedParamsError): + OpenAIResponsesAPIConfig().map_openai_params( + response_api_optional_params={"temperature": 0.5}, + model="o3-mini", + drop_params=False, + ) + + class TestResponsesSurfaceSharesTheEffortRule: """The Responses API reaches the same gpt-5 models over a different wire, and the default /v1/messages bridge for openai models routes through it. It carried its own copy of the