Skip to content

.NET Fix: AuthorName misattribution in multi-agent streaming (null MessageId handling)#1427

Closed
ltwlf wants to merge 2 commits into
microsoft:mainfrom
ltwlf:fix/author-name
Closed

.NET Fix: AuthorName misattribution in multi-agent streaming (null MessageId handling)#1427
ltwlf wants to merge 2 commits into
microsoft:mainfrom
ltwlf:fix/author-name

Conversation

@ltwlf

@ltwlf ltwlf commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

In multi-agent workflows (sequential/handoff), assistant messages get the AuthorName of the next agent. Root cause: null-MessageId streaming updates are appended to the previous message during reconstruction, and last-write-wins metadata (AuthorName) overwrites the prior message.

Where it happens

  • Agent sets author on every streaming update (expected):
    • agent-framework/dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.csRunStreamingAsync
    if (update is not null)
    {
        update.AuthorName ??= this.Name; // all updates, including reasoning/non-message deltas
    }
  • Workflow reconstructs messages from updates:
    • agent-framework/dotnet/src/Microsoft.Agents.AI.Workflows/AgentWorkflowBuilder.cs → AgentRunStreamingExecutor
    // before fix
    messages.AddRange(updates.ToAgentRunResponse().Messages);
    • ToAgentRunResponse() (Microsoft.Extensions.AI) uses MessageId for boundaries; null MessageId updates are treated as part of the previous message, polluting metadata.

Fix (workflow layer)

Filter out updates without MessageId before reconstruction:

var filtered = updates.Where(u => !string.IsNullOrEmpty(u.MessageId)).ToList();
if (filtered.Count > 0)
{
    messages.AddRange(filtered.ToAgentRunResponse().Messages);
}

Fixes issue #1413

See also dotnet/extensions#6910

@markwallace-microsoft markwallace-microsoft added .NET Usage: [Issues, PRs], Target: .Net workflows Usage: [Issues, PRs], Target: Workflows labels Oct 13, 2025
@ltwlf

ltwlf commented Oct 13, 2025

Copy link
Copy Markdown
Contributor Author

@stephentoub this is my proposed fix. I checked dotnet/extensions#6910 and I think it should also solve the issue, because it handles message boundaries much better. This would be my favorite - but would be good to have a fix fast.
What do you think?

/// <param name="updates">The collection of streaming updates to filter.</param>
/// <returns>A list containing only updates with non-empty MessageId values.</returns>
private static List<AgentRunResponseUpdate> FilterUpdatesWithMessageId(IEnumerable<AgentRunResponseUpdate> updates) =>
updates.Where(u => !string.IsNullOrEmpty(u.MessageId)).ToList();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, but this is not a valid solution. The similar check in AIAgentHost needs to be removed after discussion, and one of the reasons this Executor was needed was to avoid that check.

@stephentoub

Copy link
Copy Markdown
Member

@stephentoub this is my proposed fix. I checked dotnet/extensions#6910 and I think it should also solve the issue, because it handles message boundaries much better. This would be my favorite - but would be good to have a fix fast. What do you think?

Thanks, but it is not a valid fix. It will break other things. Updates do not always have a message id. The fix is to wait until the new build of M.E.AI is published, which should be tomorrow.

@ltwlf

ltwlf commented Oct 13, 2025

Copy link
Copy Markdown
Contributor Author

Tomorrow is great - I wish I would have seen your PR in AI Extension earlier.
But on the positve site, I get more and more familiar with the internals of Agent Framework :)

@ltwlf ltwlf closed this Oct 13, 2025
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 workflows Usage: [Issues, PRs], Target: Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants