Microsoft Agent Framework .NET: persisting AG-UI threads (from MapAGUI to MapAGUIServer and AgentSessionStore) Mohammed, founder of MemorySync, documented how Microsoft Agent Framework .NET's MapAGUIServer hosting resolves GitHub issue #2517 by loading or creating an AgentSession from the AG-UI threadId and saving it after streaming, replacing the old AgentThread/ChatMessageStoreFactory model with AgentSession/AgentSessionStore. He showed that persistence is opt-in: without an AgentSessionStore each request gets a fresh session, while WithInMemorySessionStore(withIsolation: false) preserves prior messages across turns. He also flagged that calling WithInMemorySessionStore() with no arguments enables isolation and returns a 500 error when no isolation key is provided. Disclosure: I'm Mohammed, founder of MemorySync. I drafted this article with AI assistance and reviewed it for accuracy against the official Microsoft Agent Framework docs. The code was built and run locally against the 1.26.0-preview packages with a stub chat client no real model call . If your AG-UI front end talks to an Agent Framework .NET server and the agent forgets the previous message on every turn, you've hit microsoft/agent-framework 2517 https://github.com/microsoft/agent-framework/issues/2517 , ".NET: Thread persistence does not work by default in MapAGUI". MapAGUI called the agent without a thread, so every request got a new thread and a new ChatMessageStore , even when the AG-UI threadId was the same. The only workaround was to carry the thread ID through AsyncLocal into a custom store. The issue was closed on Aug 18, 2026. In the closing comment, a maintainer said it's resolved by the current MapAGUIServer hosting: the AG-UI threadId loads or creates an AgentSession , which is passed to the agent and saved after streaming. The old AgentThread / ChatMessageStoreFactory model was replaced by AgentSession / AgentSessionStore . Below is that setup step by step, with the two things that tripped me up when I ran it. Framework behaviour comes from Microsoft's AG-UI getting started https://learn.microsoft.com/en-us/agent-framework/integrations/by-component/ui/ag-ui/getting-started and self-hosting https://learn.microsoft.com/en-us/agent-framework/hosting/self-hosting/ docs, plus the package API. I built and ran the code with Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.26.0-preview.261023.1 on .NET 10, using a stub IChatClient instead of a real model. dotnet add package Microsoft.Agents.AI.Hosting.AGUI.AspNetCore --prerelease dotnet add package Microsoft.Agents.AI.Hosting.AspNetCore --prerelease only needed for claims-based isolation Step 4 MapAGUI no longer exists in the current package the build fails with CS1061 . The method is MapAGUIServer . Persistence is opt-in. Without an AgentSessionStore , every request still gets a new session, which is the behaviour from the issue. Register the agent through hosting DI, attach a store, and map it by name: using Microsoft.Agents.AI; using Microsoft.Agents.AI.Hosting; using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore; using Microsoft.Extensions.AI; WebApplicationBuilder builder = WebApplication.CreateBuilder args ; builder.Services.AddAGUIServer ; IChatClient chatClient = CreateChatClient ; // your Azure OpenAI, OpenAI or other IChatClient AIAgent agent = chatClient.AsAIAgent new ChatClientAgentOptions { Id = "assistant", // keep it stable see Step 5 Name = "assistant", ChatOptions = new ChatOptions { Instructions = "You are a helpful assistant." }, } ; builder.AddAIAgent "assistant", , = agent .WithInMemorySessionStore withIsolation: false ; // local development, one trusted user only WebApplication app = builder.Build ; app.MapAGUIServer "assistant", "/ag-ui" ; await app.RunAsync ; The client sends only the new message on each turn, with the same threadId and the previous runId as parentRunId . With my stub model, two requests on thread-1 behaved like this: | Setup | Turn 2 "What is my name?" saw | |---|---| | No session store | only the new message | | WithInMemorySessionStore withIsolation: false | both messages | WithInMemorySessionStore into an app without isolation The issue's closing comment shows .WithInMemorySessionStore with no arguments. With the current package that turns on isolation, and if nothing provides an isolation key, every request fails with a 500: System.InvalidOperationException: Agent isolation key is required but was not provided by the configured AgentIsolationKeyProvider. That's by design. The AG-UI threadId comes from the client, and the docs are explicit that it's a correlation ID, not authorization: anyone who guesses another user's threadId could resume their conversation. So either pass withIsolation: false for single-user local development, or configure isolation as in Step 4. The self-hosting docs register a claims-based isolation provider from Microsoft.Agents.AI.Hosting.AspNetCore . By default it uses the ClaimTypes.NameIdentifier claim: builder.Services.AddAuthentication / your scheme / ; builder.Services.AddAuthorization ; builder.Services.AddHttpContextAccessor ; // the provider reads the current user from HttpContext builder.Services.UseClaimsBasedAgentIsolation ; builder.AddAIAgent "assistant", , = agent .WithInMemorySessionStore ; // isolation stays on WebApplication app = builder.Build ; app.UseAuthentication ; app.UseAuthorization ; app.MapAGUIServer "assistant", "/ag-ui" .RequireAuthorization ; Two notes from running it. Without AddHttpContextAccessor the request failed with "No service for type 'IHttpContextAccessor' has been registered." that line is my addition, not in the docs . With it, and a test user signed in, the same threadId gave each user a separate conversation, and a request with no user returned 500. The provider doesn't authenticate anyone, so you still need real ASP.NET Core authentication. The GitHub sample's comment mentions UseClaimsBasedSessionIsolation . In 1.26.0-preview the method is UseClaimsBasedAgentIsolation , which matches the Learn docs. InMemoryAgentSessionStore loses everything when the process exits, and the docs say the framework doesn't ship a general-purpose durable store. You implement AgentSessionStore yourself. Here's a minimal file-backed one, using the agent's own session serialization as the docs recommend: pragma warning disable MAAI001 // AgentSessionStore is marked evaluation-only in the preview packages using System.Security.Cryptography; using System.Text; using System.Text.Json; using Microsoft.Agents.AI; sealed class FileAgentSessionStore string dir : AgentSessionStore { string PathFor AIAgent agent, AgentSessionStoreKey key { string partitions = string.Join ",", key.Partitions ?? new Dictionary