From b248b1c7dc12c194c4e1e176b9432391ef5ae5ab Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 26 Sep 2026 16:09:09 -0700 Subject: [PATCH] fix(openai): exclude fine-tuned and custom gpt-5-chat aliases from gpt-5 reasoning path (#43185) * fix(openai): exclude fine-tuned and custom gpt-5-chat aliases from gpt-5 reasoning path Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(openai): keep gpt-5-chat alias regression test diff minimal Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(openai): cover temperature pass-through for gpt-5-chat aliases Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(openai): annotate locals and wrap long lines in gpt-5-chat alias test Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: mateo Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../llms/openai/chat/gpt_5_transformation.py | 2 +- .../llms/openai/test_is_model_gpt_5_model.py | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index d0e5ff01e71..bf6b52225f2 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -69,7 +69,7 @@ GPT_REASONING_SERIES_MARKERS: Final = ("gpt-5", "gpt-6") def is_gpt_reasoning_series_name(model: str) -> bool: normalized: Final = model.split("/")[-1] - return any(marker in model for marker in GPT_REASONING_SERIES_MARKERS) and not normalized.startswith("gpt-5-chat") + return any(marker in model for marker in GPT_REASONING_SERIES_MARKERS) and "gpt-5-chat" not in normalized class OpenAIGPT5Config(OpenAIGPTConfig): diff --git a/tests/unit/llms/openai/test_is_model_gpt_5_model.py b/tests/unit/llms/openai/test_is_model_gpt_5_model.py index 0bb8425d95e..f6fef92fc6a 100644 --- a/tests/unit/llms/openai/test_is_model_gpt_5_model.py +++ b/tests/unit/llms/openai/test_is_model_gpt_5_model.py @@ -26,14 +26,18 @@ There are two distinct families: ``gpt-5.3-chat``, …) — ARE GPT-5 reasoning models and must stay on the GPT-5 path. -The fix uses a prefix check (``startswith("gpt-5-chat")``) on the normalised model -name instead of a substring check, which correctly distinguishes the two families. +The fix uses a substring check for ``gpt-5-chat`` on the normalised model +name (not a prefix check), which correctly distinguishes the two families. """ +from typing import Final + import pytest -from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config +import litellm from litellm.llms.azure.chat.gpt_5_transformation import AzureOpenAIGPT5Config +from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config +from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig # --------------------------------------------------------------------------- # Parametrized fixtures @@ -73,6 +77,9 @@ NON_GPT5_MODELS = [ "gpt-5-chat", # gpt-5-chat family — regular chat path "gpt-5-chat-latest", # gpt-5-chat family with alias suffix "gpt-5-chat-2025-08-07", # gpt-5-chat family with date suffix + "ft:gpt-5-chat-latest:org:abc", + "my-custom-gpt-5-chat", + "openai/ft:gpt-5-chat-latest:org:abc", "gpt-4", "gpt-4o", "gpt-4-turbo", @@ -117,6 +124,27 @@ class TestOpenAIGPT5ConfigIsModelGpt5Model: model ), f"Expected '{model}' (gpt-5-chat family) NOT to be on the GPT-5 path" + def test_responses_api_gpt5_chat_aliases_are_not_gpt5(self): + for model in ["ft:gpt-5-chat-latest:org:abc", "openai/my-custom-gpt-5-chat"]: + assert not OpenAIResponsesAPIConfig._is_gpt_5_model( + model + ), f"Expected Responses API '{model}' NOT to be on the GPT-5 path" + + @pytest.mark.parametrize("model", ["ft:gpt-5-chat-latest:org:abc", "my-custom-gpt-5-chat"]) + def test_gpt5_chat_aliases_keep_non_default_temperature(self, model: str): + chat_params: Final = litellm.get_optional_params( + model=model, custom_llm_provider="openai", temperature=0.7 + ) + responses_params: Final = OpenAIResponsesAPIConfig().map_openai_params( + response_api_optional_params={"temperature": 0.7}, model=model, drop_params=False + ) + assert chat_params["temperature"] == 0.7, ( + f"chat completions dropped or rejected temperature for '{model}'" + ) + assert responses_params["temperature"] == 0.7, ( + f"responses dropped or rejected temperature for '{model}'" + ) + # Models that are gpt-5.4 or newer. main.py gates the automatic switch to the # /v1/responses bridge (when reasoning_effort is set and tools are passed) on