Description
When an AG-UI server owns durable conversation history through an AgentSessionStore, a client-side tool invocation causes the request user message and function call to be persisted twice.
My repo contains a focused live integration test.
The server owns cross-turn conversation history:
builder.AddAIAgent(agentName, (_, _) => agent)
.WithSessionStore((sp, agentName) =>
sp.GetKeyedService<CosmosAgentSessionStore>(agentName)!);
agentHost.MapAGUIServer(agentName, "/ag-ui");
The client sends only the current user message for each user-initiated turn. It creates a fresh local AgentSession for that turn only, retaining it only long enough for the internal client-tool loop to complete.
var session = await agent.CreateSessionAsync(cancellationToken);
await foreach (var update in agent.RunStreamingAsync(
[new ChatMessage(ChatRole.User, "Where am I?")],
session,
cancellationToken: cancellationToken))
{
// consume stream
}
The client registers a tool such as:
AIFunctionFactory.Create(
() => "51.3967°N, -1.3172°E",
name: "get_user_location")
Actual behavior
After one client-tool turn completes, the persisted server history is:
user: Where am I?
assistant: functionCall get_user_location (callId: X)
user: Where am I? <-- duplicate
assistant: functionCall get_user_location (X) <-- duplicate
tool: functionResult (X)
assistant: final text response
The duplicate user message retains the same messageId, and the duplicate function call retains the same callId. The function result is persisted only once.
The issue is visible when a conversation is reloaded from durable history: each user request appears twice, while each tool result appears once.
Expected behavior
A single client-tool turn should persist:
user: Where am I?
assistant: functionCall get_user_location (callId: X)
tool: functionResult (X)
assistant: final text response
Investigation
The focused regression test reads the raw serialized hosted session directly and fails because the user message occurs twice.
The apparent cause is that AGUIChatClient’s automatic client-tool continuation reuses its accumulated temporary local history when submitting the follow-up request. That request contains the original user message and function call alongside the tool result. The hosted AG-UI server then appends those resent messages to the durable AgentSessionStore history.
This does not appear to be caused by application-managed cross-turn continuation:
• The application only provides ThreadId and ParentRunId on later user-initiated turns.
• The duplicate occurs within one user turn and its automatic client-tool follow-up.
• No explicit messages override is supplied through RawRepresentationFactory.
• Disabling the Foundry Memory provider does not affect reproduction.
Question
What is the supported AGUIChatClient client-tool continuation pattern when MapAGUIServer owns durable transcript state via AgentSessionStore?
Specifically, should the client-tool resume request be treated as a delta by the server, or is there a supported client API for sending only the tool result rather than accumulated local messages?
Code Sample
Repo here: https://github.com/ecoDriverltd/FoundryAgentsExperiment/tree/session-store-only
Test: 'AGUIClientToolContinuationPersistsEachProtocolMessageOnce' in:
https://github.com/ecoDriverltd/FoundryAgentsExperiment/blob/session-store-only/FoundryAgentsExperiment.IntegrationTests/AgentChatTests.cs
Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.18.0-preview.260818.1, AGUI.Client 1.18.0-preview.260818.1
.NET Version
.NET 10
Additional Context
No response
Description
When an AG-UI server owns durable conversation history through an AgentSessionStore, a client-side tool invocation causes the request user message and function call to be persisted twice.
My repo contains a focused live integration test.
The server owns cross-turn conversation history:
The client sends only the current user message for each user-initiated turn. It creates a fresh local AgentSession for that turn only, retaining it only long enough for the internal client-tool loop to complete.
The client registers a tool such as:
Actual behavior
After one client-tool turn completes, the persisted server history is:
The duplicate user message retains the same messageId, and the duplicate function call retains the same callId. The function result is persisted only once.
The issue is visible when a conversation is reloaded from durable history: each user request appears twice, while each tool result appears once.
Expected behavior
A single client-tool turn should persist:
Investigation
The focused regression test reads the raw serialized hosted session directly and fails because the user message occurs twice.
The apparent cause is that AGUIChatClient’s automatic client-tool continuation reuses its accumulated temporary local history when submitting the follow-up request. That request contains the original user message and function call alongside the tool result. The hosted AG-UI server then appends those resent messages to the durable AgentSessionStore history.
This does not appear to be caused by application-managed cross-turn continuation:
• The application only provides ThreadId and ParentRunId on later user-initiated turns.
• The duplicate occurs within one user turn and its automatic client-tool follow-up.
• No explicit messages override is supplied through RawRepresentationFactory.
• Disabling the Foundry Memory provider does not affect reproduction.
Question
What is the supported AGUIChatClient client-tool continuation pattern when MapAGUIServer owns durable transcript state via AgentSessionStore?
Specifically, should the client-tool resume request be treated as a delta by the server, or is there a supported client API for sending only the tool result rather than accumulated local messages?
Code Sample
Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.18.0-preview.260818.1, AGUI.Client 1.18.0-preview.260818.1
.NET Version
.NET 10
Additional Context
No response