Skip to content

.NET: Fix A2A streaming artifact updates - #7722

Merged
SergeyMenshykh merged 5 commits into
microsoft:mainfrom
SergeyMenshykh:sergeymenshykh-fix-a2a-streaming-empty-parts
Aug 19, 2026
Merged

.NET: Fix A2A streaming artifact updates#7722
SergeyMenshykh merged 5 commits into
microsoft:mainfrom
SergeyMenshykh:sergeymenshykh-fix-a2a-streaming-empty-parts

Conversation

@SergeyMenshykh

@SergeyMenshykh SergeyMenshykh commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Motivation & Context

A2A streaming currently creates a message for every agent update, including contentless updates with empty parts. This violates A2A message-stream requirements, which require a message-only stream to contain exactly one message.

The handler also lacks the alternative task-lifecycle stream for background-capable runs. Long-running responses should begin with a task and deliver progress and output through status and artifact updates until reaching a terminal state. Without these two distinct paths, strict A2A clients cannot reliably reconstruct either direct responses or streamed task output.

Description & Review Guide

  • What are the major changes? Aggregate message-only streams into one message; stream background task output as ordered artifacts with correct append/lastChunk behavior; handle repeated or missing message IDs; and emit terminal task states on completion, cancellation, or failure.
  • What is the impact of these changes? A2A clients receive valid message streams and correctly chunked task artifacts without empty artifact updates.
  • What do you want reviewers to focus on? The message-ID boundary handling in ArtifactStreamWriter and task lifecycle mapping.

Related Issue

Fixes #5868

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9

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

Fixes A2A streaming by aggregating message streams and representing background output as task artifacts.

Changes:

  • Aggregates message-only updates into one response.
  • Adds ordered artifact chunking and task lifecycle states.
  • Expands tests for IDs, contentless updates, failures, and cancellation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
A2AAgentHandler.cs Routes streams to messages or task artifacts.
ArtifactStreamWriter.cs Groups updates into correctly chunked artifacts.
A2AAgentHandlerTests.cs Covers streaming and lifecycle scenarios.
Suppressed comments (2)

dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs:340

  • This checks whether any updates arrived, not whether the aggregated message has any convertible parts. A stream containing only role/finish/contentless updates has updates.Count > 0, while MessageConverter.ToParts returns an empty list, so this still enqueues the protocol-invalid parts: [] message that the PR is intended to eliminate. Validate the aggregated message's parts before enqueueing and cover the message-only contentless case.
        if (updates.Count == 0)
        {
            return;
        }

dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs:307

  • ArtifactStreamWriter always buffers the most recent content-bearing update, but it is completed only on the success path. If enumeration is canceled or throws, the terminal catch emits Canceled/Failed without flushing that buffer, so every interrupted stream drops its last yielded chunk (and a one-chunk failed stream emits no artifact at all). Ensure buffered output is finalized on terminal error paths while preserving delivery of the terminal status if artifact enqueueing also fails.
            await artifactWriter.CompleteAsync(cancellationToken).ConfigureAwait(false);

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs

@github-actions github-actions Bot 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.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (1 commit(s)): 99d325628cca
Model: gpt-5.6-sol

Overview

The review found 5 verified inline finding(s).

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
5 verified findings remained after source verification (2 high, 3 medium) across 2 files. Details are attached to the affected lines below.

Affected areas: dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs, dotnet/src/Microsoft.Agents.AI.Hosting.A2A/ArtifactStreamWriter.cs

Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs
Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/ArtifactStreamWriter.cs Outdated
Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9
@SergeyMenshykh SergeyMenshykh moved this to In Review in Agent Framework Aug 19, 2026
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

Status: Done

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: A2A streaming handler emits one Message per chat-client update with shared messageId and empty Parts on bookend chunks

5 participants