Repository navigation
.NET: Honor hosted agent lifetimes and add request-time agent selection for A2A hosting - #9524
Open
Marco Minerva (marcominerva) wants to merge 6 commits into
Conversation
…on for A2A hosting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 09:03 — with
GitHub Actions
Active
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 09:03 — with
GitHub Actions
Active
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 09:08 — with
GitHub Actions
Active
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Request-bound execution lifetimes, scoped isolation resolution, and cached-server shutdown ownership remain unresolved.
4 open issues
What changed in this PR
Updates .NET A2A hosting to honor agent lifetimes and support request-time agent selection, addressing the A2A portion of #7733.
Changes:
- Resolves hosted agents and session services in per-operation scopes.
- Adds HTTP+JSON and JSON-RPC selector overloads with stable session identity.
- Adds lifetime, selection, persistence, and response-mode tests.
| File | Description |
|---|---|
| dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/A2AServerServiceCollectionExtensionsTests.cs | Updates session-store resolution expectations. |
| dotnet/tests/Microsoft.Agents.AI.Hosting.A2A.UnitTests/A2ARequestScopedAgentTests.cs | Tests lifetimes and selector endpoints. |
| dotnet/src/Shared/HostedAgents/HostedAgentResolution.cs | Validates registrations and selected agent names. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A/ScopedA2AAgentHandler.cs | Owns per-operation service scopes. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A/Microsoft.Agents.AI.Hosting.A2A.csproj | Enables shared helpers and internal access. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AServerServiceCollectionExtensions.cs | Separates shared servers from scoped execution services. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs | Adds immediate-response restrictions and cancellation helper. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/SelectedAgentA2ARequestHandler.cs | Dispatches requests to selected agents. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj | Removes duplicate shared-source injection. |
| dotnet/src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/A2AEndpointRouteBuilderExtensions.cs | Exposes selector-based endpoint overloads. |
| dotnet/eng/MSBuild/Shared.props | Adds hosted-agent shared-source inclusion. |
Review effort: Balanced
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 09:14 — with
GitHub Actions
Active
Merged
4 of 5 tasks
…mpletes A2AServer keeps streaming runs going after the response stream ends early, for example when the client disconnects, while the selected agent and its session store belong to the HTTP request. The selector request handler now waits for the agent run before the request ends and rejects runs that would start after it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 09:45 — with
GitHub Actions
Active
The task store of the server cached for a selected agent name resolved AgentIsolationKeyProvider from the root provider, so scoped providers failed scope validation or were captured for every request. The cached task store now asks the provider resolved from the current request's services for each operation, and the selector endpoint filter executes the endpoint result in its own flow so streaming operations see the selection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ervers Servers registered with AddA2AServer resolved AgentIsolationKeyProvider from the root provider for the task store and from a new operation scope for the session store, so scoped providers failed scope validation or did not see the request. The A2A endpoint extensions now resolve the isolation key once per request from its services and make it ambient for the request flow, including operations that continue in the background. The task and session stores of both registered and selector servers use that key, falling back to a new service scope outside A2A requests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 10:35 — with
GitHub Actions
Active
The A2A servers cached for selected agents were created manually, so nothing disposed them and application shutdown could dispose their dependencies while detached operations were still running. The selector request handler now owns and disposes these servers, and it is disposed when the application has stopped, after in-flight requests and before the service provider is disposed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 10:55 — with
GitHub Actions
Active
…points The ReturnImmediately guard of the selector endpoints only covered new messages, so continuing an existing task with ReturnImmediately invoked the selected agent with a run that would outlive the request. Such continuations are now rejected with UnsupportedOperation before A2AServer starts their execution, which keeps the continued task and its history unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Marco Minerva (marcominerva)
deployed
to
github-app-auth
October 19, 2026 12:34 — with
GitHub Actions
Active
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Motivation & Context
AddA2AServerresolves the hosted agent and its session services from the root service provider, so Scoped and TransientAddAIAgentregistrations are captured for the lifetime of the application. A2A endpoints also cannot select the agent at request time.This PR is the A2A part of #9382, which was split per hosting protocol to make review easier. It is independent from the AG-UI, OpenAI Chat Completions and OpenAI Responses PRs.
Description & Review Guide
ScopedA2AAgentHandler: for Scoped/Transient registrations the keyedAIAgent, itsAgentSessionStoreand an optional keyedIAgentHandlerare resolved from a new service scope per A2A operation (not the request scope), because A2A operations can continue in the background after the HTTP request completes. TheA2AServerand its task store remain singletons; Singleton registrations are still resolved once.AddA2AServerchecks the agent registration withIServiceProviderIsKeyedServiceinstead of resolving it from the root provider.MapA2AHttpJson(path, Func<HttpContext, AIAgent?>)andMapA2AJsonRpc(path, Func<HttpContext, AIAgent?>)overloads backed by the internalSelectedAgentA2ARequestHandler. Anullselection returns404before any session/task state is loaded; the selected agent'sNamekeys its session store, task store and persisted state. Because the session store comes from the request services, non-streaming requests withReturnImmediately = trueare rejected withUnsupportedOperationwhen the run mode returns a task.Microsoft.Agents.AI.Hosting.A2Aexposes internals toMicrosoft.Agents.AI.Hosting.A2A.AspNetCore; the AspNetCore project therefore no longer injects theThrow/DiagnosticIdsshared sources, to avoid duplicate type definitions.src/Shared/HostedAgents/HostedAgentResolution.cs(identical in each PR of this split, so they merge cleanly in any order).Related Issue
Part of #7733 (split from #9382).
Contribution Checklist