From 21b3fca5b0171a3c21bcd196f2099b96da4e44f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E5=9F=BA=E9=AD=81?= <1412414664@qq.com> Date: Tue, 23 Jun 2026 23:58:12 +0800 Subject: [PATCH] fix: skip parsing incomplete response text --- src/openai/lib/_parsing/_responses.py | 4 ++- tests/lib/responses/test_responses.py | 50 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/openai/lib/_parsing/_responses.py b/src/openai/lib/_parsing/_responses.py index 232718cef6..4b22033cb0 100644 --- a/src/openai/lib/_parsing/_responses.py +++ b/src/openai/lib/_parsing/_responses.py @@ -71,7 +71,9 @@ def parse_response( type_=ParsedResponseOutputText[TextFormatT], value={ **item.to_dict(), - "parsed": parse_text(item.text, text_format=text_format), + "parsed": parse_text(item.text, text_format=text_format) + if output.status == "completed" + else None, }, ) ) diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py index 8e5f16df95..0ae938285a 100644 --- a/tests/lib/responses/test_responses.py +++ b/tests/lib/responses/test_responses.py @@ -4,10 +4,14 @@ import pytest from respx import MockRouter +from pydantic import BaseModel from inline_snapshot import snapshot from openai import OpenAI, AsyncOpenAI from openai._utils import assert_signatures_in_sync +from openai._models import construct_type_unchecked +from openai.types.responses import Response +from openai.lib._parsing._responses import parse_response from ...conftest import base_url from ..snapshots import make_snapshot_request @@ -41,6 +45,52 @@ def test_output_text(client: OpenAI, respx_mock: MockRouter) -> None: ) +def test_parse_incomplete_output_text() -> None: + class CalendarEvent(BaseModel): + name: str + + content_item: dict[str, object] = { + "type": "output_text", + "text": '{"name":', + "annotations": [], + "logprobs": [], + } + output_item: dict[str, object] = { + "id": "msg_123", + "type": "message", + "role": "assistant", + "status": "incomplete", + "content": [content_item], + } + response_payload: dict[str, object] = { + "id": "resp_123", + "object": "response", + "created_at": 0, + "model": "gpt-4o-mini", + "output": [output_item], + "parallel_tool_calls": True, + "tool_choice": "auto", + "tools": [], + } + response = construct_type_unchecked( + type_=Response, + value=response_payload, + ) + + parsed = parse_response(text_format=CalendarEvent, input_tools=None, response=response) + + assert parsed.output_parsed is None + + output = parsed.output[0] + assert output.type == "message" + assert output.status == "incomplete" + + content = output.content[0] + assert content.type == "output_text" + assert content.text == '{"name":' + assert content.parsed is None + + @pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) def test_stream_method_definition_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: checking_client: OpenAI | AsyncOpenAI = client if sync else async_client