diff --git a/litellm/llms/chatgpt/responses/transformation.py b/litellm/llms/chatgpt/responses/transformation.py index 7163cc5d3e0..d3b52bb844d 100644 --- a/litellm/llms/chatgpt/responses/transformation.py +++ b/litellm/llms/chatgpt/responses/transformation.py @@ -83,6 +83,8 @@ class ChatGPTResponsesAPIConfig(OpenAIResponsesAPIConfig): litellm_params, headers, ) + if isinstance(input, str) and input != "": + request["input"] = [{"role": "user", "content": [{"type": "input_text", "text": input}]}] base_instructions: Final = get_chatgpt_default_instructions() existing_instructions: Final = request.get("instructions") if existing_instructions: diff --git a/tests/unit/llms/chatgpt/responses/test_chatgpt_responses_transformation.py b/tests/unit/llms/chatgpt/responses/test_chatgpt_responses_transformation.py index f9e7628f23e..4b4d0cdfb80 100644 --- a/tests/unit/llms/chatgpt/responses/test_chatgpt_responses_transformation.py +++ b/tests/unit/llms/chatgpt/responses/test_chatgpt_responses_transformation.py @@ -186,9 +186,66 @@ class TestChatGPTResponsesAPITransformation: ) assert request["stream"] is True + assert request["input"] == [ + { + "role": "user", + "content": [{"type": "input_text", "text": "hi"}], + } + ] assert "reasoning.encrypted_content" in request["include"] assert request["instructions"].startswith("You are Codex, based on GPT-5.") + def test_chatgpt_normalizes_string_input_with_tools(self) -> None: + config: Final = ChatGPTResponsesAPIConfig() + tools: Final = [{"type": "function", "name": "echo", "parameters": {}}] + request: Final = config.transform_responses_api_request( + model="chatgpt/gpt-6.1-sol", + input="Call echo with ping.", + response_api_optional_request_params={ + "tools": tools, + "tool_choice": "required", + }, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert request["input"] == [ + { + "role": "user", + "content": [{"type": "input_text", "text": "Call echo with ping."}], + } + ] + assert request["tools"] == tools + assert request["tool_choice"] == "required" + + def test_chatgpt_keeps_list_input_unchanged(self) -> None: + config: Final = ChatGPTResponsesAPIConfig() + list_input: Final = [ + {"role": "user", "content": [{"type": "input_text", "text": "first"}]}, + {"type": "function_call_output", "call_id": "call_1", "output": "done"}, + ] + request: Final = config.transform_responses_api_request( + model="chatgpt/gpt-6.1-sol", + input=list_input, + response_api_optional_request_params={}, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert request["input"] == list_input + + def test_chatgpt_leaves_empty_string_input_for_the_backend_to_reject(self) -> None: + config: Final = ChatGPTResponsesAPIConfig() + request: Final = config.transform_responses_api_request( + model="chatgpt/gpt-6.1-sol", + input="", + response_api_optional_request_params={}, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert request["input"] == "" + @pytest.mark.parametrize( "model_name", [