-
Notifications
You must be signed in to change notification settings - Fork 872
.NET: AG-UI support for .NET: Support for tool calling #1896
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIChatMessageExtensions.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIChatMessageExtensions.cs
Outdated
Show resolved
Hide resolved
874ab82 to
470a4e9
Compare
3e04ada to
3d76689
Compare
3ee8c5c to
6819297
Compare
aab3bca to
d4c1b00
Compare
dbe5787 to
f18e885
Compare
d4c1b00 to
0071988
Compare
ba5e4a2 to
ea7c7af
Compare
1004759 to
ae684aa
Compare
90bcd28 to
447eef1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request adds comprehensive tool calling support to the AG-UI framework, enabling both client-side and server-side function execution. The changes include:
- Refactored the AG-UI architecture to use
AGUIChatClient(implementingIChatClient) instead ofAGUIAgent - Added polymorphic message types (AGUIUserMessage, AGUIAssistantMessage, AGUIToolMessage, etc.) replacing the single AGUIMessage class
- Implemented tool call event types (ToolCallStartEvent, ToolCallArgsEvent, ToolCallEndEvent, ToolCallResultEvent) for streaming tool execution
- Added extensive unit and integration tests covering tool calling scenarios
- Updated samples to demonstrate client/server tool calling capabilities
Reviewed Changes
Copilot reviewed 50 out of 50 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.AGUI/AGUIChatClient.cs | New IChatClient implementation with tool calling support |
| dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ChatResponseUpdateAGUIExtensions.cs | Core conversion logic between ChatResponseUpdate and AG-UI events including tool calls |
| dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIMessage*.cs | Polymorphic message type hierarchy replacing single AGUIMessage class |
| dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ToolCall*.cs | New event types for tool call streaming |
| dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ChatResponseUpdateAGUIExtensionsTests.cs | Comprehensive unit tests for tool calling conversion |
| dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs | End-to-end integration tests with Azure OpenAI |
| dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs | Server-side endpoint supporting tool execution |
| dotnet/samples/AGUIClientServer/AGUIClient/Program.cs | Updated client sample with tool calling |
| dotnet/samples/AGUIClientServer/AGUIServer/Program.cs | Updated server sample with tool registration |
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ChatResponseUpdateAGUIExtensions.cs
Show resolved
Hide resolved
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ChatResponseUpdateAGUIExtensions.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIChatMessageExtensions.cs
Outdated
Show resolved
Hide resolved
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AGUIChatMessageExtensionsTests.cs
Show resolved
Hide resolved
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AGUIChatClientTests.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs
Outdated
Show resolved
Hide resolved
447eef1 to
48e9c55
Compare
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIChatMessageExtensions.cs
Outdated
Show resolved
Hide resolved
a64e873 to
abdd3e0
Compare
|
Integration failure unrelated |
This PR adds comprehensive support for tool calling in the AG-UI implementation for .NET, including client-side and server-side function execution, conversation management, and proper serialization across boundaries.
Key Changes
1. AGUIAgent → AGUIChatClient: Architectural Shift
Previous Architecture:
AGUIAgentas a wrapper around anIChatClientNew Architecture:
AGUIChatClientis now anIChatClientimplementation that communicates with AG-UI compliant serversDelegatingChatClientand wraps aFunctionInvokingChatClientAGUIChatClient(outer) - manages conversation ID and ServerFunctionCallContent wrapping/unwrappingFunctionInvokingChatClient(middle) - handles client-side tool executionAGUIChatClientHandler(inner) - handles HTTP communication with AG-UI serverWhy this matters:
FunctionInvokingChatClientfor client-side tool executionIChatClientinterface consistently with the rest of the ecosystem2. ConversationId Handling in AG-UI
AG-UI has a fundamental constraint: it requires the full message history on every turn and uses
ThreadIdfor conversation tracking. However, the Microsoft.Extensions.AIIChatClientinterface usesConversationIdto indicate stateful conversation management where the client maintains history.The Challenge:
ChatOptions.ConversationIdis set,FunctionInvokingChatClientassumes the underlying client maintains history and only sends new messagesFunctionInvokingChatClientfrom treating the conversation as statefulThe Solution:
The PR implements a sophisticated "conversation ID juggling" pattern:
On Request (Client → Server):
During Tool Execution:
FunctionCallContent.AdditionalProperties["agui_thread_id"]On Response (Server → Client):
Why this complex approach?
ConversationIdimplies incremental historyFunctionInvokingChatClientbehavior: Only sends new messages whenConversationIdis setConversationIdfrom the middleware layer, useAdditionalPropertiesas temporary storage, restore it for the callerThis ensures:
ConversationIdacross all updates3. ServerFunctionCallContent: Hiding Server-Executed Tools
The Problem:
When a server executes a tool, it returns a
FunctionCallContentin the response stream. The wrappingFunctionInvokingChatClientsees this and tries to execute it again on the client side, causing:The Solution - ServerFunctionCallContent:
How it works:
Detection (in
AGUIChatClientHandler):Unwrapping (in
AGUIChatClient):Why a wrapper class?
FunctionInvokingChatClientonly recognizesFunctionCallContentas something it should executeServerFunctionCallContent, they become "invisible" to the middlewareAGUIChatClientthen unwraps them before yielding to the callerFunctionCallContent, but middleware doesn't try to execute server toolsBenefits:
Additional Changes in Broad Strokes
Message Type Hierarchy
AGUIMessage(base) with concrete types:AGUIUserMessageAGUIAssistantMessageAGUISystemMessageAGUIDeveloperMessageAGUIToolMessageAGUIMessagewith role strings to strongly-typed message classesTool Call Events
ToolCallStartEventToolCallArgsEventToolCallEndEventToolCallResultEventChatResponseUpdate(withFunctionCallContent) and AG-UI eventsJSON Serialization
JsonSerializerOptionsparameter toAGUIChatClientconstructorJsonElementon client)