Skip to content

Commit b4c4f50

Browse files
authored
Python: Emit tool call events in GitHubCopilotAgent streaming (microsoft#4711)
* Emit tool call events in GitHubCopilotAgent streaming _stream_updates now yields FunctionCallContent for TOOL_EXECUTION_START and FunctionResultContent for TOOL_EXECUTION_COMPLETE events from the Copilot SDK session. This enables DevUI and other consumers to display tool calls during streaming agent execution. Previously only ASSISTANT_MESSAGE_DELTA, SESSION_IDLE, and SESSION_ERROR were handled — tool execution events were silently dropped. Signed-off-by: James Sturtevant <jsturtevant@gmail.com> * Add some tests Signed-off-by: James Sturtevant <jsturtevant@gmail.com> * Respond to feedback Signed-off-by: James Sturtevant <jsturtevant@gmail.com> * Fix TOOL_EXECUTION_COMPLETE to use correct SDK types - Read result text from session_events.Result.content (not ToolResult.text_result_for_llm) - Read failure state from event.data.success/error (not result_obj.result_type/error) - Handle ErrorClass.message and plain string errors - Update tests to use session_events.Result and ErrorClass - Add tests for string errors, success-with-error, and COMPLETE missing fields Signed-off-by: James Sturtevant <jsturtevant@gmail.com> --------- Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
1 parent 0cd40f8 commit b4c4f50

2 files changed

Lines changed: 408 additions & 1 deletion

File tree

python/packages/github_copilot/agent_framework_github_copilot/_agent.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,43 @@ def event_handler(event: SessionEvent) -> None:
458458
raw_representation=event,
459459
)
460460
queue.put_nowait(update)
461+
elif event.type == SessionEventType.TOOL_EXECUTION_START:
462+
tool_call_id = getattr(event.data, "tool_call_id", None) or ""
463+
tool_name = getattr(event.data, "tool_name", None) or ""
464+
arguments = getattr(event.data, "arguments", None)
465+
fc = Content.from_function_call(
466+
call_id=tool_call_id,
467+
name=tool_name,
468+
arguments=arguments,
469+
raw_representation=event.data,
470+
)
471+
update = AgentResponseUpdate(
472+
role="assistant",
473+
contents=[fc],
474+
raw_representation=event,
475+
)
476+
queue.put_nowait(update)
477+
elif event.type == SessionEventType.TOOL_EXECUTION_COMPLETE:
478+
tool_call_id = getattr(event.data, "tool_call_id", None) or ""
479+
result_obj = getattr(event.data, "result", None)
480+
result_text = getattr(result_obj, "content", "") if result_obj else ""
481+
success = getattr(event.data, "success", None)
482+
error_val = getattr(event.data, "error", None)
483+
exception = None
484+
if success is False and error_val is not None:
485+
exception = error_val.message if hasattr(error_val, "message") else str(error_val)
486+
fr = Content.from_function_result(
487+
call_id=tool_call_id,
488+
result=result_text or "",
489+
exception=exception,
490+
raw_representation=event.data,
491+
)
492+
update = AgentResponseUpdate(
493+
role="tool",
494+
contents=[fr],
495+
raw_representation=event,
496+
)
497+
queue.put_nowait(update)
461498
elif event.type == SessionEventType.SESSION_IDLE:
462499
queue.put_nowait(None)
463500
elif event.type == SessionEventType.SESSION_ERROR:

0 commit comments

Comments
 (0)