Python: Fix response_format crash on background polling with empty text (#5146)

* Guard against empty text in _parse_structured_response_value (#5145)

When using response_format with background=True (Responses API), polling
an in-progress response produces empty text. _parse_structured_response_value
unconditionally passed this to model_validate_json/json.loads, causing
ValidationError or JSONDecodeError.

Add an early return of None when text is empty, matching the existing
guard for response_format=None. This allows .value to safely return None
for in-progress background responses.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Python: Fix `response_format` crash on background polling with empty text

Fixes #5145

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eduard van Valkenburg
2026-04-08 00:26:03 +02:00
committed by GitHub
Unverified
parent 36cafe4e5a
commit f94a75daa5
2 changed files with 29 additions and 0 deletions
@@ -1957,6 +1957,8 @@ class ContinuationToken(TypedDict):
def _parse_structured_response_value(text: str, response_format: Any | None) -> Any | None:
if response_format is None:
return None
if not text:
return None
if isinstance(response_format, type) and issubclass(response_format, BaseModel):
return response_format.model_validate_json(text)
if isinstance(response_format, Mapping):
@@ -39,6 +39,7 @@ from agent_framework._types import (
_get_data_bytes,
_get_data_bytes_as_str,
_parse_content_list,
_parse_structured_response_value,
_validate_uri,
add_usage_details,
validate_tool_mode,
@@ -813,6 +814,32 @@ def test_chat_response_with_mapping_response_format() -> None:
assert response.value["response"] == "Hello"
def test_parse_structured_response_value_empty_text_with_pydantic_model() -> None:
"""Empty text should return None instead of raising when response_format is a Pydantic model."""
result = _parse_structured_response_value("", OutputModel)
assert result is None
def test_parse_structured_response_value_empty_text_with_mapping() -> None:
"""Empty text should return None instead of raising when response_format is a mapping."""
result = _parse_structured_response_value("", {"type": "object"})
assert result is None
def test_chat_response_value_with_empty_text_and_response_format() -> None:
"""ChatResponse.value should return None when text is empty and response_format is set."""
message = Message(role="assistant", contents=[""])
response = ChatResponse(messages=message, response_format=OutputModel)
assert response.value is None
def test_agent_response_value_with_empty_text_and_response_format() -> None:
"""AgentResponse.value should return None when text is empty and response_format is set."""
message = Message(role="assistant", contents=[""])
response = AgentResponse(messages=message, response_format=OutputModel)
assert response.value is None
def test_chat_response_value_raises_on_invalid_schema():
"""Test that value property raises ValidationError with field constraint details."""