Skip to content

.NET: Replace MAF AG-UI abstractions with the AG-UI C# SDK abstractions#6653

Draft
javiercn wants to merge 1 commit into
microsoft:mainfrom
javiercn:agui-external-packages
Draft

.NET: Replace MAF AG-UI abstractions with the AG-UI C# SDK abstractions#6653
javiercn wants to merge 1 commit into
microsoft:mainfrom
javiercn:agui-external-packages

Conversation

@javiercn

Copy link
Copy Markdown
Contributor

Important

Draft. This PR consumes the external AG-UI .NET SDK packages (AGUI.*) at 0.1.0-preview, which are not yet published to NuGet.org (they ship from the AG-UI repo — see ag-ui-protocol/ag-ui#1963). CI restore will fail until those packages are public. It is opened as a draft to review the migration shape ahead of that publish.

Summary

Replaces Microsoft Agent Framework's in-tree AG-UI abstractions (Microsoft.Agents.AI.AGUI) with the external AG-UI C# SDK packages, so MAF consumes the protocol implementation maintained by the AG-UI team instead of carrying its own parallel copy.

The framework keeps its own thin ASP.NET hosting glue; only the protocol abstractions move out.

Net change: 91 files, +360 / −10,218 — almost entirely deletions of the vendored protocol code and its tests.

What changes

Removed (the vendored AG-UI implementation):

  • src/Microsoft.Agents.AI.AGUI/ — the internal AGUIChatClient, event/message types, JSON converters, AGUIJsonSerializerContext, role/tool/event constants, and the ChatResponseUpdate ↔ AG-UI extensions.
  • tests/Microsoft.Agents.AI.AGUI.UnitTests/ — the unit tests for that vendored copy (now covered upstream in the AG-UI SDK's own test suites).

Added package references (Directory.Packages.props, restored from NuGet):

  • AGUI.Abstractions, AGUI.Formatting, AGUI.Protobuf, AGUI.Client, AGUI.Server — all 0.1.0-preview.

Kept and re-pointed at the external primitives:

  • Microsoft.Agents.AI.Hosting.AGUI.AspNetCore retains its own ASP.NET surface (MapAGUI / AddAGUI / the SSE result) but now layers it over the framework-agnostic AGUI.Server primitives — RunAgentInput.ToChatRequestContext(...) and ChatResponseUpdateAGUIExtensions.AsAGUIEventStreamAsync(...).
  • The samples under samples/02-agents/AGUI/* and samples/05-end-to-end/AGUI* and the hosting integration/unit tests are migrated to the external API.

Why

  • Single source of truth. The AG-UI protocol (events, messages, tools, interrupts, state, multimodal, SSE + protobuf transports) is maintained once, in the AG-UI C# SDK, and stays wire-compatible with the TypeScript/Python SDKs. MAF no longer has to track protocol changes in a second implementation.
  • Less surface to own. ~10k lines of protocol code and tests leave the framework; MAF keeps only the ASP.NET hosting integration that is genuinely framework-specific.
  • Same model. The SDK is built on Microsoft.Extensions.AIIChatClient remains the only integration point on both the client and server sides, so the programming model is unchanged.

Migration guide (for existing consumers of Microsoft.Agents.AI.AGUI)

The hosting package (Microsoft.Agents.AI.Hosting.AGUI.AspNetCore) and its MapAGUI/AddAGUI surface are unchanged. If you used the abstractions directly, three things change:

1. Namespaces — the single Microsoft.Agents.AI.AGUI namespace splits along the SDK's package boundaries:

Was Now
Microsoft.Agents.AI.AGUI (client) AGUI.Client
Microsoft.Agents.AI.AGUI (server adapters) AGUI.Server
Microsoft.Agents.AI.AGUI (events/messages/tools) AGUI.Abstractions

2. AGUIChatClient construction — the positional constructor becomes options-based:

// Before
using Microsoft.Agents.AI.AGUI;
var chatClient = new AGUIChatClient(
    httpClient,
    serverUrl,
    jsonSerializerOptions: AGUIClientSerializerContext.Default.Options);

// After
using AGUI.Client;
var chatClient = new AGUIChatClient(new(httpClient, serverUrl)
{
    JsonSerializerOptions = AGUIClientSerializerContext.Default.Options,
});

3. Recovering the originating AG-UI input on the server — read it back from ChatOptions via the SDK extension:

using AGUI.Abstractions;
using AGUI.Server;

if (!chatOptions.TryGetRunAgentInput(out RunAgentInput? agentInput))
{
    // not an AG-UI-originated request
}

4. Package references — drop the project/package reference to Microsoft.Agents.AI.AGUI and add the AGUI.* packages you use (AGUI.Client for clients, AGUI.Server + AGUI.Abstractions for server/hosting, plus AGUI.Protobuf if you opt into the protobuf transport).

Notes for reviewers

  • The endpoint shape is unchanged: MapPostinput.ToChatRequestContext(...)chatClient.GetStreamingResponseAsync(...).AsAGUIEventStreamAsync(ctx, ct) → negotiated SSE/protobuf result.
  • No change to the public Microsoft.Agents.AI.Hosting.AGUI.AspNetCore API.
  • Blocked on the AGUI.* packages being published; until then this is a draft and CI restore will fail at the package source.

Copilot AI review requested due to automatic review settings June 21, 2026 17:44
@moonbox3 moonbox3 added documentation Improvements or additions to documentation .NET Issues related to the .NET codebase labels Jun 21, 2026
@github-actions github-actions Bot changed the title Replace MAF AG-UI abstractions with the AG-UI C# SDK abstractions .NET: Replace MAF AG-UI abstractions with the AG-UI C# SDK abstractions Jun 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the .NET AG-UI integration from Microsoft Agent Framework’s in-tree Microsoft.Agents.AI.AGUI protocol implementation to the external AGUI.* C# SDK packages, keeping only the ASP.NET Core hosting glue in-tree while updating tests and samples accordingly.

Changes:

  • Added central package versions and project PackageReferences for AGUI.Abstractions/Client/Server/... and removed the Microsoft.Agents.AI.AGUI project from solutions/samples/tests.
  • Re-pointed Microsoft.Agents.AI.Hosting.AGUI.AspNetCore endpoint mapping to use RunAgentInput.ToChatRequestContext(...) + ChatResponseUpdateAGUIExtensions.AsAGUIEventStreamAsync(...), with net10 using TypedResults.ServerSentEvents.
  • Updated integration tests and samples to use the new AGUI.Client construction pattern and revised state/tool-call expectations consistent with the external SDK.

Reviewed changes

Copilot reviewed 91 out of 91 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/TestHelpers.cs Gates async-enumerable helper behind !NET10_0_OR_GREATER to match test applicability.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj Adds AGUI.Abstractions package reference for updated unit tests.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ChatResponseUpdateAGUIExtensionsTests.cs Removes tests for the vendored ChatResponseUpdate↔AG-UI conversion now owned by the external SDK.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIServerSentEventsResultTests.cs Updates SSE polyfill tests to reference AGUI.Abstractions event types; gated to non-net10.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs Simplifies unit tests to focus on DI mapping/null-guard behavior after protocol logic moves out-of-tree.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ToolCallingTests.cs Migrates to AGUI.Client and updates mixed server/client tool execution expectations.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SharedStateTests.cs Updates state round-trip tests to use RunAgentInput.State + StateSnapshotEvent raw representations.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SessionPersistenceTests.cs Updates continuation semantics to stateless client behavior using threadId + parentRunId.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests.csproj Replaces internal AGUI project reference with AGUI.Client/Abstractions/Server packages.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ForwardedPropertiesTests.cs Switches forwarded-props recovery to TryGetRunAgentInput(...) from the external SDK.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/BasicStreamingTests.cs Adjusts lifecycle assertions to read thread/run IDs from AG-UI events instead of ConversationId.
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/TestHelpers.cs Removes helper from deleted vendored AGUI test project.
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/Microsoft.Agents.AI.AGUI.UnitTests.csproj Deletes vendored AGUI unit test project file.
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AIToolExtensionsTests.cs Removes tests for vendored tool conversion extensions now replaced by external SDK APIs.
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AGUIStreamingMessageIdTests.cs Removes vendored streaming/message-id behavior tests now owned upstream.
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AGUIHttpServiceTests.cs Removes tests for vendored HTTP/SSE client now replaced by AGUI.Client.
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.csproj Drops linked vendored Shared/** compile items; adds AGUI.Abstractions + AGUI.Server package refs.
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIServerSentEventsResult.cs Updates SSE polyfill to use AGUI.Abstractions events and limits it to pre-net10 TFMs.
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIJsonSerializerOptions.cs Seeds JSON options from AGUIJsonSerializerContext and adds AF resolver for hosting serialization.
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs Replaces in-tree parsing/stream conversion with AGUI.Server context + event stream extensions; net10 uses framework SSE result.
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIChatResponseUpdateStreamExtensions.cs Removes custom tool-filtering stream extension (superseded by external SDK behavior/config).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ToolCallStartEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ToolCallResultEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ToolCallEndEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ToolCallArgsEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/TextMessageStartEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/TextMessageEndEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/TextMessageContentEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/StateSnapshotEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/StateDeltaEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/RunStartedEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/RunFinishedEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/RunErrorEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/RunAgentInput.cs Removes vendored protocol input model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningStartEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningMessageStartEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningMessageEndEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningMessageContentEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningMessageChunkEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningEndEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ReasoningEncryptedValueEvent.cs Removes vendored protocol type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ChatResponseUpdateAGUIExtensions.cs Removes vendored conversion pipeline (now provided by the external AG-UI SDK).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/BaseEventJsonConverter.cs Removes vendored event converter (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/BaseEvent.cs Removes vendored base event type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AIToolExtensions.cs Removes vendored tool conversion extensions (replaced by external SDK APIs).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIUserMessage.cs Removes vendored message model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIToolMessage.cs Removes vendored message model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIToolCall.cs Removes vendored tool-call model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUITool.cs Removes vendored tool model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUISystemMessage.cs Removes vendored message model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIRoles.cs Removes vendored role constants (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIReasoningMessage.cs Removes vendored message model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIMessageJsonConverter.cs Removes vendored message converter (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIMessage.cs Removes vendored message base type (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIJsonSerializerContext.cs Removes vendored source-gen context (superseded by external SDK contexts).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIFunctionCall.cs Removes vendored function-call model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIEventTypes.cs Removes vendored event-type constants (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIDeveloperMessage.cs Removes vendored message model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIContextItem.cs Removes vendored context model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIChatMessageExtensions.cs Removes vendored chat-message mapping logic (replaced by external SDK server/client adapters).
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/AGUIAssistantMessage.cs Removes vendored message model (migrated to AGUI.Abstractions).
dotnet/src/Microsoft.Agents.AI.AGUI/Microsoft.Agents.AI.AGUI.csproj Deletes the vendored AGUI project.
dotnet/src/Microsoft.Agents.AI.AGUI/AGUIHttpService.cs Deletes vendored HTTP/SSE transport client (replaced by AGUI.Client).
dotnet/src/Microsoft.Agents.AI.AGUI/AGUIChatClient.cs Deletes vendored AGUIChatClient implementation (replaced by AGUI.Client).
dotnet/samples/05-end-to-end/AGUIWebChat/Server/AGUIWebChatServer.csproj Removes internal AGUI project reference from the sample server.
dotnet/samples/05-end-to-end/AGUIWebChat/README.md Updates sample docs to use the new AGUI.Client options-based constructor.
dotnet/samples/05-end-to-end/AGUIWebChat/Client/Program.cs Migrates sample client to AGUI.Client.
dotnet/samples/05-end-to-end/AGUIWebChat/Client/AGUIWebChatClient.csproj Switches sample client to AGUI.Client package reference.
dotnet/samples/05-end-to-end/AGUIClientServer/README.md Updates sample docs to the new AGUIChatClient construction pattern.
dotnet/samples/05-end-to-end/AGUIClientServer/AGUIServer/AGUIServer.csproj Removes internal AGUI project reference from sample server.
dotnet/samples/05-end-to-end/AGUIClientServer/AGUIDojoServer/SharedState/SharedStateAgent.cs Updates state extraction to use TryGetRunAgentInput(...) from the external SDK.
dotnet/samples/05-end-to-end/AGUIClientServer/AGUIClient/Program.cs Migrates sample client to AGUI.Client + options-based construction.
dotnet/samples/05-end-to-end/AGUIClientServer/AGUIClient/AGUIClient.csproj Switches sample client to AGUI.Client package reference.
dotnet/samples/02-agents/AGUI/Step05_StateManagement/Server/SharedStateAgent.cs Updates state recovery from ChatOptions to TryGetRunAgentInput(...).
dotnet/samples/02-agents/AGUI/Step05_StateManagement/Client/Program.cs Migrates tutorial client to AGUI.Client options-based construction.
dotnet/samples/02-agents/AGUI/Step05_StateManagement/Client/Client.csproj Replaces internal project reference with AGUI.Client package.
dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs Migrates tutorial client to AGUI.Client.
dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Client.csproj Replaces internal project reference with AGUI.Client package.
dotnet/samples/02-agents/AGUI/Step03_FrontendTools/Client/Program.cs Migrates tutorial client to AGUI.Client.
dotnet/samples/02-agents/AGUI/Step03_FrontendTools/Client/Client.csproj Replaces internal project reference with AGUI.Client package.
dotnet/samples/02-agents/AGUI/Step02_BackendTools/Client/Program.cs Migrates tutorial client to AGUI.Client.
dotnet/samples/02-agents/AGUI/Step02_BackendTools/Client/Client.csproj Replaces internal project reference with AGUI.Client package.
dotnet/samples/02-agents/AGUI/Step01_GettingStarted/Client/Program.cs Migrates tutorial client to AGUI.Client.
dotnet/samples/02-agents/AGUI/Step01_GettingStarted/Client/Client.csproj Replaces internal project reference with AGUI.Client package.
dotnet/Directory.Packages.props Adds AGUI.* package versions and updates a few dependency versions.
dotnet/agent-framework-release.slnf Removes the deleted Microsoft.Agents.AI.AGUI project from the release solution filter.
dotnet/agent-framework-dotnet.slnx Removes the deleted Microsoft.Agents.AI.AGUI project and its unit tests from the solution.

this._jsonWriter.Reset(writer);
}

JsonSerializer.Serialize(this._jsonWriter, item.Data, AGUIJsonSerializerContext.Default.BaseEvent);
Comment on lines 61 to 65
var errorEvent = new RunErrorEvent
{
Code = "StreamingError",
Message = ex.Message
Message = ex.Message,
};
Comment on lines 118 to 121
if (input is null)
{
return Results.BadRequest();
}

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 5 | Confidence: 77%

✓ Correctness

No actionable issues found in this dimension.

✓ Security Reliability

No actionable issues found in this dimension.

✓ Test Coverage

The existing integration tests (ToolCallingTests, BasicStreamingTests, SharedStateTests, etc.) continue to exercise the hosting pipeline end-to-end, including the mixed server+client tool invocation scenario. The new AGUIStreamOptions resolution path (endpoint metadata → DI fallback) introduced in the endpoint handler has no direct test coverage, but this is a straightforward null-coalescing passthrough to the external SDK and is exercised implicitly (with null options) by all existing integration tests.

✓ Failure Modes

The migration from vendored AG-UI code to the external SDK is structurally sound. The main failure mode concern is that on .NET 10+, streaming errors silently drop the connection without sending a RunErrorEvent to the client, unlike the polyfill path which gracefully notifies clients of failures. This leaves clients unable to distinguish between a network drop and an application error.

✗ Design Approach

The chunk mostly updates tests to the external AG-UI SDK, but two of those changes bless lower-level behavior that conflicts with the repo’s documented/public client contract. One test now codifies ConversationId being absent even though the sample client and README still describe thread identity as coming from ConversationId, and another now hand-builds RunAgentInput for turn continuation, which stops exercising the public ChatClientAgentSession path that callers actually use. The migration mostly updates the tests to the external SDK shape, but one changed test now codifies a real behavioral regression: state snapshots emitted by AG-UI are lost on the non-streaming AIAgent.RunAsync path, which changes the client programming model instead of just swapping protocol abstractions. I also found one non-blocking test-design issue where a serializer-options test no longer exercises the AGUIChatClient behavior it claims to cover.

Flagged Issues

  • BasicStreamingTests now treats a null ConversationId as expected, which codifies a backward-incompatible client contract change even though the sample client and README still document thread identity via ConversationId (dotnet/samples/05-end-to-end/AGUIClientServer/README.md:157,182,194,198 and dotnet/samples/05-end-to-end/AGUIClientServer/AGUIClient/Program.cs:122-131,177-180).
  • SessionPersistenceTests now injects ThreadId/ParentRunId/Messages through RawRepresentationFactory, so it can pass even if AGUIChatClient no longer preserves continuation state through ChatClientAgentSession; that bypasses the public pattern used by calers (dotnet/samples/05-end-to-end/AGUIClientServer/AGUIClient/Program.cs:91,117).

Automated review by javiercn's agents

@github-actions

Copy link
Copy Markdown
Contributor

Flagged issue

BasicStreamingTests now treats a null ConversationId as expected, which codifies a backward-incompatible client contract change even though the sample client and README still document thread identity via ConversationId (dotnet/samples/05-end-to-end/AGUIClientServer/README.md:157,182,194,198 and dotnet/samples/05-end-to-end/AGUIClientServer/AGUIClient/Program.cs:122-131,177-180).


Source: automated DevFlow PR review

@github-actions

Copy link
Copy Markdown
Contributor

Flagged issue

SessionPersistenceTests now injects ThreadId/ParentRunId/Messages through RawRepresentationFactory, so it can pass even if AGUIChatClient no longer preserves continuation state through ChatClientAgentSession; that bypasses the public pattern used by calers (dotnet/samples/05-end-to-end/AGUIClientServer/AGUIClient/Program.cs:91,117).


Source: automated DevFlow PR review

@javiercn javiercn force-pushed the agui-external-packages branch from de00533 to e43bcf4 Compare June 21, 2026 18:05
@javiercn javiercn force-pushed the agui-external-packages branch from e43bcf4 to 213dcef Compare June 21, 2026 18:25
@javiercn

Copy link
Copy Markdown
Contributor Author

Review comment dispositions

Thanks for the thorough automated review. Triaged below, with fixes pushed in the latest revision.

AGUIServerSentEventsResult.cs — flush Utf8JsonWriter after serialization

Dismissed (no change). JsonSerializer.Serialize(Utf8JsonWriter, value, JsonTypeInfo) flushes the writer at the end of the call, so the bytes are committed to the IBufferWriter before SseFormatter frames them — no manual Flush() is needed and small payloads are not truncated. This path is also unchanged by the migration and is covered by AGUIServerSentEventsResultTests.

AGUIServerSentEventsResult.csex.Message forwarded to the client

Fixed. The error event now sends a generic client-facing message ("An error occurred while streaming the agent response."); the full exception is still recorded server-side via LogStreamingError. (Polyfill-only path, #if !NET10_0_OR_GREATER.)

AGUIEndpointRouteBuilderExtensions.cs — invalid/empty body 400 path untested

Dismissed (no change). The [FromBody] RunAgentInput? binding + null → 400 behavior is ASP.NET Core minimal-API model binding, not logic owned by this glue, so a test here would be asserting framework behavior. The endpoint's own logic (context conversion, session resolution, streaming) is covered by the integration suite.

Design Approach — ConversationId absence and RawRepresentationFactory continuation

These reflect an intentional AG-UI SDK design, not a regression (#4869):

  • AGUIChatClient is stateless and deliberately never surfaces a ConversationId. In M.E.AI semantics a returned ConversationId means "the service is storing this conversation; send only deltas next turn" — but the AG-UI server is stateless, so advertising one would truncate history. This mirrors the reference TypeScript client, which owns a stable client-side thread id, always sends full history, and never adopts a thread id from the response. So BasicStreamingTests asserting ConversationId == null is codifying the correct contract.
  • Thread/run identity is carried on the wire events' raw representation (RunStartedEvent.ThreadId / RunFinishedEvent.ThreadId, run id via ResponseId), and continuation/branching sets RunAgentInput.ThreadId/ParentRunId through ChatOptions.RawRepresentationFactory — the AG-UI-native way to set wire-level fields. That is the public, intended pattern (not a bypass), so SessionPersistenceTests is exercising the real continuation path callers use.

Docs/samples updated to match (the contract mismatch the review correctly flagged): the surviving AG-UI samples and READMEs no longer present ConversationId as thread identity — they read the thread id from the RUN_STARTED raw representation and document the stateless model:

  • samples/02-agents/AGUI/Step01/Step02/Step03/Step05/Client/Program.cs and samples/02-agents/AGUI/README.md
  • samples/05-end-to-end/AGUIClientServer/AGUIClient/Program.cs and its README.md
  • AGUIWebChat's Blazor client is left as-is: it already uses the idiomatic M.E.AI stateless/stateful pattern (statefulMessageCount = ConversationId is not null ? … : 0), which naturally sends full history against the always-null AG-UI client.

The non-blocking note about the serializer-options test is acknowledged; it can be tightened in a follow-up since it doesn't affect the migration's correctness.

@javiercn

Copy link
Copy Markdown
Contributor Author

Follow-up: renamed the public hosting API + slimmed the JSON wiring

To avoid squatting on AddAGUI / MapAGUI — names the AG-UI .NET SDK should be free to use itself in the future — and to match the in-repo A2A convention (AddA2AServer, MapA2A*), the two public methods are renamed:

Before After
services.AddAGUI() services.AddAGUIServer()
endpoints.MapAGUI(...) endpoints.MapAGUIServer(...)

The package's entire public surface is now exactly these two methods. Supporting changes:

  • Deleted the AGUIJsonSerializerOptions static holder. The JSON type-info resolvers are now registered inside AddAGUIServer via an internal IConfigureOptions<JsonOptions> (ConfigureAGUIJsonOptions), wired with TryAddEnumerable (the idiomatic, idempotent options pattern). Resolver order is preserved (AG-UI wire context first, then Agent Framework abstractions).
  • Renamed the extension class to AGUIServerServiceCollectionExtensions (and its file) to match the A2A naming.
  • Updated all call sites: the AG-UI sample servers, the 02-agents/AGUI + AGUIClientServer + AGUIWebChat READMEs, and the hosting unit/integration tests.

Validated: hosting builds clean (net8/9/10); unit tests 9/9 and integration tests 32/32 pass (the integration suite exercises AddAGUIServer + MapAGUIServer + the new IConfigureOptions JSON path end-to-end).

Remove the in-tree Microsoft.Agents.AI.AGUI sources and consume the external
AG-UI .NET SDK packages (AGUI.Abstractions, AGUI.Formatting, AGUI.Protobuf,
AGUI.Client, AGUI.Server) at 0.1.0-preview instead.

- Microsoft.Agents.AI.Hosting.AGUI.AspNetCore keeps its own ASP.NET glue
  (MapAGUI / AddAGUI / SSE result) layered over the framework-agnostic
  AGUI.Server primitives (ToChatRequestContext / AsAGUIEventStreamAsync).
- Migrate call sites to the options-based AGUIChatClient constructor and recover
  the originating AG-UI input via ChatOptions.TryGetRunAgentInput.
- Multi-turn continuation flows through parentRunId + threadId on
  RawRepresentationFactory; shared state flows through RunAgentInput.State and is
  surfaced as StateSnapshotEvent raw representations.
- Update samples, hosting/unit/integration tests, and central package versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation .NET Issues related to the .NET codebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants