.NET: Implement tool events > function call events for AG-UI support#4824
.NET: Implement tool events > function call events for AG-UI support#4824kzu wants to merge 1 commit intomicrosoft:mainfrom
Conversation
Added two new case branches and three new converter methods: - ToolExecutionStartEvent → FunctionCallContent (the AGUI layer then emits TOOL_CALL_START/ARGS/END to the client) - ToolExecutionCompleteEvent → FunctionResultContent → TOOL_CALL_RESULT - Arguments are converted from JsonElement using AOT-safe JsonElement.EnumerateObject() — no reflection/dynamic code Fixes microsoft#4823
There was a problem hiding this comment.
Pull request overview
Adds forwarding of GitHub Copilot SDK tool execution events into the Agent Framework’s function-call/function-result content model so the AG-UI adapter can surface tool-call lifecycle events to clients (fixing #4823).
Changes:
- Handle
ToolExecutionStartEventandToolExecutionCompleteEventin the Copilot session streaming event switch. - Convert tool-start to
FunctionCallContent(including JSON argument conversion) and tool-complete toFunctionResultContent. - Add unit tests covering tool start/complete conversions and JSON argument handling.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.GitHub.Copilot/GitHubCopilotAgent.cs | Adds streaming handling + conversion helpers to emit FunctionCallContent/FunctionResultContent from tool events. |
| dotnet/tests/Microsoft.Agents.AI.GitHub.Copilot.UnitTests/GitHubCopilotAgentTests.cs | Adds tests validating tool event conversion behavior and argument mapping. |
| JsonValueKind.Null => null, | ||
| JsonValueKind.Number => property.Value.TryGetInt64(out long l) | ||
| ? (object?)l | ||
| : property.Value.GetDouble(), |
There was a problem hiding this comment.
ConvertJsonElementToArguments currently converts non-primitive argument values (e.g., JsonValueKind.Object/Array) using GetRawText(), which turns them into JSON strings. When these arguments are later serialized (e.g., into AG-UI ToolCallArgs events), nested objects/arrays will be double-encoded instead of remaining structured JSON. Prefer preserving structured values by returning JsonElement (e.g., property.Value.Clone()) for Object/Array (and consider how to handle Undefined), so downstream serialization emits proper JSON objects/arrays.
| : property.Value.GetDouble(), | |
| : property.Value.GetDouble(), | |
| JsonValueKind.Object => property.Value.Clone(), | |
| JsonValueKind.Array => property.Value.Clone(), | |
| JsonValueKind.Undefined => null, |
| // Non-primitive values fall back to raw JSON text | ||
| Assert.IsType<string>(content.Arguments["objVal"]); |
There was a problem hiding this comment.
The test currently asserts objVal is a string (raw JSON text). If arguments are intended to round-trip as structured JSON through the AG-UI layer, nested object/array values should be preserved as structured types (e.g., JsonElement) rather than raw JSON strings. Consider updating this assertion to validate the intended structured representation so regressions don’t reintroduce double-encoding of nested arguments.
| // Non-primitive values fall back to raw JSON text | |
| Assert.IsType<string>(content.Arguments["objVal"]); | |
| // Non-primitive values are preserved as structured JSON | |
| var objValElement = Assert.IsType<JsonElement>(content.Arguments["objVal"]); | |
| Assert.Equal("value", objValElement.GetProperty("nested").GetString()); |
Added two new case branches and three new converter methods:
Motivation and Context
When using Copilot SDK adapter to expose an AG-UI client, tool call events aren't surfaced at all as events the client can show.
Fixes #4823