Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions litellm/llms/openai/chat/gpt_5_transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@


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

Expand All @@ -38,7 +44,9 @@ def get_supported_openai_params(self, model: str) -> list:
]

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(
Expand Down Expand Up @@ -67,7 +75,7 @@ def map_openai_params(
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,
)
Expand Down
75 changes: 75 additions & 0 deletions litellm/model_prices_and_context_window_backup.json
Original file line number Diff line number Diff line change
Expand Up @@ -12312,6 +12312,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,
Expand Down
28 changes: 28 additions & 0 deletions model_prices_and_context_window.json
Original file line number Diff line number Diff line change
Expand Up @@ -12312,6 +12312,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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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"

101 changes: 101 additions & 0 deletions tests/test_litellm/llms/openai/test_gpt5_transformation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

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},
Expand Down Expand Up @@ -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
Loading