Description
When using AG-UI with Microsoft Agent Framework and a persisted chat history provider such as Cosmos DB, frontend-only tools can make a conversation unreplayable after the first tool interaction.
The frontend sends available tools to the backend on each request. In this flow, the agent may emit a functionCall for a tool that is meant to be rendered by the frontend, such as a map tool. However, the frontend tool does not naturally produce functionResult , because the result is not generated by the server. The UI simply renders the tool action.
It is not obvious that the frontend must always send a matching functionResult back to the backend. Even if the frontend attempts to do so, there is no guarantee that the result will reach the backend reliably because of network interruption, page refresh, tab closure, or other client-side failures.
As a result, the persisted conversation history can contain a functionCall without a matching functionResult . On the next request, when the backend reloads the conversation from Cosmos DB, AI behind Agent Framework rejects to process the conversation history because it is incomplete.
Expected behavior
Frontend-only AG-UI tools should not make persisted chat history invalid or unreplayable.
A conversation should remain resumable after refresh or reconnect, even if the frontend-rendered tool result was never sent back to the backend.
Actual behavior
When a frontend tool is used, the agent stores a functionCall in the conversation history. Since the frontend does not send a matching functionResult , the persisted history becomes inconsistent. On the next request, the backend reloads invalid history and the conversation can no longer continue.
Why this is a problem
This design assumes the frontend can always send a matching functionResult , but that is not a safe assumption.
Frontend-only tool execution is inherently unreliable from a transport perspective. The result may never make it back to the server due to:
• network failure.
• page refresh.
• browser tab closure.
• client crashes.
• other transient frontend issues.
Because of this, persisting a functionCall that depends on a frontend-returned functionResult makes the conversation fragile and difficult to resume.
Reproduction steps
- Create a .NET app using Microsoft Agent Framework with AG-UI enabled.
- Configure a persisted chat history provider such as Cosmos DB.
- Expose a frontend-only tool such as render_map .
- Send a user message that causes the agent to call that tool.
- Let the frontend render the tool output without sending a backend functionResult .
- Refresh the page or send another message in the same thread.
- Observe that the conversation history can no longer be replayed correctly.
Notes
AG-UI frontend tools are not the same as backend-executed tools. The backend should not assume a frontend-rendered tool will always return a durable functionResult .
Code Sample
Backend
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.CosmosNoSql;
using Microsoft.Agents.AI.OpenAI;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAGUI();
var app = builder.Build();
var openAiClient = new AzureOpenAIClient(
new Uri(builder.Configuration["AZURE_OPENAI_ENDPOINT"]!),
new DefaultAzureCredential());
var chatClient = openAiClient.GetChatClient(builder.Configuration["AZURE_OPENAI_DEPLOYMENT"]!);
var cosmosProvider = new CosmosChatHistoryProvider(
endpoint: builder.Configuration["COSMOS_ENDPOINT"]!,
databaseName: builder.Configuration["COSMOS_DATABASE"]!,
containerName: builder.Configuration["COSMOS_CONTAINER"]!,
credential: new DefaultAzureCredential());
var agent = chatClient.CreateAIAgent(new ChatClientAgentOptions
{
Name = "agui-repro",
Instructions = """
You are a helpful assistant.
If the user asks to show a location on a map, use the render_map tool.
""",
ChatHistoryProvider = cosmosProvider
});
app.MapAGUI("/agent", agent);
await app.RunAsync();
Frontend
const renderMapTool = {
name: "render_map",
description: "Render markers on a map in the UI",
parameters: {
type: "object",
properties: {
latitude: { type: "number" },
longitude: { type: "number" },
label: { type: "string" }
},
required: ["latitude", "longitude", "label"]
}
};
await fetch("/agent", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
threadId: "demo-thread-1",
messages: [
{ role: "user", content: "Show Tokyo on a map" }
],
tools: [renderMapTool]
})
});
Error Messages / Stack Traces
HTTP 400 (invalid, request_ error. ) Parameter: input No tool output found for function call call WglIXOb6N37wXIYy/MO7UyyP.
Package Versions
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.9.0-preview.260603.1
.NET Version
.NET 10
Additional Context
No response
Description
When using AG-UI with Microsoft Agent Framework and a persisted chat history provider such as Cosmos DB, frontend-only tools can make a conversation unreplayable after the first tool interaction.
The frontend sends available tools to the backend on each request. In this flow, the agent may emit a functionCall for a tool that is meant to be rendered by the frontend, such as a map tool. However, the frontend tool does not naturally produce functionResult , because the result is not generated by the server. The UI simply renders the tool action.
It is not obvious that the frontend must always send a matching functionResult back to the backend. Even if the frontend attempts to do so, there is no guarantee that the result will reach the backend reliably because of network interruption, page refresh, tab closure, or other client-side failures.
As a result, the persisted conversation history can contain a functionCall without a matching functionResult . On the next request, when the backend reloads the conversation from Cosmos DB, AI behind Agent Framework rejects to process the conversation history because it is incomplete.
Expected behavior
Frontend-only AG-UI tools should not make persisted chat history invalid or unreplayable.
A conversation should remain resumable after refresh or reconnect, even if the frontend-rendered tool result was never sent back to the backend.
Actual behavior
When a frontend tool is used, the agent stores a functionCall in the conversation history. Since the frontend does not send a matching functionResult , the persisted history becomes inconsistent. On the next request, the backend reloads invalid history and the conversation can no longer continue.
Why this is a problem
This design assumes the frontend can always send a matching functionResult , but that is not a safe assumption.
Frontend-only tool execution is inherently unreliable from a transport perspective. The result may never make it back to the server due to:
• network failure.
• page refresh.
• browser tab closure.
• client crashes.
• other transient frontend issues.
Because of this, persisting a functionCall that depends on a frontend-returned functionResult makes the conversation fragile and difficult to resume.
Reproduction steps
Notes
AG-UI frontend tools are not the same as backend-executed tools. The backend should not assume a frontend-rendered tool will always return a durable functionResult .
Code Sample
Backend using Azure.AI.OpenAI; using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Agents.AI.CosmosNoSql; using Microsoft.Agents.AI.OpenAI; var builder = WebApplication.CreateBuilder(args); builder.Services.AddAGUI(); var app = builder.Build(); var openAiClient = new AzureOpenAIClient( new Uri(builder.Configuration["AZURE_OPENAI_ENDPOINT"]!), new DefaultAzureCredential()); var chatClient = openAiClient.GetChatClient(builder.Configuration["AZURE_OPENAI_DEPLOYMENT"]!); var cosmosProvider = new CosmosChatHistoryProvider( endpoint: builder.Configuration["COSMOS_ENDPOINT"]!, databaseName: builder.Configuration["COSMOS_DATABASE"]!, containerName: builder.Configuration["COSMOS_CONTAINER"]!, credential: new DefaultAzureCredential()); var agent = chatClient.CreateAIAgent(new ChatClientAgentOptions { Name = "agui-repro", Instructions = """ You are a helpful assistant. If the user asks to show a location on a map, use the render_map tool. """, ChatHistoryProvider = cosmosProvider }); app.MapAGUI("/agent", agent); await app.RunAsync(); Frontend const renderMapTool = { name: "render_map", description: "Render markers on a map in the UI", parameters: { type: "object", properties: { latitude: { type: "number" }, longitude: { type: "number" }, label: { type: "string" } }, required: ["latitude", "longitude", "label"] } }; await fetch("/agent", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ threadId: "demo-thread-1", messages: [ { role: "user", content: "Show Tokyo on a map" } ], tools: [renderMapTool] }) });Error Messages / Stack Traces
HTTP 400 (invalid, request_ error. ) Parameter: input No tool output found for function call call WglIXOb6N37wXIYy/MO7UyyP.Package Versions
Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.9.0-preview.260603.1
.NET Version
.NET 10
Additional Context
No response