Add support for GPT 5 codex models (#14841)

* Add support for GPT 5 codex models

* lint

* fixes
This commit is contained in:
Uzair Ali
2025-09-30 18:44:35 -07:00
committed by GitHub
parent 26145da3e7
commit fcfe856e10
5 changed files with 271 additions and 4 deletions
@@ -8,18 +8,24 @@ from .gpt_transformation import OpenAIGPTConfig
class OpenAIGPT5Config(OpenAIGPTConfig):
"""Configuration for gpt-5 models.
"""Configuration for gpt-5 models including GPT-5-Codex variants.
Handles OpenAI API quirks for the gpt-5 series like:
- Mapping ``max_tokens`` -> ``max_completion_tokens``.
- Dropping unsupported ``temperature`` values when requested.
- Support for GPT-5-Codex models optimized for code generation.
"""
@classmethod
def is_model_gpt_5_model(cls, model: str) -> bool:
return "gpt-5" in model
@classmethod
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
def get_supported_openai_params(self, model: str) -> list:
from litellm.utils import supports_tool_choice
@@ -38,7 +44,9 @@ class OpenAIGPT5Config(OpenAIGPTConfig):
]
return [
param for param in base_gpt_series_params if param not in non_supported_params
param
for param in base_gpt_series_params
if param not in non_supported_params
]
def map_openai_params(
@@ -67,7 +75,7 @@ class OpenAIGPT5Config(OpenAIGPTConfig):
else:
raise litellm.utils.UnsupportedParamsError(
message=(
"gpt-5 models 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. To drop unsupported params set `litellm.drop_params = True`"
).format(temperature_value),
status_code=400,
)
@@ -12727,6 +12727,81 @@
"supports_tool_choice": true,
"supports_vision": true
},
"gpt-5-codex": {
"cache_read_input_token_cost": 1.25e-07,
"cache_read_input_token_cost_flex": 6.25e-08,
"cache_read_input_token_cost_priority": 2.5e-07,
"input_cost_per_token": 1.25e-06,
"input_cost_per_token_flex": 6.25e-07,
"input_cost_per_token_priority": 2.5e-06,
"litellm_provider": "openai",
"max_input_tokens": 400000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"metadata": {
"notes": "GPT-5-Codex pricing placeholder - needs to be updated with actual OpenAI pricing"
},
"mode": "chat",
"output_cost_per_token": 1e-05,
"output_cost_per_token_flex": 5e-06,
"output_cost_per_token_priority": 2e-05,
"supported_endpoints": [
"/v1/responses"
],
"supported_modalities": [
"text",
"image"
],
"supported_output_modalities": [
"text"
],
"supports_function_calling": true,
"supports_native_streaming": true,
"supports_parallel_function_calling": true,
"supports_prompt_caching": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_system_messages": true,
"supports_tool_choice": true
},
"gpt-5-codex-latest": {
"cache_read_input_token_cost": 1.25e-07,
"cache_read_input_token_cost_flex": 6.25e-08,
"cache_read_input_token_cost_priority": 2.5e-07,
"input_cost_per_token": 1.25e-06,
"input_cost_per_token_flex": 6.25e-07,
"input_cost_per_token_priority": 2.5e-06,
"litellm_provider": "openai",
"max_input_tokens": 400000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"metadata": {
"notes": "GPT-5-Codex-Latest pricing placeholder - needs to be updated with actual OpenAI pricing"
},
"mode": "chat",
"output_cost_per_token": 1e-05,
"output_cost_per_token_flex": 5e-06,
"output_cost_per_token_priority": 2e-05,
"supported_endpoints": [
"/v1/chat/completions",
"/v1/batch",
"/v1/responses"
],
"supported_modalities": [
"text"
],
"supported_output_modalities": [
"text"
],
"supports_function_calling": true,
"supports_native_streaming": true,
"supports_parallel_function_calling": true,
"supports_prompt_caching": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_system_messages": true,
"supports_tool_choice": true
},
"gpt-5-2025-08-07": {
"cache_read_input_token_cost": 1.25e-07,
"cache_read_input_token_cost_flex": 6.25e-08,
+28
View File
@@ -12727,6 +12727,34 @@
"supports_tool_choice": true,
"supports_vision": true
},
"gpt-5-codex": {
"cache_read_input_token_cost": 1.25e-07,
"input_cost_per_token": 1.25e-06,
"litellm_provider": "openai",
"max_input_tokens": 400000,
"max_output_tokens": 128000,
"max_tokens": 128000,
"mode": "chat",
"output_cost_per_token": 1e-05,
"supported_endpoints": [
"/v1/responses"
],
"supported_modalities": [
"text",
"image"
],
"supported_output_modalities": [
"text"
],
"supports_function_calling": true,
"supports_native_streaming": true,
"supports_parallel_function_calling": true,
"supports_prompt_caching": true,
"supports_reasoning": true,
"supports_response_schema": true,
"supports_system_messages": true,
"supports_tool_choice": true
},
"gpt-5-2025-08-07": {
"cache_read_input_token_cost": 1.25e-07,
"cache_read_input_token_cost_flex": 6.25e-08,
@@ -11,7 +11,9 @@ def config() -> AzureOpenAIGPT5Config:
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(model="gpt5_series/my-deployment")
assert "reasoning_effort" in config.get_supported_openai_params(
model="gpt5_series/my-deployment"
)
def test_azure_gpt5_maps_max_tokens(config: AzureOpenAIGPT5Config):
@@ -46,3 +48,56 @@ def test_azure_gpt5_series_transform_request(config: AzureOpenAIGPT5Config):
headers={},
)
assert request["model"] == "gpt-5"
# GPT-5-Codex specific tests for Azure
def test_azure_gpt5_codex_model_detection(config: AzureOpenAIGPT5Config):
"""Test that Azure GPT-5-Codex models are correctly detected."""
assert config.is_model_gpt_5_model("gpt-5-codex")
assert config.is_model_gpt_5_model("gpt5_series/gpt-5-codex")
def test_azure_gpt5_codex_supports_reasoning_effort(config: AzureOpenAIGPT5Config):
"""Test that Azure GPT-5-Codex supports reasoning_effort parameter."""
assert "reasoning_effort" in config.get_supported_openai_params(model="gpt-5-codex")
assert "reasoning_effort" in config.get_supported_openai_params(
model="gpt5_series/gpt-5-codex"
)
def test_azure_gpt5_codex_maps_max_tokens(config: AzureOpenAIGPT5Config):
"""Test that Azure GPT-5-Codex correctly maps max_tokens to max_completion_tokens."""
params = config.map_openai_params(
non_default_params={"max_tokens": 150},
optional_params={},
model="gpt-5-codex",
drop_params=False,
api_version="2024-05-01-preview",
)
assert params["max_completion_tokens"] == 150
assert "max_tokens" not in params
def test_azure_gpt5_codex_temperature_error(config: AzureOpenAIGPT5Config):
"""Test that Azure GPT-5-Codex raises error for unsupported temperature."""
with pytest.raises(litellm.utils.UnsupportedParamsError):
config.map_openai_params(
non_default_params={"temperature": 0.8},
optional_params={},
model="gpt-5-codex",
drop_params=False,
api_version="2024-05-01-preview",
)
def test_azure_gpt5_codex_series_transform_request(config: AzureOpenAIGPT5Config):
"""Test that Azure GPT-5-Codex series routing works correctly."""
request = config.transform_request(
model="gpt5_series/gpt-5-codex",
messages=[],
optional_params={},
litellm_params={},
headers={},
)
assert request["model"] == "gpt-5-codex"
@@ -2,16 +2,24 @@ import pytest
import litellm
from litellm.llms.openai.openai import OpenAIConfig
from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config
@pytest.fixture()
def config() -> OpenAIConfig:
return OpenAIConfig()
@pytest.fixture()
def gpt5_config() -> OpenAIGPT5Config:
return OpenAIGPT5Config()
def test_gpt5_supports_reasoning_effort(config: OpenAIConfig):
assert "reasoning_effort" in config.get_supported_openai_params(model="gpt-5")
assert "reasoning_effort" in config.get_supported_openai_params(model="gpt-5-mini")
def test_gpt5_maps_max_tokens(config: OpenAIConfig):
params = config.map_openai_params(
non_default_params={"max_tokens": 10},
@@ -52,3 +60,96 @@ def test_gpt5_unsupported_params_drop(config: OpenAIConfig):
drop_params=True,
)
assert "top_p" not in params
# GPT-5-Codex specific tests
def test_gpt5_codex_model_detection(gpt5_config: OpenAIGPT5Config):
"""Test that GPT-5-Codex models are correctly detected as GPT-5 models."""
assert gpt5_config.is_model_gpt_5_model("gpt-5-codex")
assert gpt5_config.is_model_gpt_5_codex_model("gpt-5-codex")
# Regular GPT-5 models should not be detected as codex
assert not gpt5_config.is_model_gpt_5_codex_model("gpt-5")
assert not gpt5_config.is_model_gpt_5_codex_model("gpt-5-mini")
def test_gpt5_codex_supports_reasoning_effort(config: OpenAIConfig):
"""Test that GPT-5-Codex supports reasoning_effort parameter."""
assert "reasoning_effort" in config.get_supported_openai_params(model="gpt-5-codex")
def test_gpt5_codex_maps_max_tokens(config: OpenAIConfig):
"""Test that GPT-5-Codex correctly maps max_tokens to max_completion_tokens."""
params = config.map_openai_params(
non_default_params={"max_tokens": 100},
optional_params={},
model="gpt-5-codex",
drop_params=False,
)
assert params["max_completion_tokens"] == 100
assert "max_tokens" not in params
def test_gpt5_codex_temperature_drop(config: OpenAIConfig):
"""Test that GPT-5-Codex drops unsupported temperature values when drop_params=True."""
params = config.map_openai_params(
non_default_params={"temperature": 0.7},
optional_params={},
model="gpt-5-codex",
drop_params=True,
)
assert "temperature" not in params
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\\)",
):
config.map_openai_params(
non_default_params={"temperature": 0.7},
optional_params={},
model="gpt-5-codex",
drop_params=False,
)
def test_gpt5_codex_temperature_one_allowed(config: OpenAIConfig):
"""Test that GPT-5-Codex allows temperature=1."""
params = config.map_openai_params(
non_default_params={"temperature": 1.0},
optional_params={},
model="gpt-5-codex",
drop_params=False,
)
assert params["temperature"] == 1.0
def test_gpt5_codex_unsupported_params_drop(config: OpenAIConfig):
"""Test that GPT-5-Codex drops unsupported parameters."""
unsupported_params = [
"top_p",
"presence_penalty",
"frequency_penalty",
"logprobs",
"top_logprobs",
]
for param in unsupported_params:
assert param not in config.get_supported_openai_params(model="gpt-5-codex")
def test_gpt5_codex_supports_tool_choice(gpt5_config: OpenAIGPT5Config):
"""Test that GPT-5-Codex supports tool_choice parameter."""
supported_params = gpt5_config.get_supported_openai_params(model="gpt-5-codex")
assert "tool_choice" in supported_params
def test_gpt5_codex_supports_function_calling(config: OpenAIConfig):
"""Test that GPT-5-Codex supports function calling parameters."""
supported_params = config.get_supported_openai_params(model="gpt-5-codex")
assert "functions" in supported_params
assert "function_call" in supported_params
assert "tools" in supported_params