-
Notifications
You must be signed in to change notification settings - Fork 790
.NET: AG-UI support for .NET #1776
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
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 PR introduces AG-UI (Agent-User Interaction) protocol support for the Microsoft Agent Framework, enabling standardized client-server communication for AI agents. The implementation includes both server-side ASP.NET Core hosting capabilities and client-side consumption functionality.
Key changes:
- Added AG-UI protocol implementation with server-sent events (SSE) streaming
- Created ASP.NET Core hosting extensions for exposing agents via AG-UI endpoints
- Implemented AGUIAgent client for consuming remote AG-UI services
- Added comprehensive unit and integration tests covering protocol behavior
Reviewed Changes
Copilot reviewed 47 out of 47 changed files in this pull request and generated 29 comments.
Show a summary per file
| File | Description |
|---|---|
Microsoft.Agents.AI.AGUI/AGUIAgent.cs |
Core client implementation for connecting to AG-UI servers |
Microsoft.Agents.AI.AGUI/AGUIHttpService.cs |
HTTP service for SSE-based communication with AG-UI endpoints |
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs |
Extension methods for mapping AG-UI agents to ASP.NET endpoints |
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIServerSentEventsResult.cs |
IResult implementation for streaming AG-UI events via SSE |
Shared/*.cs |
Protocol event types, serialization contexts, and message conversion utilities |
| Test files | Comprehensive unit and integration tests for AG-UI functionality |
samples/AGUIClientServer/* |
Sample client and server demonstrating AG-UI protocol usage |
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AgentRunResponseUpdateAGUIExtensionsTests.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AgentRunResponseUpdateAGUIExtensions.cs
Outdated
Show resolved
Hide resolved
...osoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIServerSentEventsResult.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIServerSentEventsResult.cs
Outdated
Show resolved
Hide resolved
|
@javiercn can you copy the information in the PR description to an ADR and add to this folder: https://github.com/microsoft/agent-framework/tree/main/docs/decisions It will be much easier to find the information later and it will be with all of the other design decisions. |
0f9d19d to
f58312e
Compare
javiercn
left a comment
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.
Addressed feedback:
- I've gotten rid of the custom contents and mapped the info from the events as ResponseUpdate.
- I switched to use the SseFormatter instead of the manual SSE Event serialization.
- I've gotten rid of Context/Tools/ForwardedProps for now and will bring them in a separate PR.
- I've mapped additional properties to response updates.
- I removed some buffering when dealing with messages.
- I've fixed the build dependencies and cleaned up some copilot leftover.
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AgentRunResponseUpdateAGUIExtensions.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AgentRunResponseUpdateAGUIExtensions.cs
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIChatMessageExtensions.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIServerSentEventsResult.cs
Outdated
Show resolved
Hide resolved
Yep, I saw the ADRs, and was planning to do that, but wanted to check with you first. I'll include the ADRs as a last step as we work out through the details |
…and update the sample client
ba5e4a2 to
ea7c7af
Compare
|
I'll give it a go on the other PR that I have in flight as I'm touching the json serialization there. |
* .NET: [BREAKING] Simplify TextSearchProvider construction and improve Mem0Provider scoping. (#1905) * Simplify TextSearchProvider construction and improve Mem0Provider scoping * Fixing indentation. * .NET: [Breaking Change] Moving MAAI.AzureAI V1 Package -> MAAI.AzureAI.Persistent (V1) (#1902) * Update AzureAI -> AzureAI.Persistent * Fix sample reference * Fix workflow lookup with AddAsAIAgent(name) when name differs from workflow name (#1925) * .NET: AG-UI support for .NET (#1776) * Initial plan * Infrastructure setup * Plan for minimal client * Plan update * Basic agentic chat * cleanup * Cleanups * More cleanups * Cleanups * More cleanups * Test plan * Sample * Fix streaming and error handling * Fix notifications * Cleanups * cleanup sample * Additional tests * Additional tests * Run dotnet format * Remove unnecessary files * Mark packages as non packable * Fix build * Address feedback * Fix build * Fix remaining warnings * Feedback * Feedback and cleanup * Cleanup * Cleanups * Cleanups * Cleanups * Retrieve existing messages from the store to send them along the way and update the sample client * Run dotnet format * Add ADR for AG-UI * Switch to use the SG and use a convention for run ids * Cleanup MapAGUI API * Fix formatting * Fix solution * Fix solution * Python: Added parameter to disable agent cleanup in AzureAIAgentClient (#1882) * Removed automatic agent cleanup in AzureAIAgentClient * Revert "Removed automatic agent cleanup in AzureAIAgentClient" This reverts commit 89846c7. * Exposed boolean flag to control deletion behavior * Update sample * [BREAKING] refactor: Fix unintuitive binding of StreamAsync (#1930) In #1551 we added a mechanism to open a Streaming workflow run without providing any input. This caused unintuitive behaviour when passing a string as input without providing a runId, resulting in the input being misinterpreted as the runId and the workflow not executing. As well, the name caused confusion about why the Workflow was not running when using the input-less StreamAsync (since the Workflow cannot run without any messages to drive its execution). * Python: fix missing packaging dependency (#1929) * fix missing packaging dependency * add aiohttp to azureai * Bring back files * Address merge conflict * Address merge conflict+ --------- Co-authored-by: westey <[email protected]> Co-authored-by: Jeff Handley <[email protected]> Co-authored-by: Javier Calvarro Nelson <[email protected]> Co-authored-by: Dmytro Struk <[email protected]> Co-authored-by: Jacob Alber <[email protected]> Co-authored-by: Eduard van Valkenburg <[email protected]>
Summary
This PR implements Phase 1 of AG-UI protocol support in the .NET Agent Framework, enabling text streaming capabilities for both consuming AG-UI-compliant servers and exposing .NET agents via the AG-UI protocol.
Motivation and goals
The AG-UI (Agent-User Interaction) protocol is an open, lightweight, event-based protocol that standardizes how AI agents connect to user-facing applications. It addresses key challenges in agentic applications:
Without AG-UI support, .NET agents cannot interoperate with the growing ecosystem of AG-UI-compatible frontends and agent frameworks (LangGraph, CrewAI, Pydantic AI, etc.).
This implementation enables:
In scope
Client-side AG-UI consumption (
Microsoft.Agents.AI.AGUIpackage)AGUIAgentclass for connecting to remote AG-UI serversAGUIAgentThreadfor managing conversation threadsServer-side AG-UI hosting (
Microsoft.Agents.AI.Hosting.AGUI.AspNetCorepackage)MapAGUIAgentextension method for ASP.NET CoreSseFormatterText streaming events (Phase 1)
RunStarted,RunFinished,RunErrorTextMessageStart,TextMessageContent,TextMessageEndConversationIdandResponseIdpropertiesTesting and samples
Out of scope
The following AG-UI features are intentionally deferred to future PRs:
ToolCallStart,ToolCallArgs,ToolCallEnd,ToolCallResult)StateSnapshot,StateDelta,MessagesSnapshot)StepStarted,StepFinished)Examples
Server: Exposing a .NET agent via AG-UI
Client: Consuming an AG-UI server
SSE Event Stream Format
When a client sends a request:
The server streams back SSE events:
Detailed design
Architecture
Package Structure
Key Design Decisions
1. Event Models as Internal Types
RunStartedEvent,TextMessageContentEvent) are internalAgentRunResponseUpdate,ChatMessage)2. No Custom Content Types
ChatResponseUpdate.ConversationIdandResponseIdpropertiesErrorContenttypeConversationIdandResponseIdindicating run startedFinishReasonindicates run finished3. Agent Factory Pattern in MapAGUIAgent
(messages) => AIAgent4. Bidirectional Conversion Architecture
AgentRunResponseUpdate→ AG-UI eventsAgentRunResponseUpdateShared/namespace (compiled in both packages)5. Thread Management
AGUIAgentThreadstores onlyThreadId(string)ConversationIdproperty on updates6. SSE Formatting
SseFormatterfor Server-Sent Eventsdata:prefix and double newline delimiterEvent Conversion Logic
Text Message Streaming (Server → Client):
Text Message Streaming (Client → Framework):
JSON Serialization
System.Text.Json.Serialization.JsonConverterfor polymorphic eventsBaseEventJsonConverterdispatches based on"type"fieldAGUIJsonSerializerContext) for AOT compatibilityError Handling
HttpRequestExceptionRunErrorevents convert toErrorContentin update streamJsonExceptionorInvalidOperationExceptionOperationCanceledExceptionwhen cancelledDrawbacks
Custom JSON Converter: Required custom polymorphic deserialization instead of built-in STJ support
Shared Code via Preprocessor Directives: Files in
Shared/use#if ASPNETCOREto compile into both packagesConsidered alternatives
Alternative 1: Expose AG-UI Event Types Publicly
Rejected: We already have common abstractions for AI concepts. We can break AG-UI specific payloads into a separate assembly in the future and take a dependency on that if needed.
Alternative 2: Implement All Event Types Upfront
Rejected: Keeping the PR manageable and focused on text streaming. Tool calls and state management can be added incrementally.
Alternative 3: Custom AIContent Types for Lifecycle
Rejected after review: Initially proposed
RunStartedContent,RunFinishedContent, andRunErrorContent. Feedback indicated these should use existing framework properties (ConversationId,ResponseId,ErrorContent) instead.#Fixes #1775