From 9a69e89096e9f5131afaf15369f6359a89599aec Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 3 Jun 2026 15:00:14 +0100 Subject: [PATCH] fix: assistant input content must be output_text, not input_text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live /v1/responses rejects input_text for the assistant role (input[N].content[0] -> "Supported values are: 'output_text' and 'refusal'"). Revert the previous review-driven change: encode assistant turns as output_text and user/system turns as input_text. The SDK type union suggested input_* only, but the API enforces output_text per-role — confirmed against the live endpoint. --- application/llm/openai.py | 13 +++++-------- tests/llm/test_openai_responses.py | 4 +++- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/application/llm/openai.py b/application/llm/openai.py index ddbe5e3d..e3b9000e 100644 --- a/application/llm/openai.py +++ b/application/llm/openai.py @@ -461,15 +461,12 @@ class OpenAILLM(BaseLLM): @staticmethod def _responses_content_parts(role, content): """Translate a cleaned chat ``content`` value into Responses content - parts (``input_text``/``input_image``/``input_file``). - - Assistant text from prior turns is replayed as ``input_text`` too: a - Responses easy-input message only accepts the input_* content types - regardless of role (``output_text`` is reserved for full - output-message items, which carry id/status/annotations). + parts. The Responses API enforces the content-part type by message + role: assistant turns require ``output_text`` (``input_text`` is + rejected with a 400), while user/system turns require ``input_text``. + Images/files use ``input_image``/``input_file``. """ - _ = role - text_type = "input_text" + text_type = "output_text" if role == "assistant" else "input_text" parts = [] if content is None: return parts diff --git a/tests/llm/test_openai_responses.py b/tests/llm/test_openai_responses.py index 67a021d8..127edf49 100644 --- a/tests/llm/test_openai_responses.py +++ b/tests/llm/test_openai_responses.py @@ -102,7 +102,9 @@ def test_to_responses_input_tool_roundtrip(monkeypatch): "arguments": '{"q":"x"}', }, {"type": "function_call_output", "call_id": "call_1", "output": "result"}, - {"role": "assistant", "content": [{"type": "input_text", "text": "final"}]}, + # The Responses API requires output_text (not input_text) for the + # assistant role; input_text 400s. Locked in here so it can't regress. + {"role": "assistant", "content": [{"type": "output_text", "text": "final"}]}, ]