Skip to content

.NET: fix: avoid AGUI tool result message id collisions#5800

Merged
rogerbarreto merged 4 commits into
microsoft:mainfrom
he-yufeng:fix/agui-tool-result-message-id
May 15, 2026
Merged

.NET: fix: avoid AGUI tool result message id collisions#5800
rogerbarreto merged 4 commits into
microsoft:mainfrom
he-yufeng:fix/agui-tool-result-message-id

Conversation

@he-yufeng

Copy link
Copy Markdown
Contributor

Summary

  • generate a separate fallback message id for tool-result-only updates
  • keep assistant text and tool-call parent events on the shared assistant fallback id
  • add a regression test covering null provider MessageId with text, tool call, and tool result events

Fixes #5794.

To verify

  • dotnet test --project .\tests\Microsoft.Agents.AI.AGUI.UnitTests -f net10.0 --filter-query "/*/Microsoft.Agents.AI.AGUI.UnitTests/AGUIStreamingMessageIdTests/ToolResults_NullMessageId_GeneratesDistinctMessageIdAsync"
  • dotnet build .\src\Microsoft.Agents.AI.AGUI -f net10.0 --no-restore --tl:off
  • dotnet build .\src\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore -f net10.0 --no-restore --tl:off
  • dotnet test --project .\tests\Microsoft.Agents.AI.AGUI.UnitTests -f net10.0 --no-restore
  • dotnet run --project .\tests\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests -f net10.0 --
  • dotnet format .\src\Microsoft.Agents.AI.AGUI\Microsoft.Agents.AI.AGUI.csproj --verify-no-changes --no-restore
  • dotnet format .\tests\Microsoft.Agents.AI.AGUI.UnitTests\Microsoft.Agents.AI.AGUI.UnitTests.csproj --verify-no-changes --no-restore
  • dotnet format .\src\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.csproj --verify-no-changes --no-restore

Note: dotnet test --project .\tests\Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests -f net10.0 --no-restore reports the repository-level MTP/VSTest runner mismatch for that project, so I ran it through dotnet run --project ... -f net10.0 -- instead.

Copilot AI review requested due to automatic review settings May 13, 2026 06:14
@moonbox3 moonbox3 added the .NET Usage: [Issues, PRs], Target: .Net label May 13, 2026
@github-actions github-actions Bot changed the title fix: avoid AGUI tool result message id collisions .NET: fix: avoid AGUI tool result message id collisions May 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 fixes an AG-UI streaming regression where providers that omit ChatResponseUpdate.MessageId could cause tool result events to reuse the assistant message’s fallback ID, leading to message ID collisions and front-end deduplication (Fixes #5794).

Changes:

  • Adjusts AsAGUIEventStreamAsync fallback MessageId generation to avoid collisions between assistant messages and tool result messages.
  • Adds ContainsOnlyToolResults helper to detect tool-result-only updates for special fallback handling.
  • Adds a regression unit test covering null provider MessageId across assistant text, tool call, and tool result events.

Reviewed changes

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

File Description
dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ChatResponseUpdateAGUIExtensions.cs Updates fallback message-id generation logic to avoid tool result collisions; adds helper method.
dotnet/tests/Microsoft.Agents.AI.AGUI.UnitTests/AGUIStreamingMessageIdTests.cs Adds regression test ensuring tool results get a distinct fallback MessageId when provider omits it.

Comment thread dotnet/src/Microsoft.Agents.AI.AGUI/Shared/ChatResponseUpdateAGUIExtensions.cs Outdated
@he-yufeng he-yufeng force-pushed the fix/agui-tool-result-message-id branch from 5adceb4 to 634e41f Compare May 13, 2026 15:51
@he-yufeng

Copy link
Copy Markdown
Contributor Author

Addressed the mixed-content tool result case in 501cae3. Fallback IDs now split whenever an update contains a FunctionResultContent, not only when it contains function results exclusively, so a tool-role update with TextContent + FunctionResultContent gets a distinct message id and the emitted tool-role text shares the tool result id.\n\nValidation:\n\npowershell\ndotnet build dotnet\\tests\\Microsoft.Agents.AI.AGUI.UnitTests\\Microsoft.Agents.AI.AGUI.UnitTests.csproj --no-restore\ndotnet dotnet\\tests\\Microsoft.Agents.AI.AGUI.UnitTests\\bin\\Debug\\net10.0\\Microsoft.Agents.AI.AGUI.UnitTests.dll --filter-method '*ToolResults_NullMessageId_GeneratesDistinctMessageIdAsync' --filter-method '*ToolResults_WithTextContent_GeneratesDistinctMessageIdAsync' --filter-method '*ToolCalls_EmptyMessageId_GeneratesFallbackParentMessageIdAsync' --no-progress\ndotnet format dotnet\\agent-framework-dotnet.slnx --verify-no-changes --no-restore --include dotnet\\src\\Microsoft.Agents.AI.AGUI\\Shared\\ChatResponseUpdateAGUIExtensions.cs dotnet\\tests\\Microsoft.Agents.AI.AGUI.UnitTests\\AGUIStreamingMessageIdTests.cs\ngit diff --check\n\n\nResult: build passed with 0 warnings/errors, 3 targeted tests passed, format and diff checks passed.

@he-yufeng he-yufeng force-pushed the fix/agui-tool-result-message-id branch from 501cae3 to 8ecb9cf Compare May 14, 2026 14:27
@he-yufeng

Copy link
Copy Markdown
Contributor Author

Rebased this branch onto current main and force-pushed with lease. Re-ran the focused AG-UI validation after the rebase: AGUI unit-test project build passed with 0 warnings/errors, the three message-id regression tests passed, dotnet format --verify-no-changes passed for the touched files, and git diff --check passed.

@rogerbarreto rogerbarreto added this pull request to the merge queue May 15, 2026
Merged via the queue into microsoft:main with commit a60e541 May 15, 2026
26 checks passed
westey-m pushed a commit to westey-m/agent-framework that referenced this pull request May 25, 2026
…rosoft#6009)

Fix three interlocked bugs that prevent parallel tool calls from rendering
correctly in AG-UI protocol clients:

Bug microsoft#1: Scope synthetic MessageId fallback to text events only. The shared
streamingMessageId was leaking into ToolCallStartEvent.ParentMessageId,
causing all parallel tool calls to collapse into one FE card.

Bug microsoft#2: Make ToolCallResultEvent.MessageId deterministically unique using
result-{CallId} format. MEAI's FunctionInvokingChatClient batches all
results with a shared MessageId, collapsing them in FE reconciliation.

Bug microsoft#3: Coalesce consecutive assistant-tool-call messages in AsChatMessages.
Once Bug microsoft#1 is fixed, the FE produces separate AGUIAssistantMessage per
tool call. On multi-turn replay these become consecutive assistant messages
without intervening tool results, triggering HTTP 400 from Azure OpenAI.

Remove the now-dead ContainsToolResult helper introduced by PR microsoft#5800.

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

Labels

.NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: Regression - Tool Events not being emitted correctly to the front end

5 participants