Skip to content

[dotnet-port] fix(agui): avoid tool result message ID collisions with streaming text messages #190

Description

@github-actions

Summary

When the agent (or underlying LLM provider) sets the same MessageID on both a streaming text/tool-call update and the subsequent tool result update, the ToolCallResult AG-UI event ends up with the same messageId as the TextMessageStart event. AG-UI clients that use messageId to correlate events then incorrectly associate the tool result with the text message.

Fix: in updatesToAGUIEvents, detect when an update contains FunctionResultContent and generate a fresh messageId for those events rather than reusing the update's msgID. A new hasFunctionResultContent helper is added to support this check.

Changed files:

  • agent/hosting/aguihosting/events.go — generate a distinct toolResultMsgID when the update contains FunctionResultContent
  • agent/hosting/aguihosting/agui_test.go — add TestHandler_ToolResult_HasDistinctMessageID covering the collision scenario

Ported .NET PRs

Breaking Changes

No. The ToolCallResult messageId field changes from reusing the update's MessageID to a freshly generated ID, but this was already the intended AG-UI semantic and no existing public API contracts are changed.

Tests and Examples

  • Ran go test ./agent/hosting/aguihosting/... — all existing tests pass
  • Added TestHandler_ToolResult_HasDistinctMessageID: sets up an agent that emits text, tool-call, and tool-result updates all sharing the same explicit MessageID, then asserts that the TOOL_CALL_RESULT event's messageId differs from the TEXT_MESSAGE_START event's messageId
  • Ran go test ./... — all tests pass

Notes

The other new upstream commits (c885ca3d #5895 OpenAI store-false helper fix, d81a8753 #5838 StateBag edge-case tests, 9b772f34 #5894 OpenAIWebSearch observer) are .NET-only: OpenAI-specific C# extensions, test coverage for a .NET StateBag concept absent from the Go SDK, and a harness console sample observer. None were ported.

Upstream head inspected: a60e541c (upstream-agent-framework/main at time of run).

Generated by .NET to Go Porting Agent · ● 1.4M ·


Note

This was originally intended as a pull request, but GitHub Actions is not permitted to create or approve pull requests in this repository.
The changes have been pushed to branch dotnet-port/agui-tool-result-message-id-5800-8c6a7fe5d95d95b3.

Click here to create the pull request

To fix the permissions issue, go to SettingsActionsGeneral and enable Allow GitHub Actions to create and approve pull requests. See also: gh-aw FAQ

Show patch preview (147 of 147 lines)
From 4895b87614d20b02e551c4b189415c689a63f994 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Sat, 16 May 2026 09:31:17 +0000
Subject: [PATCH] fix(agui): avoid tool result message ID collisions with
 streaming text messages

Port of microsoft/agent-framework#5800.

Tool result events (ToolCallResult) must not share the same message ID as
the preceding streaming text/tool-call message. When an update contains
FunctionResultContent, generate a fresh message ID for the tool result
rather than reusing the update's msgID. This prevents AG-UI clients from
incorrectly associating tool results with the wrong parent message.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
 agent/hosting/aguihosting/agui_test.go | 68 ++++++++++++++++++++++++++
 agent/hosting/aguihosting/events.go    | 22 ++++++++-
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/agent/hosting/aguihosting/agui_test.go b/agent/hosting/aguihosting/agui_test.go
index 1afe6aa3..0406224a 100644
--- a/agent/hosting/aguihosting/agui_test.go
+++ b/agent/hosting/aguihosting/agui_test.go
@@ -288,3 +288,71 @@ func TestHandler_UnknownDataContent_UsesCurrentMessageLifecycle(t *testing.T) {
 		t.Fatalf("expected fallback text to use current message id/content, got %q", content)
 	}
 }
+
+// TestHandler_ToolResult_HasDistinctMessageID verifies that tool result events get a
+// distinct message ID from the preceding text/tool-call message to avoid AG-UI
+// message ID collisions (mirrors .NET fix in microsoft/agent-framework#5800).
+func TestHandler_ToolResult_HasDistinctMessageID(t *testing.T) {
+	a := newTestAgent(func(_ context.Context, _ []*message.Message, _ ...agent.Option) iter.Seq2[*agent.ResponseUpdate, error] {
+		return func(yield func(*agent.ResponseUpdate, error) bool) {
+			yield(&agent.ResponseUpdate{
+				MessageID: "msg-stream-1",
+				Role:      message.RoleAssistant,
+				Contents:  message.Contents{&message.T
... (truncated)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions