Repository navigation
Description
Summary
MapAGUI in Microsoft.Agents.AI.Hosting.AGUI.AspNetCore passes thread: null to AIAgent.RunStreamingAsync(), which means the agent's ChatMessageStoreFactory configuration is not properly utilized for thread persistence across requests.
Current Behavior
Looking at AGUIEndpointRouteBuilderExtensions.cs:
var events = aiAgent.RunStreamingAsync(
messages,
options: runOptions, // <-- No thread parameter passed (defaults to null)
cancellationToken: cancellationToken)When thread is null, ChatClientAgent calls GetNewThread() which creates a new ChatClientAgentThread with a new ChatMessageStore instance for every single request.
The AG-UI thread ID is passed via ChatOptions.AdditionalProperties[\"ag_ui_thread_id\"], but since no AgentThread is passed, each request:
- Creates a brand new thread
- Creates a brand new
ChatMessageStoreviaChatMessageStoreFactory - The
ChatMessageStorehas no way to correlate with the AG-UI thread ID untilAddMessagesAsyncis called (after the factory)
Expected Behavior
MapAGUI should support server-side thread persistence so that:
- If an agent has a
ChatMessageStoreFactoryconfigured, it should be used to restore/persist conversation history per AG-UI thread ID - The
ChatMessageStoreshould be created with knowledge of the AG-UI thread ID upfront - On subsequent requests with the same
ag_ui_thread_id, the same logical thread/store should be used
Workaround
Currently, developers must use ambient context (AsyncLocal) to pass the AG-UI thread ID from middleware to the ChatMessageStore, and manually manage thread storage outside of the Agent Framework's normal patterns:
// In middleware before agent runs:
CurrentThreadContext.ThreadId = ExtractThreadIdFromOptions(options);
// In ChatMessageStoreFactory:
ChatMessageStoreFactory = ctx => new CustomChatMessageStore(
threadStore,
CurrentThreadContext.ThreadId, // Read from ambient context
ctx.SerializedState
)This is fragile and requires duplicating message storage logic outside of the normal Agent Framework patterns.
Related Issues
- .NET: Sync AG-UI conversation history from backend #2510 - .NET: Sync AG-UI conversation history from backend (related but focused on MESSAGE_SNAPSHOT events)
- Python: sync AG-UI conversation history from backend #2458 - Python: sync AG-UI conversation history from backend
Environment
- Package:
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
[-]Thread persistence does not work by default in MapAGUI[/-][+].NET: Thread persistence does not work by default in MapAGUI[/+][-].NET: Thread persistence does not work by default in MapAGUI[/-][+]Python: Thread persistence does not work by default in MapAGUI[/+]javiercn commentedon Nov 28, 2025
David Parks (@DavidParks8) thanks for contacting us.
This is a current limitation. We will be working on more comprehensive support for this in the future.
DavidParks8 commentedon Nov 28, 2025
Javier Calvarro Nelson (@javiercn) How soon would that be? I'm trying to decide if I should rely on MapAGUI for a live product or if I should just roll my own.
vecode commentedon Dec 14, 2025
David Parks (@DavidParks8) Could you provide more details on how/where you are extracting the thread ID?
arjendeblok commentedon Dec 14, 2025
I also see that in
AGUIChatClientthe propertyagui_thread_idis used and inAGUIEndpointRouteBuilderExtensionsthe propertyag_ui_thread_idis used with an additional underscore. I also would like to store my thread in the agent server side.[-]Python: Thread persistence does not work by default in MapAGUI[/-][+].NET: Thread persistence does not work by default in MapAGUI[/+]tigertop commentedon Mar 15, 2026
Any news on this one? Any known workarounds possible at the moment?
javiercn commentedon Aug 18, 2026
This is resolved by the current
MapAGUIServerhosting implementation.AG-UI
threadIdis now used to load or create anAgentSession, which is passed to the agent and saved after streaming:Requests using the same AG-UI thread resume the stored session; a replacement thread starts a new session.
Persistence must be configured explicitly. Without an
AgentSessionStore, sessions are intentionally ephemeral.WithInMemorySessionStoreis appropriate for single-process development; distributed applications should register a durable store.Multi-user hosts must additionally scope session lookup by an authenticated user or tenant rather than treating
threadIdas authorization.The former
AgentThread/ChatMessageStoreFactorymodel has been replaced byAgentSession/AgentSessionStore. Since hosted AG-UI sessions now persist through the supported mechanism, this issue can be closed as resolved.