From 2950e3a9bb6e93469658818fb10682fb171e031c Mon Sep 17 00:00:00 2001 From: HeMuling <74801533+HeMuling@users.noreply.github.com> Date: Mon, 23 Mar 2026 00:18:32 +0800 Subject: [PATCH] fix(chatgpt): preserve text and parallel_tool_calls in responses --- .../llms/chatgpt/responses/transformation.py | 2 + .../test_chatgpt_responses_transformation.py | 65 +++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/litellm/llms/chatgpt/responses/transformation.py b/litellm/llms/chatgpt/responses/transformation.py index 3c59ca16581..7a507057624 100644 --- a/litellm/llms/chatgpt/responses/transformation.py +++ b/litellm/llms/chatgpt/responses/transformation.py @@ -96,9 +96,11 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig): "stream", "store", "include", + "parallel_tool_calls", "tools", "tool_choice", "reasoning", + "text", "previous_response_id", "truncation", } 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 c0a0927b7d1..7bfb42827b8 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 @@ -103,10 +103,58 @@ class TestChatGPTResponsesAPITransformation: assert request["stream"] is True assert "reasoning.encrypted_content" in request["include"] - assert request["instructions"].startswith( - "You are Codex, based on GPT-5." + assert request["instructions"].startswith("You are Codex, based on GPT-5.") + + @pytest.mark.parametrize( + "text_value", + [ + { + "format": { + "type": "json_schema", + "name": "answer_schema", + "schema": { + "type": "object", + "properties": {"answer": {"type": "string"}}, + "required": ["answer"], + "additionalProperties": False, + }, + "strict": True, + } + }, + {"format": {"type": "json_object"}}, + {"format": {"type": "text"}}, + ], + ids=["json_schema", "json_object", "text"], + ) + def test_chatgpt_preserves_text_param(self, text_value): + config = ChatGPTResponsesAPIConfig() + request = config.transform_responses_api_request( + model="chatgpt/gpt-5.2-codex", + input="hi", + response_api_optional_request_params={"text": text_value}, + litellm_params=GenericLiteLLMParams(), + headers={}, ) + assert request["text"] == text_value + assert request["stream"] is True + assert "reasoning.encrypted_content" in request["include"] + assert request["instructions"].startswith("You are Codex, based on GPT-5.") + + def test_chatgpt_preserves_parallel_tool_calls(self): + config = ChatGPTResponsesAPIConfig() + request = config.transform_responses_api_request( + model="chatgpt/gpt-5.2-codex", + input="hi", + response_api_optional_request_params={"parallel_tool_calls": False}, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert request["parallel_tool_calls"] is False + assert request["stream"] is True + assert "reasoning.encrypted_content" in request["include"] + @pytest.mark.parametrize( "model_name", [ @@ -124,14 +172,18 @@ class TestChatGPTResponsesAPITransformation: "user": "user_123", "temperature": 0.2, "top_p": 0.9, - "context_management": [{"type": "compaction", "compact_threshold": 200000}], + "context_management": [ + {"type": "compaction", "compact_threshold": 200000} + ], "metadata": {"foo": "bar"}, "max_output_tokens": 123, "stream_options": {"include_usage": True}, # supported and should be preserved "truncation": "auto", "previous_response_id": "resp_123", + "parallel_tool_calls": False, "reasoning": {"effort": "medium"}, + "text": {"format": {"type": "json_object"}}, "tools": [{"type": "function", "function": {"name": "hello"}}], "tool_choice": {"type": "function", "function": {"name": "hello"}}, }, @@ -149,9 +201,14 @@ class TestChatGPTResponsesAPITransformation: assert request["truncation"] == "auto" assert request["previous_response_id"] == "resp_123" + assert request["parallel_tool_calls"] is False assert request["reasoning"] == {"effort": "medium"} + assert request["text"] == {"format": {"type": "json_object"}} assert request["tools"] == [{"type": "function", "function": {"name": "hello"}}] - assert request["tool_choice"] == {"type": "function", "function": {"name": "hello"}} + assert request["tool_choice"] == { + "type": "function", + "function": {"name": "hello"}, + } @pytest.mark.parametrize( ("model_name", "response_model"),