From 282ac87617c6005b842e43385e135c3ad335fc4c Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 25 Nov 2025 08:24:22 +0530 Subject: [PATCH] Add temperature support for 5.1 models (#17011) --- .../llms/openai/chat/gpt_5_transformation.py | 25 +++- .../chat/test_azure_gpt5_transformation.py | 62 +++++++++ .../llms/openai/test_gpt5_transformation.py | 119 ++++++++++++++++++ 3 files changed, 204 insertions(+), 2 deletions(-) diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index d18f898cf1c..60a172ef817 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -25,6 +25,15 @@ class OpenAIGPT5Config(OpenAIGPTConfig): def is_model_gpt_5_codex_model(cls, model: str) -> bool: """Check if the model is specifically a GPT-5 Codex variant.""" return "gpt-5-codex" in model + + @classmethod + def is_model_gpt_5_1_model(cls, model: str) -> bool: + """Check if the model is a gpt-5.1 variant. + + gpt-5.1 supports temperature when reasoning_effort="none", + unlike gpt-5 which only supports temperature=1. + """ + return "gpt-5.1" in model def get_supported_openai_params(self, model: str) -> list: from litellm.utils import supports_tool_choice @@ -69,14 +78,26 @@ class OpenAIGPT5Config(OpenAIGPTConfig): if "temperature" in non_default_params: temperature_value: Optional[float] = non_default_params.pop("temperature") if temperature_value is not None: - if temperature_value == 1: + is_gpt_5_1 = self.is_model_gpt_5_1_model(model) + reasoning_effort = ( + non_default_params.get("reasoning_effort") + or optional_params.get("reasoning_effort") + ) + + # gpt-5.1 supports any temperature when reasoning_effort="none" (or not specified, as it defaults to "none") + if is_gpt_5_1 and (reasoning_effort == "none" or reasoning_effort is None): + optional_params["temperature"] = temperature_value + elif temperature_value == 1: optional_params["temperature"] = temperature_value elif litellm.drop_params or drop_params: pass else: raise litellm.utils.UnsupportedParamsError( message=( - "gpt-5 models (including gpt-5-codex) don't support temperature={}. Only temperature=1 is supported. To drop unsupported params set `litellm.drop_params = True`" + "gpt-5 models (including gpt-5-codex) don't support temperature={}. " + "Only temperature=1 is supported. " + "For gpt-5.1, temperature is supported when reasoning_effort='none' (or not specified, as it defaults to 'none'). " + "To drop unsupported params set `litellm.drop_params = True`" ).format(temperature_value), status_code=400, ) diff --git a/tests/test_litellm/llms/azure/chat/test_azure_gpt5_transformation.py b/tests/test_litellm/llms/azure/chat/test_azure_gpt5_transformation.py index 2ef2020b09a..76d069733be 100644 --- a/tests/test_litellm/llms/azure/chat/test_azure_gpt5_transformation.py +++ b/tests/test_litellm/llms/azure/chat/test_azure_gpt5_transformation.py @@ -101,3 +101,65 @@ def test_azure_gpt5_codex_series_transform_request(config: AzureOpenAIGPT5Config ) assert request["model"] == "gpt-5-codex" + +# GPT-5.1 temperature handling tests for Azure +def test_azure_gpt5_1_temperature_with_reasoning_effort_none(config: AzureOpenAIGPT5Config): + """Test that Azure GPT-5.1 supports any temperature when reasoning_effort='none'.""" + params = config.map_openai_params( + non_default_params={"temperature": 0.5, "reasoning_effort": "none"}, + optional_params={}, + model="azure/gpt-5.1", + drop_params=False, + api_version="2024-05-01-preview", + ) + assert params["temperature"] == 0.5 + assert params["reasoning_effort"] == "none" + + +def test_azure_gpt5_1_temperature_without_reasoning_effort(config: AzureOpenAIGPT5Config): + """Test that Azure GPT-5.1 supports any temperature when reasoning_effort is not specified.""" + params = config.map_openai_params( + non_default_params={"temperature": 0.7}, + optional_params={}, + model="azure/gpt-5.1", + drop_params=False, + api_version="2024-05-01-preview", + ) + assert params["temperature"] == 0.7 + + +def test_azure_gpt5_1_temperature_with_reasoning_effort_other_values(config: AzureOpenAIGPT5Config): + """Test that Azure GPT-5.1 only allows temperature=1 when reasoning_effort is not 'none'.""" + # Test that temperature != 1 raises error when reasoning_effort is set to other values + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.7, "reasoning_effort": "low"}, + optional_params={}, + model="azure/gpt-5.1", + drop_params=False, + api_version="2024-05-01-preview", + ) + + # Test that temperature=1 is allowed with other reasoning_effort values + params = config.map_openai_params( + non_default_params={"temperature": 1.0, "reasoning_effort": "medium"}, + optional_params={}, + model="azure/gpt-5.1", + drop_params=False, + api_version="2024-05-01-preview", + ) + assert params["temperature"] == 1.0 + assert params["reasoning_effort"] == "medium" + + +def test_azure_gpt5_1_series_temperature_handling(config: AzureOpenAIGPT5Config): + """Test that Azure GPT-5.1 with gpt5_series prefix supports temperature with reasoning_effort='none'.""" + params = config.map_openai_params( + non_default_params={"temperature": 0.6}, + optional_params={}, + model="gpt5_series/gpt-5.1", + drop_params=False, + api_version="2024-05-01-preview", + ) + assert params["temperature"] == 0.6 + diff --git a/tests/test_litellm/llms/openai/test_gpt5_transformation.py b/tests/test_litellm/llms/openai/test_gpt5_transformation.py index 2e1eacce532..5080a7a7c59 100644 --- a/tests/test_litellm/llms/openai/test_gpt5_transformation.py +++ b/tests/test_litellm/llms/openai/test_gpt5_transformation.py @@ -209,3 +209,122 @@ def test_gpt5_1_reasoning_effort_none(config: OpenAIConfig): drop_params=False, ) assert params["reasoning_effort"] == effort + + +# GPT-5.1 temperature handling tests +def test_gpt5_1_model_detection(gpt5_config: OpenAIGPT5Config): + """Test that GPT-5.1 models are correctly detected.""" + assert gpt5_config.is_model_gpt_5_1_model("gpt-5.1") + assert gpt5_config.is_model_gpt_5_1_model("gpt-5.1-codex") + assert gpt5_config.is_model_gpt_5_1_model("gpt-5.1-chat") + assert not gpt5_config.is_model_gpt_5_1_model("gpt-5") + assert not gpt5_config.is_model_gpt_5_1_model("gpt-5-mini") + assert not gpt5_config.is_model_gpt_5_1_model("gpt-5-codex") + + +def test_gpt5_1_temperature_with_reasoning_effort_none(config: OpenAIConfig): + """Test that GPT-5.1 supports any temperature when reasoning_effort='none'.""" + # Test various temperature values with reasoning_effort="none" + for temp in [0.0, 0.2, 0.5, 0.7, 0.9, 1.0, 1.5, 2.0]: + params = config.map_openai_params( + non_default_params={"temperature": temp, "reasoning_effort": "none"}, + optional_params={}, + model="gpt-5.1", + drop_params=False, + ) + assert params["temperature"] == temp + assert params["reasoning_effort"] == "none" + + +def test_gpt5_1_temperature_without_reasoning_effort(config: OpenAIConfig): + """Test that GPT-5.1 supports any temperature when reasoning_effort is not specified. + + When reasoning_effort is not provided, it defaults to "none" for gpt-5.1, + so temperature should be allowed. + """ + # Test various temperature values without reasoning_effort (defaults to "none") + for temp in [0.0, 0.2, 0.5, 0.7, 0.9, 1.0, 1.5, 2.0]: + params = config.map_openai_params( + non_default_params={"temperature": temp}, + optional_params={}, + model="gpt-5.1", + drop_params=False, + ) + assert params["temperature"] == temp + + +def test_gpt5_1_temperature_with_reasoning_effort_other_values(config: OpenAIConfig): + """Test that GPT-5.1 only allows temperature=1 when reasoning_effort is not 'none'.""" + # Test that temperature != 1 raises error when reasoning_effort is set to other values + for effort in ["low", "medium", "high"]: + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.7, "reasoning_effort": effort}, + optional_params={}, + model="gpt-5.1", + drop_params=False, + ) + + # Test that temperature=1 is allowed with other reasoning_effort values + for effort in ["low", "medium", "high"]: + params = config.map_openai_params( + non_default_params={"temperature": 1.0, "reasoning_effort": effort}, + optional_params={}, + model="gpt-5.1", + drop_params=False, + ) + assert params["temperature"] == 1.0 + assert params["reasoning_effort"] == effort + + +def test_gpt5_1_temperature_with_reasoning_effort_in_optional_params(config: OpenAIConfig): + """Test that reasoning_effort can be in optional_params and still work correctly.""" + # Test with reasoning_effort="none" in optional_params + params = config.map_openai_params( + non_default_params={"temperature": 0.5}, + optional_params={"reasoning_effort": "none"}, + model="gpt-5.1", + drop_params=False, + ) + assert params["temperature"] == 0.5 + + # Test with reasoning_effort="low" in optional_params (should only allow temp=1) + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.5}, + optional_params={"reasoning_effort": "low"}, + model="gpt-5.1", + drop_params=False, + ) + +def test_gpt5_1_temperature_drop_when_not_none(config: OpenAIConfig): + """Test that GPT-5.1 drops temperature when reasoning_effort != 'none' and drop_params=True.""" + params = config.map_openai_params( + non_default_params={"temperature": 0.7, "reasoning_effort": "low"}, + optional_params={}, + model="gpt-5.1", + drop_params=True, + ) + assert "temperature" not in params + assert params["reasoning_effort"] == "low" + + +def test_gpt5_temperature_still_restricted(config: OpenAIConfig): + """Test that regular gpt-5 (not 5.1) still only allows temperature=1.""" + # Regular gpt-5 should still only allow temperature=1 + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.7}, + optional_params={}, + model="gpt-5", + drop_params=False, + ) + + # temperature=1 should still work for gpt-5 + params = config.map_openai_params( + non_default_params={"temperature": 1.0}, + optional_params={}, + model="gpt-5", + drop_params=False, + ) + assert params["temperature"] == 1.0