mirror of
https://github.com/langchain-ai/langchain.git
synced 2026-10-05 09:25:14 +03:00
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:
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 (
|
||||
|
||||
Reference in new issue
Block a user