mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Fix streaming path to emit mcp_server_tool_result on output_item.done instead of output_item.added (#4821)
* Fix streaming path to deliver mcp_server_tool_result content (#4814) Remove premature mcp_server_tool_result emission from the response.output_item.added/mcp_call handler — at that point the MCP server has not yet responded and output is always None. Add a handler for response.mcp_call.completed that emits mcp_server_tool_result with the actual tool output, matching the non-streaming path behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix streaming path to deliver mcp_server_tool_result content (#4814) Stop eagerly emitting mcp_server_tool_result on response.output_item.added (when output is always None). Instead, handle response.output_item.done for mcp_call items, which carries the full McpCall with populated output. This matches the non-streaming path which guards with 'if item.output is not None' before emitting the result. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix test docstring to match actual implementation event name Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: call_id fallback and raw_representation consistency (#4814) - Add call_id fallback in response.output_item.done mcp_call handler to match the output_item.added handler pattern - Use done_item instead of event for raw_representation to keep consistent with other output_item branches and non-streaming path - Add test for call_id fallback when id attribute is missing - Add raw_representation assertions to existing done handler tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review: call_id fallback for non-streaming path and test coverage (#4814) - Apply defensive call_id fallback (getattr with id/call_id/empty) to non-streaming mcp_call path for consistency with streaming path - Add raw_representation assertion to call_id fallback test - Add test for empty-string fallback when neither id nor call_id exist Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
c1435ac201
commit
dc27740f1a
@@ -1728,7 +1728,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
)
|
||||
)
|
||||
case "mcp_call":
|
||||
call_id = item.id
|
||||
call_id = getattr(item, "id", None) or getattr(item, "call_id", None) or ""
|
||||
contents.append(
|
||||
Content.from_mcp_server_tool_call(
|
||||
call_id=call_id,
|
||||
@@ -2118,27 +2118,7 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
raw_representation=event_item,
|
||||
)
|
||||
)
|
||||
result_output = (
|
||||
getattr(event_item, "result", None)
|
||||
or getattr(event_item, "output", None)
|
||||
or getattr(event_item, "outputs", None)
|
||||
)
|
||||
parsed_output: list[Content] | None = None
|
||||
if result_output:
|
||||
normalized = ( # pyright: ignore[reportUnknownVariableType]
|
||||
result_output
|
||||
if isinstance(result_output, Sequence)
|
||||
and not isinstance(result_output, (str, bytes, MutableMapping))
|
||||
else [result_output]
|
||||
)
|
||||
parsed_output = [Content.from_dict(output_item) for output_item in normalized] # pyright: ignore[reportArgumentType,reportUnknownVariableType]
|
||||
contents.append(
|
||||
Content.from_mcp_server_tool_result(
|
||||
call_id=call_id,
|
||||
output=parsed_output,
|
||||
raw_representation=event_item,
|
||||
)
|
||||
)
|
||||
# Result deferred to response.output_item.done
|
||||
case "code_interpreter_call": # ResponseOutputCodeInterpreterCall
|
||||
call_id = getattr(event_item, "call_id", None) or getattr(event_item, "id", None)
|
||||
outputs: list[Content] = []
|
||||
@@ -2408,6 +2388,21 @@ class RawOpenAIChatClient( # type: ignore[misc]
|
||||
)
|
||||
else:
|
||||
logger.debug("Unparsed annotation type in streaming: %s", ann_type)
|
||||
case "response.output_item.done":
|
||||
done_item = event.item
|
||||
if getattr(done_item, "type", None) == "mcp_call":
|
||||
call_id = getattr(done_item, "id", None) or getattr(done_item, "call_id", None) or ""
|
||||
output_text = getattr(done_item, "output", None)
|
||||
parsed_output: list[Content] | None = (
|
||||
[Content.from_text(text=output_text)] if isinstance(output_text, str) else None
|
||||
)
|
||||
contents.append(
|
||||
Content.from_mcp_server_tool_result(
|
||||
call_id=call_id,
|
||||
output=parsed_output,
|
||||
raw_representation=done_item,
|
||||
)
|
||||
)
|
||||
case _:
|
||||
logger.debug("Unparsed event of type: %s: %s", event.type, event)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user