diff --git a/docs/my-website/docs/providers/chatgpt.md b/docs/my-website/docs/providers/chatgpt.md index 156bbf99df6..222881953dc 100644 --- a/docs/my-website/docs/providers/chatgpt.md +++ b/docs/my-website/docs/providers/chatgpt.md @@ -4,12 +4,12 @@ Use ChatGPT Pro/Max subscription models through LiteLLM with OAuth device flow a | Property | Details | |-------|-------| -| Description | ChatGPT subscription access (Codex + GPT-5.2 family) via ChatGPT backend API | +| Description | ChatGPT subscription access (Codex + GPT-5.3/5.4 family) via ChatGPT backend API | | Provider Route on LiteLLM | `chatgpt/` | | Supported Endpoints | `/responses`, `/chat/completions` (bridged to Responses for supported models) | | API Reference | https://chatgpt.com | -ChatGPT subscription access is native to the Responses API. Chat Completions requests are bridged to Responses for supported models (for example `chatgpt/gpt-5.2`). +ChatGPT subscription access is native to the Responses API. Chat Completions requests are bridged to Responses for supported models (for example `chatgpt/gpt-5.4`). Notes: - The ChatGPT subscription backend rejects token limit fields (`max_tokens`, `max_output_tokens`, `max_completion_tokens`) and `metadata`. LiteLLM strips these fields for this provider. @@ -31,7 +31,7 @@ ChatGPT subscription access uses an OAuth device code flow: import litellm response = litellm.responses( - model="chatgpt/gpt-5.2-codex", + model="chatgpt/gpt-5.3-codex", input="Write a Python hello world" ) @@ -44,7 +44,7 @@ print(response) import litellm response = litellm.completion( - model="chatgpt/gpt-5.2", + model="chatgpt/gpt-5.4", messages=[{"role": "user", "content": "Write a Python hello world"}] ) @@ -55,16 +55,36 @@ print(response) ```yaml showLineNumbers title="config.yaml" model_list: - - model_name: chatgpt/gpt-5.2 + - model_name: chatgpt/gpt-5.4 model_info: mode: responses litellm_params: - model: chatgpt/gpt-5.2 - - model_name: chatgpt/gpt-5.2-codex + model: chatgpt/gpt-5.4 + - model_name: chatgpt/gpt-5.4-pro model_info: mode: responses litellm_params: - model: chatgpt/gpt-5.2-codex + model: chatgpt/gpt-5.4-pro + - model_name: chatgpt/gpt-5.3-codex + model_info: + mode: responses + litellm_params: + model: chatgpt/gpt-5.3-codex + - model_name: chatgpt/gpt-5.3-codex-spark + model_info: + mode: responses + litellm_params: + model: chatgpt/gpt-5.3-codex-spark + - model_name: chatgpt/gpt-5.3-instant + model_info: + mode: responses + litellm_params: + model: chatgpt/gpt-5.3-instant + - model_name: chatgpt/gpt-5.3-chat-latest + model_info: + mode: responses + litellm_params: + model: chatgpt/gpt-5.3-chat-latest ``` ```bash showLineNumbers title="Start LiteLLM Proxy" diff --git a/docs/my-website/docs/providers/openai.md b/docs/my-website/docs/providers/openai.md index 782c7072e50..6817c32e9b4 100644 --- a/docs/my-website/docs/providers/openai.md +++ b/docs/my-website/docs/providers/openai.md @@ -192,8 +192,12 @@ os.environ["OPENAI_BASE_URL"] = "https://your_host/v1" # OPTIONAL | gpt-5.2-2025-12-11 | `response = completion(model="gpt-5.2-2025-12-11", messages=messages)` | | gpt-5.2-chat-latest | `response = completion(model="gpt-5.2-chat-latest", messages=messages)` | | gpt-5.3-chat-latest | `response = completion(model="gpt-5.3-chat-latest", messages=messages)` | +| gpt-5.4 | `response = completion(model="gpt-5.4", messages=messages)` | +| gpt-5.4-2026-03-05 | `response = completion(model="gpt-5.4-2026-03-05", messages=messages)` | | gpt-5.2-pro | `response = completion(model="gpt-5.2-pro", messages=messages)` | | gpt-5.2-pro-2025-12-11 | `response = completion(model="gpt-5.2-pro-2025-12-11", messages=messages)` | +| gpt-5.4-pro | `response = completion(model="gpt-5.4-pro", messages=messages)` | +| gpt-5.4-pro-2026-03-05 | `response = completion(model="gpt-5.4-pro-2026-03-05", messages=messages)` | | gpt-5.1 | `response = completion(model="gpt-5.1", messages=messages)` | | gpt-5.1-codex | `response = completion(model="gpt-5.1-codex", messages=messages)` | | gpt-5.1-codex-mini | `response = completion(model="gpt-5.1-codex-mini", messages=messages)` | diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 81e99f3712d..e4fe94da78a 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -18437,6 +18437,93 @@ "max_tokens": 8191, "mode": "embedding" }, + "chatgpt/gpt-5.4": { + "litellm_provider": "chatgpt", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.4-pro": { + "litellm_provider": "chatgpt", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-codex": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-codex-spark": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-instant": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "responses", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-chat-latest": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "responses", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, "chatgpt/gpt-5.2-codex": { "litellm_provider": "chatgpt", "max_input_tokens": 128000, @@ -20891,6 +20978,68 @@ "supports_service_tier": true, "supports_vision": true }, + "gpt-5.4-pro": { + "cache_read_input_token_cost": 2e-06, + "input_cost_per_token": 2e-05, + "litellm_provider": "openai", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "output_cost_per_token": 0.00012, + "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_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, + "gpt-5.4-pro-2026-03-05": { + "cache_read_input_token_cost": 2e-06, + "input_cost_per_token": 2e-05, + "litellm_provider": "openai", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "output_cost_per_token": 0.00012, + "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_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, "gpt-5-pro": { "input_cost_per_token": 1.5e-05, "input_cost_per_token_batches": 7.5e-06, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 81e99f3712d..e4fe94da78a 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -18437,6 +18437,93 @@ "max_tokens": 8191, "mode": "embedding" }, + "chatgpt/gpt-5.4": { + "litellm_provider": "chatgpt", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.4-pro": { + "litellm_provider": "chatgpt", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-codex": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-codex-spark": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "supported_endpoints": [ + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-instant": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "responses", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, + "chatgpt/gpt-5.3-chat-latest": { + "litellm_provider": "chatgpt", + "max_input_tokens": 128000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "responses", + "supported_endpoints": [ + "/v1/chat/completions", + "/v1/responses" + ], + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_response_schema": true, + "supports_vision": true + }, "chatgpt/gpt-5.2-codex": { "litellm_provider": "chatgpt", "max_input_tokens": 128000, @@ -20891,6 +20978,68 @@ "supports_service_tier": true, "supports_vision": true }, + "gpt-5.4-pro": { + "cache_read_input_token_cost": 2e-06, + "input_cost_per_token": 2e-05, + "litellm_provider": "openai", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "output_cost_per_token": 0.00012, + "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_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, + "gpt-5.4-pro-2026-03-05": { + "cache_read_input_token_cost": 2e-06, + "input_cost_per_token": 2e-05, + "litellm_provider": "openai", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "responses", + "output_cost_per_token": 0.00012, + "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_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true + }, "gpt-5-pro": { "input_cost_per_token": 1.5e-05, "input_cost_per_token_batches": 7.5e-06, diff --git a/tests/test_litellm/llms/chatgpt/responses/test_chatgpt_responses_transformation.py b/tests/test_litellm/llms/chatgpt/responses/test_chatgpt_responses_transformation.py index 03cea8785bc..c0a0927b7d1 100644 --- a/tests/test_litellm/llms/chatgpt/responses/test_chatgpt_responses_transformation.py +++ b/tests/test_litellm/llms/chatgpt/responses/test_chatgpt_responses_transformation.py @@ -9,6 +9,7 @@ from unittest.mock import MagicMock, patch import httpx +import pytest sys.path.insert(0, os.path.abspath("../../../../..")) @@ -19,9 +20,20 @@ class TestChatGPTResponsesAPITransformation: - def test_chatgpt_provider_config_registration(self): + @pytest.mark.parametrize( + "model_name", + [ + "chatgpt/gpt-5.4", + "chatgpt/gpt-5.4-pro", + "chatgpt/gpt-5.3-chat-latest", + "chatgpt/gpt-5.3-instant", + "chatgpt/gpt-5.3-codex", + "chatgpt/gpt-5.3-codex-spark", + ], + ) + def test_chatgpt_provider_config_registration(self, model_name): config = ProviderConfigManager.get_provider_responses_api_config( - model="chatgpt/gpt-5.2", + model=model_name, provider=LlmProviders.CHATGPT, ) @@ -72,10 +84,17 @@ def test_validate_environment_headers(self, mock_authenticator_class): assert headers["accept"] == "text/event-stream" assert headers["session_id"] == "session-123" - def test_chatgpt_forces_streaming_and_reasoning_include(self): + @pytest.mark.parametrize( + "model_name", + [ + "chatgpt/gpt-5.2-codex", + "chatgpt/gpt-5.3-codex", + ], + ) + def test_chatgpt_forces_streaming_and_reasoning_include(self, model_name): config = ChatGPTResponsesAPIConfig() request = config.transform_responses_api_request( - model="chatgpt/gpt-5.2-codex", + model=model_name, input="hi", response_api_optional_request_params={}, litellm_params=GenericLiteLLMParams(), @@ -88,10 +107,17 @@ def test_chatgpt_forces_streaming_and_reasoning_include(self): "You are Codex, based on GPT-5." ) - def test_chatgpt_drops_unsupported_responses_params(self): + @pytest.mark.parametrize( + "model_name", + [ + "chatgpt/gpt-5.2-codex", + "chatgpt/gpt-5.3-codex-spark", + ], + ) + def test_chatgpt_drops_unsupported_responses_params(self, model_name): config = ChatGPTResponsesAPIConfig() request = config.transform_responses_api_request( - model="chatgpt/gpt-5.2-codex", + model=model_name, input="hi", response_api_optional_request_params={ # unsupported by ChatGPT Codex @@ -127,14 +153,23 @@ def test_chatgpt_drops_unsupported_responses_params(self): assert request["tools"] == [{"type": "function", "function": {"name": "hello"}}] assert request["tool_choice"] == {"type": "function", "function": {"name": "hello"}} - def test_chatgpt_non_stream_sse_response_parsing(self): + @pytest.mark.parametrize( + ("model_name", "response_model"), + [ + ("chatgpt/gpt-5.2-codex", "gpt-5.2-codex"), + ("chatgpt/gpt-5.3-codex", "gpt-5.3-codex"), + ], + ) + def test_chatgpt_non_stream_sse_response_parsing( + self, model_name: str, response_model: str + ): config = ChatGPTResponsesAPIConfig() response_payload = { "id": "resp_test", "object": "response", "created_at": 1700000000, "status": "completed", - "model": "gpt-5.2-codex", + "model": response_model, "output": [ { "type": "message", @@ -156,7 +191,7 @@ def test_chatgpt_non_stream_sse_response_parsing(self): logging_obj = MagicMock() parsed = config.transform_response_api_response( - model="chatgpt/gpt-5.2-codex", + model=model_name, raw_response=raw_response, logging_obj=logging_obj, ) diff --git a/tests/test_litellm/llms/openai/test_gpt5_transformation.py b/tests/test_litellm/llms/openai/test_gpt5_transformation.py index 026aba9ba4d..70ed96c91a2 100644 --- a/tests/test_litellm/llms/openai/test_gpt5_transformation.py +++ b/tests/test_litellm/llms/openai/test_gpt5_transformation.py @@ -267,9 +267,12 @@ def test_gpt5_1_model_detection(gpt5_config: OpenAIGPT5Config): assert gpt5_config.is_model_gpt_5_1_model("gpt-5.1-chat") assert gpt5_config.is_model_gpt_5_1_model("gpt-5.2") assert gpt5_config.is_model_gpt_5_1_model("gpt-5.2-2025-12-11") + assert gpt5_config.is_model_gpt_5_1_model("gpt-5.4") + assert gpt5_config.is_model_gpt_5_1_model("gpt-5.4-2026-03-05") assert not gpt5_config.is_model_gpt_5_1_model("gpt-5.2-chat") assert not gpt5_config.is_model_gpt_5_1_model("gpt-5.2-chat-latest") assert not gpt5_config.is_model_gpt_5_1_model("gpt-5.3-chat-latest") + assert not gpt5_config.is_model_gpt_5_1_model("gpt-5.4-pro") assert not gpt5_config.is_model_gpt_5_1_model("gpt-5.2-pro") assert not gpt5_config.is_model_gpt_5_1_model("gpt-5") assert not gpt5_config.is_model_gpt_5_1_model("gpt-5-mini") @@ -303,6 +306,36 @@ def test_gpt5_2_temperature_with_reasoning_effort_none(config: OpenAIConfig): assert params["reasoning_effort"] == "none" +def test_gpt5_4_allows_reasoning_effort_xhigh(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"reasoning_effort": "xhigh"}, + optional_params={}, + model="gpt-5.4", + drop_params=False, + ) + assert params["reasoning_effort"] == "xhigh" + + +def test_gpt5_4_pro_allows_reasoning_effort_xhigh(config: OpenAIConfig): + params = config.map_openai_params( + non_default_params={"reasoning_effort": "xhigh"}, + optional_params={}, + model="gpt-5.4-pro", + drop_params=False, + ) + assert params["reasoning_effort"] == "xhigh" + + +def test_gpt5_4_pro_rejects_non_default_temperature(config: OpenAIConfig): + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"temperature": 0.5}, + optional_params={}, + model="gpt-5.4-pro", + drop_params=False, + ) + + def test_gpt5_1_temperature_without_reasoning_effort(config: OpenAIConfig): """Test that GPT-5.1 supports any temperature when reasoning_effort is not specified.