diff --git a/litellm/llms/azure/chat/gpt_5_transformation.py b/litellm/llms/azure/chat/gpt_5_transformation.py index f1bfd96de94..986271edcba 100644 --- a/litellm/llms/azure/chat/gpt_5_transformation.py +++ b/litellm/llms/azure/chat/gpt_5_transformation.py @@ -19,19 +19,12 @@ class AzureOpenAIGPT5Config(AzureOpenAIConfig, OpenAIGPT5Config): GPT5_SERIES_ROUTE = "gpt5_series/" @classmethod - def _supports_reasoning_effort_level(cls, model: str, level: str) -> bool: - """Override to handle gpt5_series/ prefix used for Azure routing. - - The parent class calls ``_supports_factory(model, custom_llm_provider=None)`` - which fails to resolve ``gpt5_series/gpt-5.1`` to the correct Azure model - entry. Strip the prefix and prepend ``azure/`` so the lookup finds - ``azure/gpt-5.1`` in model_prices_and_context_window.json. - """ + def _model_map_lookup_name(cls, model: str) -> str: if model.startswith(cls.GPT5_SERIES_ROUTE): - model = "azure/" + model[len(cls.GPT5_SERIES_ROUTE) :] - elif not model.startswith("azure/"): - model = "azure/" + model - return super()._supports_reasoning_effort_level(model, level) + return "azure/" + model[len(cls.GPT5_SERIES_ROUTE) :] + if model.startswith("azure/"): + return model + return "azure/" + model @classmethod def is_model_gpt_5_model(cls, model: str) -> bool: diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index f0a859deba0..70ef3ea5773 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -4,6 +4,7 @@ from typing import Optional, Union import litellm from litellm.utils import ( + _default_reasoning_effort_factory, _is_explicitly_disabled_factory, _supports_factory, ) @@ -114,6 +115,10 @@ class OpenAIGPT5Config(OpenAIGPTConfig): except (ValueError, IndexError): return False + @classmethod + def _model_map_lookup_name(cls, model: str) -> str: + return model + @classmethod def _supports_reasoning_effort_level(cls, model: str, level: str) -> bool: """Check if the model supports a specific reasoning_effort level. @@ -123,11 +128,44 @@ class OpenAIGPT5Config(OpenAIGPTConfig): Returns False for unknown models (safe fallback). """ return _supports_factory( - model=model, + model=cls._model_map_lookup_name(model), custom_llm_provider=None, key=f"supports_{level}_reasoning_effort", ) + @classmethod + def _get_default_reasoning_effort(cls, model: str) -> "str | None": + return _default_reasoning_effort_factory( + model=cls._model_map_lookup_name(model), + custom_llm_provider=None, + ) + + @classmethod + def _effort_resolves_to_none(cls, model: str, effective_effort: "str | None", supports_none: bool) -> bool: + if effective_effort is not None: + return effective_effort == "none" + default_effort = cls._get_default_reasoning_effort(model) + if default_effort is not None: + return default_effort == "none" + return supports_none + + @classmethod + def _unsupported_temperature_message( + cls, model: str, temperature_value: float, effective_effort: "str | None" + ) -> str: + resolved_effort = effective_effort if effective_effort is not None else cls._get_default_reasoning_effort(model) + effort_clause = ( + f"reasoning_effort resolves to '{resolved_effort}'" + if resolved_effort is not None + else "reasoning is active" + ) + return ( + f"{model} doesn't support temperature={temperature_value} because {effort_clause}. " + "Only temperature=1 is supported unless reasoning_effort resolves to 'none' " + "(explicitly set, or as the model's default). " + "To drop unsupported params set `litellm.drop_params = True`" + ) + @classmethod def _is_reasoning_effort_level_explicitly_disabled(cls, model: str, level: str) -> bool: """Return True only when the model map explicitly sets the capability to False. @@ -260,7 +298,7 @@ class OpenAIGPT5Config(OpenAIGPTConfig): if supports_none: sampling_params = ["logprobs", "top_logprobs", "top_p"] has_sampling = any(p in non_default_params for p in sampling_params) - if has_sampling and effective_effort not in (None, "none"): + if has_sampling and not self._effort_resolves_to_none(model, effective_effort, supports_none): if litellm.drop_params or drop_params: for p in sampling_params: non_default_params.pop(p, None) @@ -268,17 +306,16 @@ class OpenAIGPT5Config(OpenAIGPTConfig): raise litellm.utils.UnsupportedParamsError( message=( "gpt-5.1/5.2/5.4 only support logprobs, top_p, top_logprobs when " - "reasoning_effort='none'. Current reasoning_effort='{}'. " + "reasoning_effort resolves to 'none'. Current reasoning_effort='{}'. " "To drop unsupported params set `litellm.drop_params = True`" - ).format(effective_effort), + ).format(effective_effort or self._get_default_reasoning_effort(model)), status_code=400, ) if "temperature" in non_default_params: temperature_value: Optional[float] = non_default_params.pop("temperature") if temperature_value is not None: - # models supporting reasoning_effort="none" also support flexible temperature - if supports_none and (effective_effort == "none" or effective_effort is None): + if supports_none and self._effort_resolves_to_none(model, effective_effort, supports_none): optional_params["temperature"] = temperature_value elif temperature_value == 1: optional_params["temperature"] = temperature_value @@ -286,12 +323,7 @@ class OpenAIGPT5Config(OpenAIGPTConfig): pass else: raise litellm.utils.UnsupportedParamsError( - message=( - "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), + message=self._unsupported_temperature_message(model, temperature_value, effective_effort), status_code=400, ) return super()._map_openai_params( diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index 3c2ae238a0b..e62bec2f4bc 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -113,22 +113,18 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): if self._is_gpt_5_model(model=model): temperature = params.get("temperature") if temperature is not None and temperature != 1: + from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config + reasoning = params.get("reasoning") or {} effort = reasoning.get("effort") if isinstance(reasoning, dict) else None supports_none = self._supports_reasoning_effort_none(model=model) - if supports_none and (effort == "none" or effort is None): + if supports_none and OpenAIGPT5Config._effort_resolves_to_none(model, effort, supports_none): pass # flexible temperature allowed elif drop_params or litellm.drop_params: params.pop("temperature", None) else: raise litellm.UnsupportedParamsError( - message=( - "gpt-5 models don't support temperature={}. " - "Only temperature=1 is supported. " - "For models like gpt-5.1/5.4, temperature is supported " - "when reasoning.effort='none' (or not specified). " - "To drop unsupported params set `litellm.drop_params = True`" - ).format(temperature), + message=OpenAIGPT5Config._unsupported_temperature_message(model, temperature, effort), status_code=400, ) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index d3917886060..ae88fa8a294 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -3575,6 +3575,7 @@ "supports_vision": true }, "azure/eu/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.4e-07, "input_cost_per_token": 1.38e-06, "litellm_provider": "azure", @@ -3877,6 +3878,7 @@ "supports_vision": true }, "azure/global/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "input_cost_per_token": 1.25e-06, "litellm_provider": "azure", @@ -4913,6 +4915,7 @@ "supports_audio_input": true }, "azure/gpt-5.1-2025-11-13": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "cache_read_input_token_cost_priority": 2.5e-07, "input_cost_per_token": 1.25e-06, @@ -5368,6 +5371,7 @@ "supports_vision": true }, "azure/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "input_cost_per_token": 1.25e-06, "litellm_provider": "azure", @@ -5526,6 +5530,7 @@ "supports_vision": true }, "azure/gpt-5.2": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "input_cost_per_token": 1.75e-06, "litellm_provider": "azure", @@ -5559,6 +5564,7 @@ "supports_vision": true }, "azure/gpt-5.2-2025-12-11": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "cache_read_input_token_cost_priority": 3.5e-07, "input_cost_per_token": 1.75e-06, @@ -5819,6 +5825,7 @@ "supports_web_search": true }, "azure/gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, @@ -5860,6 +5867,7 @@ "supports_vision": true }, "azure/us/gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -5895,6 +5903,7 @@ "supports_vision": true }, "azure/eu/gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -5930,6 +5939,7 @@ "supports_vision": true }, "azure/gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, @@ -5971,6 +5981,7 @@ "supports_vision": true }, "azure/us/gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -6006,6 +6017,7 @@ "supports_vision": true }, "azure/eu/gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -6627,6 +6639,7 @@ "supports_minimal_reasoning_effort": false }, "azure/gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_priority": 1e-06, @@ -6672,6 +6685,7 @@ "supports_minimal_reasoning_effort": false }, "azure/us/gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6714,6 +6728,7 @@ "supports_minimal_reasoning_effort": false }, "azure/eu/gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6756,6 +6771,7 @@ "supports_minimal_reasoning_effort": false }, "azure/gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_priority": 1e-06, @@ -6798,6 +6814,7 @@ "supports_web_search": true }, "azure/us/gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6837,6 +6854,7 @@ "supports_web_search": true }, "azure/eu/gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6876,6 +6894,7 @@ "supports_web_search": true }, "azure/gpt-5.5-pro": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -6915,6 +6934,7 @@ "supports_low_reasoning_effort": false }, "azure/gpt-5.5-pro-2026-04-23": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -8078,6 +8098,7 @@ "supports_vision": true }, "azure/us/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.4e-07, "input_cost_per_token": 1.38e-06, "litellm_provider": "azure", @@ -23023,6 +23044,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "cache_read_input_token_cost_priority": 2.5e-07, "input_cost_per_token": 1.25e-06, @@ -23062,6 +23084,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.1-2025-11-13": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "cache_read_input_token_cost_priority": 2.5e-07, "input_cost_per_token": 1.25e-06, @@ -23140,6 +23163,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.2": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "cache_read_input_token_cost_priority": 3.5e-07, "input_cost_per_token": 1.75e-06, @@ -23180,6 +23204,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.2-2025-12-11": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "cache_read_input_token_cost_priority": 3.5e-07, "input_cost_per_token": 1.75e-06, @@ -23576,6 +23601,7 @@ "supports_xhigh_reasoning_effort": true }, "gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_flex": 2.5e-07, @@ -23625,6 +23651,7 @@ "supports_minimal_reasoning_effort": false }, "gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_flex": 2.5e-07, @@ -23674,6 +23701,7 @@ "supports_minimal_reasoning_effort": false }, "gpt-5.5-pro": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -23719,6 +23747,7 @@ "supports_low_reasoning_effort": false }, "gpt-5.5-pro-2026-04-23": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -23764,6 +23793,7 @@ "supports_low_reasoning_effort": false }, "gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_flex": 1.3e-07, @@ -23812,6 +23842,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_flex": 1.3e-07, diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 714ad372a5f..d1806176f0f 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -161,6 +161,7 @@ class ProviderSpecificModelInfo(TypedDict, total=False): supports_low_reasoning_effort: Optional[bool] supports_xhigh_reasoning_effort: Optional[bool] supports_max_reasoning_effort: Optional[bool] + default_reasoning_effort: Optional[Literal["none", "minimal", "low", "medium", "high", "xhigh"]] supports_output_config: Optional[bool] supports_image_size: Optional[bool] bedrock_output_config_effort_ceiling: Optional[Literal["low", "medium", "high", "max", "xhigh"]] diff --git a/litellm/utils.py b/litellm/utils.py index a11c5500503..02f51257673 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -2420,6 +2420,29 @@ def _is_explicitly_disabled_factory(model: str, custom_llm_provider: Optional[st return False +def _default_reasoning_effort_factory(model: str, custom_llm_provider: str | None) -> str | None: + try: + resolved_model, resolved_provider, _, _ = litellm.get_llm_provider( + model=model, custom_llm_provider=custom_llm_provider + ) + model_info = _get_model_info_helper(model=resolved_model, custom_llm_provider=resolved_provider) + value = model_info.get("default_reasoning_effort") + if value is not None: + return value + bare_model_key = _get_model_cost_key(resolved_model) + if bare_model_key is None: + return None + bare_value = (litellm.model_cost.get(bare_model_key) or {}).get("default_reasoning_effort") + return bare_value if isinstance(bare_value, str) else None + except Exception as e: # noqa: BLE001 # _get_model_info_helper raises bare Exception for unmapped models + verbose_logger.debug( + f"Model not found or error in checking default_reasoning_effort. " + f"You passed model={model}, custom_llm_provider={custom_llm_provider}. " + f"Error: {str(e)}" + ) + return None + + def supports_audio_input(model: str, custom_llm_provider: Optional[str] = None) -> bool: """Check if a given model supports audio input in a chat completion call""" return _supports_factory(model=model, custom_llm_provider=custom_llm_provider, key="supports_audio_input") @@ -5520,6 +5543,7 @@ def _get_model_info_helper( supports_low_reasoning_effort=_model_info.get("supports_low_reasoning_effort", None), supports_xhigh_reasoning_effort=_model_info.get("supports_xhigh_reasoning_effort", None), supports_max_reasoning_effort=_model_info.get("supports_max_reasoning_effort", None), + default_reasoning_effort=_model_info.get("default_reasoning_effort", None), bedrock_output_config_effort_ceiling=_model_info.get("bedrock_output_config_effort_ceiling", None), bedrock_converse_supports_strict_tools=_model_info.get("bedrock_converse_supports_strict_tools", None), supports_computer_use=_model_info.get("supports_computer_use", None), diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index c9d871fc41d..b8050fd0bb1 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -3575,6 +3575,7 @@ "supports_vision": true }, "azure/eu/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.4e-07, "input_cost_per_token": 1.38e-06, "litellm_provider": "azure", @@ -3877,6 +3878,7 @@ "supports_vision": true }, "azure/global/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "input_cost_per_token": 1.25e-06, "litellm_provider": "azure", @@ -4913,6 +4915,7 @@ "supports_audio_input": true }, "azure/gpt-5.1-2025-11-13": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "cache_read_input_token_cost_priority": 2.5e-07, "input_cost_per_token": 1.25e-06, @@ -5368,6 +5371,7 @@ "supports_vision": true }, "azure/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "input_cost_per_token": 1.25e-06, "litellm_provider": "azure", @@ -5526,6 +5530,7 @@ "supports_vision": true }, "azure/gpt-5.2": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "input_cost_per_token": 1.75e-06, "litellm_provider": "azure", @@ -5559,6 +5564,7 @@ "supports_vision": true }, "azure/gpt-5.2-2025-12-11": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "cache_read_input_token_cost_priority": 3.5e-07, "input_cost_per_token": 1.75e-06, @@ -5819,6 +5825,7 @@ "supports_web_search": true }, "azure/gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, @@ -5860,6 +5867,7 @@ "supports_vision": true }, "azure/us/gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -5895,6 +5903,7 @@ "supports_vision": true }, "azure/eu/gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -5930,6 +5939,7 @@ "supports_vision": true }, "azure/gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, @@ -5971,6 +5981,7 @@ "supports_vision": true }, "azure/us/gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -6006,6 +6017,7 @@ "supports_vision": true }, "azure/eu/gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.8e-07, "cache_read_input_token_cost_priority": 5.5e-07, "input_cost_per_token": 2.75e-06, @@ -6627,6 +6639,7 @@ "supports_minimal_reasoning_effort": false }, "azure/gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_priority": 1e-06, @@ -6672,6 +6685,7 @@ "supports_minimal_reasoning_effort": false }, "azure/us/gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6714,6 +6728,7 @@ "supports_minimal_reasoning_effort": false }, "azure/eu/gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6756,6 +6771,7 @@ "supports_minimal_reasoning_effort": false }, "azure/gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_priority": 1e-06, @@ -6798,6 +6814,7 @@ "supports_web_search": true }, "azure/us/gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6837,6 +6854,7 @@ "supports_web_search": true }, "azure/eu/gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5.5e-07, "cache_read_input_token_cost_above_272k_tokens": 1.1e-06, "cache_read_input_token_cost_priority": 1.38e-06, @@ -6876,6 +6894,7 @@ "supports_web_search": true }, "azure/gpt-5.5-pro": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -6915,6 +6934,7 @@ "supports_low_reasoning_effort": false }, "azure/gpt-5.5-pro-2026-04-23": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -8078,6 +8098,7 @@ "supports_vision": true }, "azure/us/gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.4e-07, "input_cost_per_token": 1.38e-06, "litellm_provider": "azure", @@ -23098,6 +23119,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.1": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "cache_read_input_token_cost_priority": 2.5e-07, "input_cost_per_token": 1.25e-06, @@ -23137,6 +23159,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.1-2025-11-13": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.25e-07, "cache_read_input_token_cost_priority": 2.5e-07, "input_cost_per_token": 1.25e-06, @@ -23215,6 +23238,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.2": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "cache_read_input_token_cost_priority": 3.5e-07, "input_cost_per_token": 1.75e-06, @@ -23255,6 +23279,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.2-2025-12-11": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 1.75e-07, "cache_read_input_token_cost_priority": 3.5e-07, "input_cost_per_token": 1.75e-06, @@ -23651,6 +23676,7 @@ "supports_xhigh_reasoning_effort": true }, "gpt-5.5": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_flex": 2.5e-07, @@ -23700,6 +23726,7 @@ "supports_minimal_reasoning_effort": false }, "gpt-5.5-2026-04-23": { + "default_reasoning_effort": "medium", "cache_read_input_token_cost": 5e-07, "cache_read_input_token_cost_above_272k_tokens": 1e-06, "cache_read_input_token_cost_flex": 2.5e-07, @@ -23749,6 +23776,7 @@ "supports_minimal_reasoning_effort": false }, "gpt-5.5-pro": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -23794,6 +23822,7 @@ "supports_low_reasoning_effort": false }, "gpt-5.5-pro-2026-04-23": { + "default_reasoning_effort": "high", "cache_read_input_token_cost": 3e-06, "cache_read_input_token_cost_above_272k_tokens": 6e-06, "input_cost_per_token": 3e-05, @@ -23839,6 +23868,7 @@ "supports_low_reasoning_effort": false }, "gpt-5.4": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_flex": 1.3e-07, @@ -23887,6 +23917,7 @@ "supports_minimal_reasoning_effort": true }, "gpt-5.4-2026-03-05": { + "default_reasoning_effort": "none", "cache_read_input_token_cost": 2.5e-07, "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_flex": 1.3e-07, 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 83562331b9a..1d6ca4ca2bc 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 @@ -1,6 +1,7 @@ import pytest import litellm +from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map from litellm.llms.azure.chat.gpt_5_transformation import AzureOpenAIGPT5Config @@ -9,6 +10,13 @@ def config() -> AzureOpenAIGPT5Config: return AzureOpenAIGPT5Config() +@pytest.fixture(autouse=True) +def use_local_model_cost_map(monkeypatch: pytest.MonkeyPatch): + monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True") + monkeypatch.setattr(litellm, "model_cost", get_model_cost_map(url=litellm.model_cost_map_url)) + litellm.add_known_models(model_cost_map=litellm.model_cost) + + def test_azure_gpt5_supports_reasoning_effort(config: AzureOpenAIGPT5Config): assert "reasoning_effort" in config.get_supported_openai_params(model="gpt-5") assert "reasoning_effort" in config.get_supported_openai_params( @@ -299,3 +307,72 @@ def test_azure_gpt5_1_does_not_support_logprobs(config: AzureOpenAIGPT5Config): supported_params = config.get_supported_openai_params(model="gpt-5.1") assert "logprobs" not in supported_params assert "top_logprobs" not in supported_params + + +def test_azure_gpt5_5_temperature_dropped_without_reasoning_effort( + config: AzureOpenAIGPT5Config, +): + params = config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="azure/gpt-5.5", + drop_params=True, + api_version="2025-01-01-preview", + ) + assert "temperature" not in params + + +def test_azure_gpt5_5_temperature_error_without_reasoning_effort( + config: AzureOpenAIGPT5Config, +): + with pytest.raises( + litellm.utils.UnsupportedParamsError, + match="reasoning_effort resolves to 'medium'", + ): + config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="azure/gpt-5.5", + drop_params=False, + api_version="2025-01-01-preview", + ) + + +def test_azure_gpt5_5_series_temperature_dropped_without_reasoning_effort( + config: AzureOpenAIGPT5Config, +): + params = config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="gpt5_series/gpt-5.5", + drop_params=True, + api_version="2025-01-01-preview", + ) + assert "temperature" not in params + + +def test_azure_gpt5_5_bare_deployment_temperature_error_without_reasoning_effort( + config: AzureOpenAIGPT5Config, +): + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="gpt-5.5", + drop_params=False, + api_version="2025-01-01-preview", + ) + + +def test_azure_gpt5_5_temperature_with_explicit_reasoning_effort_none( + config: AzureOpenAIGPT5Config, +): + params = config.map_openai_params( + non_default_params={"temperature": 0.1, "reasoning_effort": "none"}, + optional_params={}, + model="azure/gpt-5.5", + drop_params=False, + api_version="2025-01-01-preview", + ) + assert params["temperature"] == 0.1 + assert params["reasoning_effort"] == "none" diff --git a/tests/test_litellm/llms/openai/test_gpt5_transformation.py b/tests/test_litellm/llms/openai/test_gpt5_transformation.py index d279b119efe..91ebbd88ecc 100644 --- a/tests/test_litellm/llms/openai/test_gpt5_transformation.py +++ b/tests/test_litellm/llms/openai/test_gpt5_transformation.py @@ -137,7 +137,7 @@ def test_gpt5_codex_temperature_error(config: OpenAIConfig): """Test that GPT-5-Codex raises error for unsupported temperature when drop_params=False.""" with pytest.raises( litellm.utils.UnsupportedParamsError, - match="gpt-5 models \\(including gpt-5-codex\\)", + match="gpt-5-codex doesn't support temperature=0.7", ): config.map_openai_params( non_default_params={"temperature": 0.7}, @@ -1309,3 +1309,120 @@ def test_responses_gpt54_allow_temperature_effort_none( drop_params=False, ) assert params["temperature"] == 0.7 + + +def test_gpt5_5_temperature_dropped_without_reasoning_effort(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="gpt-5.5", + drop_params=True, + ) + assert "temperature" not in params + + +def test_gpt5_5_temperature_error_without_reasoning_effort(config: OpenAIConfig): + with pytest.raises( + litellm.utils.UnsupportedParamsError, + match="reasoning_effort resolves to 'medium'", + ): + config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="gpt-5.5", + drop_params=False, + ) + + +def test_gpt5_5_dated_temperature_error_without_reasoning_effort(config: OpenAIConfig): + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.1}, + optional_params={}, + model="gpt-5.5-2026-04-23", + drop_params=False, + ) + + +def test_gpt5_5_temperature_with_explicit_reasoning_effort_none(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"temperature": 0.1, "reasoning_effort": "none"}, + optional_params={}, + model="gpt-5.5", + drop_params=False, + ) + assert params["temperature"] == 0.1 + assert params["reasoning_effort"] == "none" + + +def test_gpt5_5_temperature_one_without_reasoning_effort(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"temperature": 1.0}, + optional_params={}, + model="gpt-5.5", + drop_params=False, + ) + assert params["temperature"] == 1.0 + + +def test_gpt5_5_top_p_dropped_without_reasoning_effort(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"top_p": 0.5}, + optional_params={}, + model="gpt-5.5", + drop_params=True, + ) + assert "top_p" not in params + + +def test_gpt5_6_temperature_kept_when_default_effort_absent(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"temperature": 0.2}, + optional_params={}, + model="gpt-5.6", + drop_params=False, + ) + assert params["temperature"] == 0.2 + + +def test_responses_gpt5_5_temperature_dropped_without_reasoning( + responses_config: OpenAIResponsesAPIConfig, +): + params = responses_config.map_openai_params( + response_api_optional_params=ResponsesAPIOptionalRequestParams( + temperature=0.1, + ), + model="gpt-5.5", + drop_params=True, + ) + assert "temperature" not in params + + +def test_responses_gpt5_5_temperature_error_without_reasoning( + responses_config: OpenAIResponsesAPIConfig, +): + with pytest.raises( + litellm.UnsupportedParamsError, + match="reasoning_effort resolves to 'medium'", + ): + responses_config.map_openai_params( + response_api_optional_params=ResponsesAPIOptionalRequestParams( + temperature=0.1, + ), + model="gpt-5.5", + drop_params=False, + ) + + +def test_responses_gpt5_5_temperature_allowed_with_effort_none( + responses_config: OpenAIResponsesAPIConfig, +): + params = responses_config.map_openai_params( + response_api_optional_params=ResponsesAPIOptionalRequestParams( + temperature=0.1, + reasoning={"effort": "none"}, + ), + model="gpt-5.5", + drop_params=False, + ) + assert params["temperature"] == 0.1 diff --git a/tests/test_litellm/test_utils.py b/tests/test_litellm/test_utils.py index a1a9448cc58..2515749fb54 100644 --- a/tests/test_litellm/test_utils.py +++ b/tests/test_litellm/test_utils.py @@ -861,6 +861,10 @@ def test_aaamodel_prices_and_context_window_json_is_valid(): "supports_none_reasoning_effort": {"type": "boolean"}, "supports_xhigh_reasoning_effort": {"type": "boolean"}, "supports_max_reasoning_effort": {"type": "boolean"}, + "default_reasoning_effort": { + "type": "string", + "enum": ["none", "minimal", "low", "medium", "high", "xhigh"], + }, "supports_adaptive_thinking": {"type": "boolean"}, "supports_mid_conversation_system": {"type": "boolean"}, "supports_sampling_params": {"type": "boolean"},