Skip to content

.NET: Migrate A2A agent and hosting to A2A SDK v1#5422

Closed
SergeyMenshykh wants to merge 7 commits intomicrosoft:mainfrom
SergeyMenshykh:a2a-agent-migration
Closed

.NET: Migrate A2A agent and hosting to A2A SDK v1#5422
SergeyMenshykh wants to merge 7 commits intomicrosoft:mainfrom
SergeyMenshykh:a2a-agent-migration

Conversation

@SergeyMenshykh
Copy link
Copy Markdown
Member

@SergeyMenshykh SergeyMenshykh commented Apr 22, 2026

Summary

Migrate the .NET A2A agent and hosting packages from A2A SDK 0.3.4-preview to 1.0.0-preview2. This is a comprehensive update that reworks the agent, hosting, and extension APIs to align with the v1 SDK, adds SSE stream reconnection support, and reorganizes samples.

What Changed

Core Agent (Microsoft.Agents.AI.A2A)

  • Refactored A2AAgent for v1 SDK APIs — updated message/task handling and streaming logic.
  • Added SSE stream reconnection support using continuation tokens, allowing recovery from stream interruptions without losing progress.
  • Updated A2AAgentCardExtensions and A2ACardResolverExtensions to use A2AClientFactory.Create() for client creation and accept an optional A2AClientOptions for protocol binding preference.
  • Updated A2AClientExtensions to operate on IA2AClient interface instead of concrete A2AClient.

Hosting (Microsoft.Agents.AI.Hosting.A2A / .AspNetCore)

  • Added: A2AAgentHandler — new handler aligned with v1 SDK hosting model.
  • Added: A2AServerRegistrationOptions — configuration for server registration.
  • Added: A2AServerServiceCollectionExtensions — consolidated DI registration for A2A servers.
  • Added: A2AEndpointRouteBuilderExtensions — protocol-specific endpoint mapping methods.
  • Removed: EndpointRouteBuilderExtensions (replaced by A2AEndpointRouteBuilderExtensions).
  • Removed: AIAgentExtensions (logic consolidated into A2AServerServiceCollectionExtensions).

Samples

  • Moved A2A samples from samples/04-hosting/A2A/ to samples/02-agents/A2A/.
  • New: A2AAgent_ProtocolSelection — demonstrates protocol selection.
  • New: A2AAgent_StreamReconnection — demonstrates SSE stream reconnection.
  • Updated A2AClientServer, AgentWebChat, and A2AAgent_PollingForTaskCompletion to use the new APIs.

SergeyMenshykh and others added 6 commits April 15, 2026 11:08
Move the A2A sample projects (A2AAgent_AsFunctionTools and
A2AAgent_PollingForTaskCompletion) from samples/04-hosting/A2A/ to
samples/02-agents/A2A/ to better align with the sample directory
structure. Update solution file and samples README accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add SSE stream reconnection support to A2AAgent

Implement automatic reconnection for SSE streams that disconnect mid-task,
using the Last-Event-ID header to resume from where the stream left off.

Changes:
- Add InvokeStreamingWithReconnectAsync method to A2AAgent with configurable
  max retries and delay between attempts
- Add new log messages for reconnection events
- Add A2AAgent_StreamReconnection sample demonstrating the feature
- Update existing polling sample to use simplified SendMessageAsync API
- Add unit tests for stream reconnection logic

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

* address comments

* Address PR review feedback

- Dispose SSE enumerator before GetTaskAsync fallback to release HTTP connection
- Wrap StreamWriter in using blocks with leaveOpen:true and explicit UTF-8 encoding
- Print update.Text instead of update object in stream reconnection sample

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refactor A2A extensions to use IA2AClientFactory and add ProtocolSelection sample

- Update A2AAgentCardExtensions to accept IA2AClientFactory instead of A2AClientOptions
- Update A2ACardResolverExtensions to accept IA2AClientFactory
- Update A2AClientExtensions to accept IA2AClientFactory
- Update A2AAgent to use IA2AClientFactory for client creation
- Add A2AAgent_ProtocolSelection sample demonstrating protocol selection
- Add comprehensive unit tests for all changes
- Update README files with new sample reference

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

* Reorder params: options before loggerFactory in A2A extensions

Move A2AClientOptions parameter before ILoggerFactory in AsAIAgent
and GetAIAgentAsync extension methods to follow the repo convention
of keeping LoggerFactory and CancellationToken as the last parameters.

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* .NET: Migrate A2A hosting to A2A SDK v1

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

* remove unused agent card

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…osoft#5413)

* .NET: Refactor A2A hosting registration into A2AServerServiceCollectionExtensions

