How to Integrate the AG-UI Protocol for Agent Interfaces in the Microsoft Agent Framework

Integrate the AG-UI protocol for agent interfaces in Agent Framework by using the MapAGUI extension to expose an ASP.NET Core endpoint that streams Server-Sent Events, and consume the stream with the AGUIChatClient class that automatically handles conversation threading and tool invocation.

The AG-UI (Agent-User Interface) protocol defines a lightweight, event-based standard for bidirectional communication between AI agents and frontend applications. When you integrate AG-UI protocol for agent interfaces in Agent Framework, you leverage the microsoft/agent-framework repository's built-in implementations for both server-side streaming and client-side consumption. This architecture enables real-time updates, persistent conversation context, and seamless tool calling across distributed systems.

Server-Side Setup with MapAGUI

The server-side integration centers on the MapAGUI extension method defined in dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs. This method registers a POST handler that transforms an AIAgent into an AG-UI compliant endpoint streaming Server-Sent Events (SSE).

To expose an agent via AG-UI, first register your underlying chat client and the AIAgent in the dependency injection container:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.AI;
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// Register Azure OpenAI or any IChatClient
builder.Services.AddAzureOpenAIChatClient(
    endpoint: Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!,
    deploymentName: Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME")!);

// Build the AIAgent that will handle AG-UI requests
builder.Services.AddSingleton<AIAgent>(sp =>
{
    var chatClient = sp.GetRequiredService<IChatClient>();
    return new AIAgent(chatClient);
});

After building the application, map the AG-UI route using app.MapAGUI():

var app = builder.Build();

// Map the AG-UI endpoint at any route path
app.MapAGUI("/agui", app.Services.GetRequiredService<AIAgent>());

app.Run();

Internally, the MapAGUI method constructs a ChatClientAgentRunOptions instance and populates ChatOptions.AdditionalProperties with AG-UI context keys including ag_ui_thread_id and ag_ui_run_id (lines 49‑63 in the source). The handler invokes aiAgent.RunStreamingAsync(...).AsChatResponseUpdatesAsync(), then pipes the IAsyncEnumerable<ChatResponseUpdate> through AsAGUIEventStreamAsync to serialize RunStarted, TextMessageContent, RunFinished, and error events into the SSE stream.

Client-Side Implementation Using AGUIChatClient

The consumer side relies on the AGUIChatClient class located in dotnet/src/Microsoft.Agents.AI.AGUI/AGUIChatClient.cs. This class implements IChatClient and acts as a delegating client that translates standard chat operations into AG-UI protocol HTTP requests.

Instantiate the client with a shared HttpClient instance and the server endpoint URL:

using Microsoft.Extensions.AI;
using Microsoft.Agents.AI.AGUI;

var httpClient = new HttpClient();
var aguiClient = new AGUIChatClient(
    httpClient: httpClient,
    endpoint: Environment.GetEnvironmentVariable("AGUI_SERVER_URL") ?? "http://localhost:8888");

Stream responses using the standard GetStreamingResponseAsync method. The client automatically serializes the RunAgentInput payload, manages the SSE response decoding, and yields ChatResponseUpdate objects:

var messages = new[]
{
    new ChatMessage(ChatRole.User, "Explain quantum computing basics")
};

await foreach (var update in aguiClient.GetStreamingResponseAsync(messages))
{
    foreach (var content in update.Contents)
    {
        if (content is TextContent txt)
            Console.Write(txt.Text);
    }
}

Handling Thread IDs and State Management

The AGUIChatClient manages conversation-id (thread) bookkeeping automatically through the AdditionalProperties dictionary. When you supply a ChatOptions.ConversationId on the first request, the client stores it as agui_thread_id in AdditionalProperties and clears the ConversationId before the inner client executes (lines 95‑104 in AGUIChatClient.cs). This ensures the AG-UI server receives the full conversation history on every turn while maintaining local correlation.

If no conversation ID is provided, the client generates a temporary thread identifier using thread_{Guid.NewGuid():N} via the ExtractTemporaryThreadId method. After the first response, extract the persistent thread ID from AdditionalProperties["agui_thread_id"] for subsequent turns:

// First turn without existing ID
var firstResponse = await aguiClient.GetResponseAsync(messages);
string? threadId = firstResponse.AdditionalProperties?["agui_thread_id"]?.ToString();

// Subsequent turn with preserved context
var options = new ChatOptions { ConversationId = threadId };
await foreach (var update in aguiClient.GetStreamingResponseAsync(newMessages, options))
{
    // Process streaming updates
}

Agent state is handled through DataContent with MIME type application/json. The internal ExtractAndRemoveStateFromMessages method extracts state from the final message and transmits it via the ag_ui_state property in the RunAgentInput payload.

Function Calling and Tool Support

When the AG-UI server returns tool calls, the AGUIChatClientHandler tags each FunctionCallContent instance with the agui_thread_id (lines 60‑63). This allows the outer FunctionInvokingChatClient wrapper to resolve tools locally while preserving the AG-UI conversation context across the distributed boundary. The thread ID flows back to the server on the next request, enabling stateful multi-turn tool invocations.

The protocol supports the full event lifecycle defined in dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIEventTypes.cs, including:

  • RunStarted and RunFinished for session boundaries
  • TextMessageStart, TextMessageContent, and TextMessageEnd for streaming text
  • RunError for exception handling

Serialization uses the custom AGUIMessageJsonConverter to handle polymorphic event payloads according to the AG-UI specification detailed in docs/decisions/0010-ag-ui-support.md.

Complete End-to-End Example

Server (Program.cs):

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureOpenAIChatClient(
    endpoint: "<your-endpoint>",
    deploymentName: "<your-deployment>");
builder.Services.AddSingleton<AIAgent>(sp =>
    new AIAgent(sp.GetRequiredService<IChatClient>()));
var app = builder.Build();
app.MapAGUI("/agui", app.Services.GetRequiredService<AIAgent>());
app.Run();

Client (Console Application):

var http = new HttpClient();
var client = new AGUIChatClient(http, "http://localhost:8888");

// Initial request
var first = await client.GetResponseAsync(
    new[] { new ChatMessage(ChatRole.User, "What is the weather in Seattle?") });

string? conversationId = first.AdditionalProperties?["agui_thread_id"]?.ToString();

// Follow-up with context
await foreach (var upd in client.GetStreamingResponseAsync(
    new[] { new ChatMessage(ChatRole.User, "And tomorrow?") },
    new ChatOptions { ConversationId = conversationId }))
{
    Console.Write(string.Join("", upd.Contents.OfType<TextContent>().Select(t => t.Text)));
}

Summary

  • Register server endpoints using MapAGUI in AGUIEndpointRouteBuilderExtensions.cs to expose AIAgent instances as AG-UI streaming endpoints over SSE.
  • Consume AG-UI streams with the AGUIChatClient class, which implements IChatClient and translates AG-UI events into standard ChatResponseUpdate objects.
  • Manage conversation context automatically through the agui_thread_id property in AdditionalProperties, with automatic GUID generation when no explicit thread ID is provided.
  • Support tool calling by wrapping the client in FunctionInvokingChatClient, allowing local tool resolution while maintaining remote AG-UI conversation state.
  • Handle agent state by embedding JSON data in the final message of a turn, which the client extracts and transmits via the ag_ui_state field.

Frequently Asked Questions

What is the AG-UI protocol and why use it with Agent Framework?

The AG-UI protocol is a standardized, event-based communication layer designed specifically for AI agent interfaces, supporting real-time streaming and bidirectional messaging. Using it with Agent Framework provides a consistent Server-Sent Events transport mechanism across different frontend technologies, automatic conversation threading, and built-in serialization via AGUIMessageJsonConverter without requiring custom WebSocket implementations.

How does conversation persistence work across AG-UI client calls?

The AGUIChatClient automatically extracts or generates thread identifiers and stores them in AdditionalProperties["agui_thread_id"]. On subsequent calls, if you provide the same identifier via ChatOptions.ConversationId, the client injects the full conversation history into the RunAgentInput payload while clearing the local ConversationId to satisfy AG-UI protocol requirements, ensuring the server maintains state across distributed turns.

Can AG-UI handle function calling and tool invocations?

Yes. The client-side pipeline wraps the AGUIChatClient in a FunctionInvokingChatClient that intercepts FunctionCallContent objects returned by the server. The handler tags these calls with the current agui_thread_id, executes the functions locally, and returns results to the AG-UI server, preserving the conversation context for multi-turn tool usage.

Where are the core AG-UI types defined in the repository?

The primary implementations reside in dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs for server-side endpoint mapping, dotnet/src/Microsoft.Agents.AI.AGUI/AGUIChatClient.cs for the client implementation, and dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIEventTypes.cs for the event model definitions including RunStarted, TextMessageContent, and RunFinished.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →