fix(openai): exclude fine-tuned and custom gpt-5-chat aliases from gpt-5 reasoning path (#43185)
Some checks are pending
LiteLLM Rust / rust-lint (push) Waiting to run
LiteLLM Rust / rust-test (push) Waiting to run
LiteLLM Rust / rust-wheel (push) Waiting to run

* 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 <mateo@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
devin-ai-integration[bot] 2026-09-26 16:09:09 -07:00 • committed by GitHub
parent e494723105
commit b248b1c7dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 4 deletions

View file

@ -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):

View file

@ -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