- Rename A2AHostingOptions to A2AServerRegistrationOptions
- Move server registration logic from A2AEndpointRouteBuilderExtensions
  and AIAgentExtensions into new A2AServerServiceCollectionExtensions
- Remove A2AProtocolBinding and AIAgentExtensions (consolidated)
- Update samples and tests to use the new registration API

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

* address copilot comments

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 22, 2026 09:57
@moonbox3 moonbox3 added documentation Improvements or additions to documentation .NET labels Apr 22, 2026
@SergeyMenshykh SergeyMenshykh self-assigned this Apr 22, 2026
@SergeyMenshykh SergeyMenshykh moved this to In Progress in Agent Framework Apr 22, 2026
@SergeyMenshykh SergeyMenshykh moved this from In Progress to In Review in Agent Framework Apr 22, 2026
@SergeyMenshykh
Copy link
Copy Markdown
Member Author

@copilot resolve the merge conflicts in this pull request

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Migrates the .NET A2A agent and hosting layers to A2A SDK v1 (1.0.0-preview2), updating agent/task/streaming models, introducing a new DI-first hosting registration + endpoint mapping approach, and reorganizing/expanding samples and tests to match the new SDK surface.

Changes:

  • Updated A2A agent/client integration to v1 SDK types (IA2AClient, SendMessageRequest/Response, StreamResponse) and added stream reconnection fallback behavior.
  • Reworked A2A hosting to a server-registration model (AddA2AServer) with protocol-specific endpoint mapping (MapA2AHttpJson, MapA2AJsonRpc) and added a new A2AAgentHandler.
  • Moved/added A2A samples under samples/02-agents/A2A/ and refreshed/expanded unit tests; bumped A2A + related dependency versions.

Reviewed changes

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

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.A2A/A2AAgent.cs Migrates agent runtime + streaming to v1 SDK request/response models and adds Subscribe-to-task fallback logic.
dotnet/src/Microsoft.Agents.AI.A2A/A2AAgentLogMessages.cs Adds a warning log for subscribe→get-task fallback on UnsupportedOperation.
dotnet/src/Microsoft.Agents.AI.A2A/Extensions/A2AClientExtensions.cs Switches extension surface to IA2AClient.
dotnet/src/Microsoft.Agents.AI.A2A/Extensions/ChatMessageExtensions.cs Updates A2A message conversion to v1 Message/Role types.
dotnet/src/Microsoft.Agents.AI.A2A/Extensions/A2AAgentCardExtensions.cs Uses A2AClientFactory.Create(...) and adds optional A2AClientOptions for binding selection.
dotnet/src/Microsoft.Agents.AI.A2A/Extensions/A2ACardResolverExtensions.cs Adds optional A2AClientOptions passthrough when resolving agents from cards.
dotnet/src/Microsoft.Agents.AI.A2A/Microsoft.Agents.AI.A2A.csproj Targets $(TargetFrameworksCore) for the A2A library.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs Introduces a v1-aligned agent handler emitting A2A events for messages/tasks.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2ARunDecisionContext.cs Updates run-decision context to wrap v1 RequestContext.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A/AgentRunMode.cs Fixes background decision default behavior and updates docs/behavior.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A/Converters/MessageConverter.cs Updates converter to accept v1 SendMessageRequest.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AServerRegistrationOptions.cs Adds options container for keyed server registration.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AServerServiceCollectionExtensions.cs Adds DI registration extensions for keyed A2AServer creation.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/A2AEndpointRouteBuilderExtensions.cs Adds protocol-specific endpoint mapping methods (HTTP+JSON, JSON-RPC).
dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/EndpointRouteBuilderExtensions.cs Removes legacy endpoint-mapping extensions.
dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj Adds RT0002 suppression and normalizes formatting/props.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Microsoft.Agents.AI.A2A.UnitTests.csproj Aligns test TFMs with $(TargetFrameworksCore).
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/A2AClientExtensionsTests.cs Adds interface-based client extension coverage.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/ChatMessageExtensionsTests.cs Updates assertions for v1 parts/content cases.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/A2ACardResolverExtensionsTests.cs Updates card URL model and verifies protocol binding option passthrough.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/A2AAgentCardExtensionsTests.cs Adds protocol selection test cases and updates JSON-RPC response shaping.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/A2AArtifactExtensionsTests.cs Updates artifact parts creation to v1 Part helpers.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/A2AAgentTaskExtensionsTests.cs Updates task/status types and artifact part creation for v1.
dotnet/tests/Microsoft.Agents.AI.A2A.UnitTests/Extensions/A2AAIContentExtensionsTests.cs Updates content-to-part mapping assertions for v1.
dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/A2AAgentHandlerTests.cs Adds extensive handler tests for message/task flows and run modes.
dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/AgentRunModeTests.cs Adds equality/to-string/validation coverage for AgentRunMode.
dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/Converters/MessageConverterTests.cs Updates converter test inputs to v1 request/message types.
dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/A2AEndpointRouteBuilderExtensionsTests.cs Updates tests to new endpoint mapping + DI server registration model.
dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/AIAgentExtensionsTests.cs Removes tests for removed legacy AIAgentExtensions surface.
dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/A2AIntegrationTests.cs Removes legacy integration test tied to old mapping/card model.
dotnet/samples/README.md Updates hosting samples description after moving A2A samples.
dotnet/samples/02-agents/README.md Adds entry for new A2A samples folder.
dotnet/samples/02-agents/A2A/README.md Fixes relative link and lists new A2A samples.
dotnet/samples/02-agents/A2A/A2AAgent_AsFunctionTools/* Adds new A2A agent-as-tools sample under 02-agents.
dotnet/samples/02-agents/A2A/A2AAgent_PollingForTaskCompletion/* Updates polling sample for v1 APIs and background responses.
dotnet/samples/02-agents/A2A/A2AAgent_StreamReconnection/* Adds stream reconnection sample using continuation tokens.
dotnet/samples/02-agents/A2A/A2AAgent_ProtocolSelection/* Adds protocol binding selection sample via A2AClientOptions.
dotnet/samples/05-end-to-end/AgentWebChat/AgentWebChat.Web/A2AAgentClient.cs Updates client code to v1 response union (PayloadCase).
dotnet/samples/05-end-to-end/AgentWebChat/AgentWebChat.AgentHost/Program.cs Updates hosting setup to AddA2AServer + MapA2AHttpJson.
dotnet/samples/05-end-to-end/A2AClientServer/A2AServer/Program.cs Migrates sample server to new registration/mapping model and updated agent card interfaces.
dotnet/samples/05-end-to-end/A2AClientServer/A2AServer/HostAgentFactory.cs Updates generated agent cards to use SupportedInterfaces and configurable URLs.
dotnet/samples/05-end-to-end/A2AClientServer/A2AClient/Program.cs Simplifies output printing to use AgentResponse.Text.
dotnet/agent-framework-dotnet.slnx Moves A2A samples folder location and adds new sample projects.
dotnet/Directory.Packages.props Bumps A2A/A2A.AspNetCore + related dependency versions for v1.

RawRepresentation = statusUpdateEvent,
Role = ChatRole.Assistant,
AdditionalProperties = taskUpdateEvent.Metadata?.ToAdditionalProperties() ?? [],
FinishReason = MapTaskStateToFinishReason(statusUpdateEvent.Status.State),
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

TaskStatusUpdateEvent streaming updates currently don’t populate AgentResponseUpdate.ContinuationToken. That makes it impossible for callers to capture a continuation token if the stream begins with status updates (common for long-running tasks), which conflicts with the stream-reconnection behavior described in this PR. Consider setting ContinuationToken from the task id when Status.State is Submitted/Working (same logic used for AgentTask updates).

Suggested change
FinishReason = MapTaskStateToFinishReason(statusUpdateEvent.Status.State),
FinishReason = MapTaskStateToFinishReason(statusUpdateEvent.Status.State),
ContinuationToken = CreateContinuationToken(statusUpdateEvent.TaskId, statusUpdateEvent.Status.State),

Copilot uses AI. Check for mistakes.
Comment on lines +161 to +168
ProtocolBinding = "JSONRPC",
ProtocolVersion = "1.0",
}));

agentInterfaces.AddRange(agentUrls.Select(url => new AgentInterface
{
Url = url,
ProtocolBinding = "HTTP+JSON",
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

In CreateAgentInterfaces, protocol binding names are hard-coded as "JSONRPC" and "HTTP+JSON". Since the repo already uses ProtocolBindingNames.HttpJson/JsonRpc elsewhere, using those constants here would avoid casing/typo bugs and keep samples consistent with the rest of the codebase.

Suggested change
ProtocolBinding = "JSONRPC",
ProtocolVersion = "1.0",
}));
agentInterfaces.AddRange(agentUrls.Select(url => new AgentInterface
{
Url = url,
ProtocolBinding = "HTTP+JSON",
ProtocolBinding = ProtocolBindingNames.JsonRpc,
ProtocolVersion = "1.0",
}));
agentInterfaces.AddRange(agentUrls.Select(url => new AgentInterface
{
Url = url,
ProtocolBinding = ProtocolBindingNames.HttpJson,

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 3 | Confidence: 85%

✓ Security Reliability

No actionable issues found in this dimension.

✗ Test Coverage

No test additions or updates are visible for any of these. The existing EndpointRouteA2ABuilderExtensionsTests still reference the deleted MapA2A overloads from the removed EndpointRouteBuilderExtensions.cs, so those tests will fail against the new MapA2AHttpJson/MapA2AJsonRpc API. The existing A2AAgentCardExtensionsTests do not cover the new A2AClientOptions parameter added to AsAIAgent. The SubscribeToTaskWithFallbackAsync method contains nuanced async-enumerator disposal and A2AException fallback logic that especially warants dedicated unit tests. The AgentRunMode bug fix (DisallowBackground returning wrong value) is covered by tests in other files in this PR. The new tests have meaningful assertions and appropriate mocking. Minor suggestions: two binding-related tests use overly broad exception assertions, and the handler stub has a minor inconsistency in JSON serialization options. The new A2AgentHandlerTests and AgentRunModeTests provide good baseline coverage for the new handler architecture. However, there are notable coverage regressions compared to the deleted AIAgentExtensionsTests: (1) no test for the positive case where input metadata with values is forwarded as AgentRunOptions.AdditionalProperties, (2) weaker assertions on response metadata that only check key existence rather than values, (3) the deletion of A2AIntegrationTests removes the only HTTP-level test verifying the agent card endpoint, and (4) no tests exercise the streaming path (all tests hardcode StreamingResponse=false). The AgentRunModeTests and endpoint builder tests are thorough for their scope.

✗ Design Approach

The A2A 1.0 migration is mostly coherent, but the new hosting split introduces a discovery mismatch in the AgentWebChat sample. The host now exposes only the HTTP+JSON transport endpoints, while the in-repo web client still resolves agent cards from /v1/card/; that leaves the sample unable to retrieve cards unless discovery is mapped explicitly or the client is changed to use the new endpoint shape. I found two design-level issues. First, the new streaming-continuation behavior appears to treat a task ID as a resumable stream cursor, but the current continuation token shape and the existing A2A agent comments both indicate the protocol does not define replay/resume semantics here, so this can surface duplicate or missing updates. Second, the new card-selection tests lock the client onto SupportedInterfaces and exceptions when that collection is absent, which turns an SDK-shape migration into a client compatibility break for existing AgentCard.Url producers that this repo still uses and tests today. That bakes a misleading abstraction into the contract. I also think the test reshuffle weakens coverage of the HTTP-facing agent-card contract by deleting the only end-to-end assertion around URL population and replacing it with route-mapping smoke tests.

Flagged Issues

  • A2AEndpointRouteBuilderExtensions replaces the deleted EndpointRouteBuilderExtensions.cs, introducing MapA2AHttpJson and MapA2AJsonRpc. The existing EndpointRouteA2ABuilderExtensionsTests still call the now-deleted MapA2A methods (lines 32, 54, 74, 94, 120) and will fail. No tests for the new methods were found.
  • AgentRunMode equality for callback-backed dynamic modes compares only the string _value and ignores the delegate (AgentRunMode.cs:86–93), so behaviorally different policies collapse to the same key/hash. This is a poor contract for a configuration object whose purpose is to carry execution policy.

Suggestions

  • Add tests for the extracted ConvertToAgentResponse(Message) and ConvertToAgentResponse(AgentTask) methods. While indirectly tested through RunAsync, dedicated tests would catch regressions in response mapping, especially ContinuationToken creation for tasks.
  • Prefer SupportedInterfaces when present but keep AgentCard.Url as a compatibility fallback until all card producers have moved to the new shape.
  • Do not expose streaming continuation as supported until the token can encode replay/resume state explicitly, or limit the API to non-streaming GetTask continuation for now.

Automated review by SergeyMenshykh's agents

Assert.Equal(2, message.Metadata.Count);
Assert.True(message.Metadata.ContainsKey("responseKey1"));
Assert.True(message.Metadata.ContainsKey("responseKey2"));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This test asserts metadata keys exist (ContainsKey) but doesn't verify the values. The deleted AIAgentExtensionsTests had stronger assertions like Assert.Equal("responseValue1", ...). Consider verifying that metadata values round-trip correctly, not just that keys are present.

@@ -154,17 +158,9 @@ Once the user has deduced what type (knight or knave) both Alice and Bob are, te
// Configure the HTTP request pipeline.
app.UseExceptionHandler();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MapA2AHttpJson only wires up the REST transport routes, but this sample's client still resolves agent cards via A2ACardResolver(..., agentCardPath: "/v1/card/") in AgentWebChat.Web/A2AgentClient.cs:148. The host no longer publishes the discovery route the client expects, so agent-card retrieval will fail. Either preserve discovery mapping here or update host and client together.

@SergeyMenshykh
Copy link
Copy Markdown
Member Author

Closing to recreate from microsoft:a2a-agent-migration

@github-project-automation github-project-automation Bot moved this from In Review to Done in Agent Framework Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation .NET

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants