fix(openai): accommodate dict response items in streaming (#36899)

This commit is contained in:
ccurme
2026-04-20 15:44:01 -04:00
committed by GitHub
parent 8fec4e7cee
commit 19b0805bc1
3 changed files with 48 additions and 7 deletions

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
import copy
from typing import Any
from unittest.mock import MagicMock, patch
@@ -986,3 +987,32 @@ def test_responses_stream_function_call_preserves_namespace() -> None:
assert first_block.get("namespace") == "my_namespace", (
f"Expected namespace 'my_namespace', got {first_block.get('namespace')}"
)
def test_responses_stream_tolerates_dict_response_field() -> None:
"""Regression test for `AttributeError: 'dict' object has no attribute 'id'`.
The OpenAI SDK types `<event>.response` strictly as `Response`, but raw dicts
have been observed in the wild.
"""
stream = copy.deepcopy(responses_stream)
first_event = stream[0]
assert isinstance(first_event, ResponseCreatedEvent)
first_event.response = first_event.response.model_dump(mode="json") # type: ignore[assignment]
assert isinstance(first_event.response, dict)
llm = ChatOpenAI(model="o4-mini", use_responses_api=True)
mock_client = MagicMock()
def mock_create(*args: Any, **kwargs: Any) -> MockSyncContextManager:
return MockSyncContextManager(stream)
mock_client.responses.create = mock_create
full: BaseMessageChunk | None = None
with patch.object(llm, "root_client", mock_client):
for chunk in llm.stream("test"):
assert isinstance(chunk, AIMessageChunk)
full = chunk if full is None else full + chunk
assert isinstance(full, AIMessageChunk)
assert full.id == "resp_123"