fix(openai): update function_call status on the done streaming event

Address review feedback on #39310: the streaming converter only
recorded a function_call's status from response.output_item.added
(typically "in_progress") and never updated it from
response.output_item.done, which carries the provider's final status
(typically "completed"). Replaying a streamed message therefore sent
a stale, transient status. This now emits a status-only update on the
done event, merged into the same content block (relies on the
companion langchain-core fix so merging doesn't concatenate the two
status strings).

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
Nishitha Mandopen-swe[bot] committed 2026-08-10 17:12:18 +00:00
1 parent dbc1fbf931
commit 0bfb12d18e
2 files changed
+74

No files matched your search

@@ -5194,6 +5194,20 @@ def _convert_responses_chunk_to_generation_chunk(
if getattr(chunk.item, "namespace", None) is not None:
function_call_content["namespace"] = chunk.item.namespace
content.append(function_call_content)
elif (
chunk.type == "response.output_item.done" and chunk.item.type == "function_call"
):
# The "added" event above records the transient status (typically
# "in_progress"); update it here with the terminal status (e.g.
# "completed") so a replayed history doesn't send a stale value.
_advance(chunk.output_index)
content.append(
{
"type": "function_call",
"status": getattr(chunk.item, "status", None),
"index": current_index,
}
)
elif chunk.type == "response.output_item.done" and chunk.item.type in (
"compaction",
"web_search_call",
@@ -2662,6 +2662,66 @@ def test__convert_responses_chunk_to_generation_chunk_function_call_status() ->
assert function_call_block["status"] == "in_progress"
def test__convert_responses_chunk_to_generation_chunk_function_call_done_status() -> (
None
):
"""A streamed function_call's terminal status overwrites the transient one.
The "added" event reports a transient status (typically "in_progress"),
and the "done" event reports the terminal status (e.g. "completed").
Merging the two chunks must not concatenate "status" as if it were
accumulated text.
"""
added_chunk = MagicMock()
added_chunk.type = "response.output_item.added"
added_chunk.output_index = 0
added_chunk.item = ResponseFunctionToolCall(
type="function_call",
id="func_123",
call_id="call_123",
name="get_weather",
arguments="",
status="in_progress",
)
idx, output_idx, sub_idx, added_generation_chunk = (
_convert_responses_chunk_to_generation_chunk(
added_chunk,
current_index=-1,
current_output_index=-1,
current_sub_index=-1,
)
)
assert added_generation_chunk is not None
done_chunk = MagicMock()
done_chunk.type = "response.output_item.done"
done_chunk.output_index = 0
done_chunk.item = ResponseFunctionToolCall(
type="function_call",
id="func_123",
call_id="call_123",
name="get_weather",
arguments="{}",
status="completed",
)
_, _, _, done_generation_chunk = _convert_responses_chunk_to_generation_chunk(
done_chunk,
current_index=idx,
current_output_index=output_idx,
current_sub_index=sub_idx,
)
assert done_generation_chunk is not None
merged = added_generation_chunk + done_generation_chunk
content = merged.message.content
assert isinstance(content, list)
function_call_block = content[0]
assert isinstance(function_call_block, dict)
assert function_call_block["status"] == "completed"
def test__construct_lc_result_from_responses_api_web_search_response() -> None:
"""Test a response with web search output."""
from openai.types.responses.response_function_web_search import (