From 10bd3ff5d60671c9bff5c208edd5570331cf369a Mon Sep 17 00:00:00 2001 From: Chesars Date: Wed, 15 Apr 2026 23:29:34 -0300 Subject: [PATCH] Fix three bugs introduced by staging PRs - factory.py: fix _sort_bedrock_assistant_content_blocks to treat cachePoint blocks with the same sort key as toolUse so Python's stable sort keeps each cachePoint paired with its preceding toolUse block (PR #24368) - responses/transformation.py: remove cyclic import of OpenAIGPT5Config inside map_openai_params; add _is_gpt_5_model and _supports_reasoning_effort_none static methods that replicate the same logic without the import cycle. _is_gpt_5_model now also excludes pass-through models from other providers (e.g. perplexity/openai/gpt-5.2) that contain 'gpt-5' in their name but should not be subject to OpenAI GPT-5 temperature restrictions (PR #24371) --- .../prompt_templates/factory.py | 4 +++ .../llms/openai/responses/transformation.py | 31 +++++++++++++++---- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index 18a4726e3bd..4146689cc09 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -4076,6 +4076,10 @@ def _sort_bedrock_assistant_content_blocks( return 0 if "toolUse" in block: return 2 + if "cachePoint" in block: + # cachePoint blocks are paired with their preceding toolUse block. + # Same key as toolUse so Python's stable sort keeps them together. + return 2 return 1 return sorted(blocks, key=_sort_key) diff --git a/litellm/llms/openai/responses/transformation.py b/litellm/llms/openai/responses/transformation.py index 03e09b039d1..83e1d6c386c 100644 --- a/litellm/llms/openai/responses/transformation.py +++ b/litellm/llms/openai/responses/transformation.py @@ -35,6 +35,29 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): def supports_native_file_search(self) -> bool: return True + @staticmethod + def _is_gpt_5_model(model: str) -> bool: + """Return True only for actual OpenAI GPT-5 models. + + Excludes pass-through models from other providers that happen to + reference gpt-5 in their name (e.g. perplexity/openai/gpt-5.2). + """ + parts = model.split("/") + if len(parts) > 1 and parts[0] not in ("openai",): + return False + return "gpt-5" in model and "gpt-5-chat" not in model + + @staticmethod + def _supports_reasoning_effort_none(model: str) -> bool: + """Return True if the model supports reasoning.effort='none'.""" + from litellm.utils import _supports_factory + + return _supports_factory( + model=model, + custom_llm_provider=None, + key="supports_none_reasoning_effort", + ) + def get_supported_openai_params(self, model: str) -> list: """ All OpenAI Responses API params are supported @@ -66,18 +89,14 @@ class OpenAIResponsesAPIConfig(BaseResponsesAPIConfig): is accepted unless reasoning_effort='none' on models that support it). Apply the same validation used by the chat completions path. """ - from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config - params = dict(response_api_optional_params) - if OpenAIGPT5Config.is_model_gpt_5_model(model=model): + if self._is_gpt_5_model(model=model): temperature = params.get("temperature") if temperature is not None and temperature != 1: reasoning = params.get("reasoning") or {} effort = reasoning.get("effort") if isinstance(reasoning, dict) else None - supports_none = OpenAIGPT5Config._supports_reasoning_effort_level( - model=model, level="none" - ) + supports_none = self._supports_reasoning_effort_none(model=model) if supports_none and (effort == "none" or effort is None): pass # flexible temperature allowed elif drop_params or litellm.drop_params: