Skip to content

.NET: Update AGUI service to support session storage#5193

Open
westey-m wants to merge 2 commits intomicrosoft:mainfrom
westey-m:agui-sessionstore-support
Open

.NET: Update AGUI service to support session storage#5193
westey-m wants to merge 2 commits intomicrosoft:mainfrom
westey-m:agui-sessionstore-support

Conversation

@westey-m
Copy link
Copy Markdown
Contributor

@westey-m westey-m commented Apr 9, 2026

Motivation and Context

AGUI wasn't supporting session store as defined in the core hosting package.

Description

  • Updating the AGUI.AspNet package to support SessionStore from the core hosting package
  • Updating sample to show how to use it correctly with an InMemorySessionStore

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

Copilot AI review requested due to automatic review settings April 9, 2026 17:30
@moonbox3 moonbox3 added the .NET label Apr 9, 2026
@github-actions github-actions bot changed the title Update AGUI service to support session storage .NET: Update AGUI service to support session storage Apr 9, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a 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 updates the .NET AGUI ASP.NET Core hosting endpoint to integrate with the core hosting AgentSessionStore abstraction, enabling session persistence across requests (keyed by AG-UI thread ID). It also adds/updates tests and a sample to demonstrate the DI + in-memory session store setup.

Changes:

  • Add MapAGUI overloads that resolve a named agent from DI (via IHostedAgentBuilder or agentName).
  • Wrap agent execution with AIHostAgent and persist/restore sessions using a keyed AgentSessionStore (fallback to noop when not registered).
  • Add unit/integration tests and update the end-to-end sample to use WithInMemorySessionStore.

Reviewed changes

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

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs Adds DI-based MapAGUI overloads and session persistence logic using AIHostAgent + AgentSessionStore.
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.csproj Adds reference to the core hosting project to access session store abstractions.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs Adds unit tests for new overloads and session store/noop fallback behavior.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SessionPersistenceTests.cs Adds integration tests validating multi-turn session persistence via in-memory session store.
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests.csproj Adds hosting project reference needed for WithInMemorySessionStore() usage in tests.
dotnet/samples/05-end-to-end/AGUIClientServer/AGUIServer/Program.cs Updates sample to register a named agent in DI and enable in-memory session persistence.

using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

using System.Threading.Tasks; appears unused in this file and will trigger CS8019 (unnecessary using directive) in typical builds. Please remove it (and any other unused usings) to keep builds warning-free.

Suggested change
using System.Threading.Tasks;

Copilot uses AI. Check for mistakes.
this IEndpointRouteBuilder endpoints,
IHostedAgentBuilder agentBuilder,
[StringSyntax("route")] string pattern)
{
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The MapAGUI(IHostedAgentBuilder, ...) overload doesn't validate endpoints. If a caller passes null explicitly, this will throw a NullReferenceException when calling endpoints.MapAGUI(...) instead of an ArgumentNullException. Add ArgumentNullException.ThrowIfNull(endpoints); at the start for consistency with the other overloads.

Suggested change
{
{
ArgumentNullException.ThrowIfNull(endpoints);

Copilot uses AI. Check for mistakes.
ArgumentNullException.ThrowIfNull(endpoints);
ArgumentNullException.ThrowIfNull(aiAgent);

var agentSessionStore = endpoints.ServiceProvider.GetKeyedService<AgentSessionStore>(aiAgent.Name);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

aiAgent.Name is nullable. Passing a null/whitespace key into GetKeyedService<AgentSessionStore>(aiAgent.Name) can lead to surprising behavior (e.g., resolving an unkeyed store, or later failing when creating sessions). Consider guarding with string.IsNullOrWhiteSpace(aiAgent.Name) and treating that as "no store registered" (use NoopAgentSessionStore).

Suggested change
var agentSessionStore = endpoints.ServiceProvider.GetKeyedService<AgentSessionStore>(aiAgent.Name);
var agentSessionStore = string.IsNullOrWhiteSpace(aiAgent.Name)
? null
: endpoints.ServiceProvider.GetKeyedService<AgentSessionStore>(aiAgent.Name);

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +86
var agentSessionStore = endpoints.ServiceProvider.GetKeyedService<AgentSessionStore>(aiAgent.Name);
var hostAgent = new AIHostAgent(aiAgent, agentSessionStore ?? new NoopAgentSessionStore());

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

The session store (and AIHostAgent) are resolved/constructed at endpoint-mapping time via endpoints.ServiceProvider. If a user registers an AgentSessionStore with Scoped/Transient lifetime (supported by WithSessionStore(..., lifetime)), resolving it from the root provider can throw ("Cannot resolve scoped service...") or capture the wrong lifetime. Resolve the store from HttpContext.RequestServices inside the request handler (or otherwise create the AIHostAgent per request) to respect DI lifetimes.

Copilot uses AI. Check for mistakes.
Comment on lines 106 to +118
AdditionalProperties = new AdditionalPropertiesDictionary
{
["ag_ui_state"] = input.State,
["ag_ui_context"] = input.Context?.Select(c => new KeyValuePair<string, string>(c.Description, c.Value)).ToArray(),
["ag_ui_forwarded_properties"] = input.ForwardedProperties,
["ag_ui_thread_id"] = input.ThreadId,
["ag_ui_run_id"] = input.RunId
}
}
};

var threadId = input.ThreadId ?? Guid.NewGuid().ToString("N");
var session = await hostAgent.GetOrCreateSessionAsync(threadId, cancellationToken).ConfigureAwait(false);
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

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

threadId is only regenerated when input.ThreadId is null, but ThreadId can be empty/whitespace (and AIHostAgent.GetOrCreateSessionAsync will throw on whitespace). Compute threadId using string.IsNullOrWhiteSpace(input.ThreadId) and then use that computed threadId consistently, including in ChatOptions.AdditionalProperties["ag_ui_thread_id"] (currently it stores the original input.ThreadId).

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants