Skip to content

.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
microsoft:mainfrom
marcominerva:dotnet-hosting-request-scoped-agents-a2a
Open

Marco Minerva (marcominerva) wants to merge 6 commits into
microsoft:mainfrom
marcominerva:dotnet-hosting-request-scoped-agents-a2a

Conversation

@marcominerva

@marcominerva Marco Minerva (marcominerva) commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

AddA2AServer resolves the hosted agent and its session services from the root service provider, so Scoped and Transient AddAIAgent registrations 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

  • What are the major changes?
    • New internal ScopedA2AAgentHandler: for Scoped/Transient registrations the keyed AIAgent, its AgentSessionStore and an optional keyed IAgentHandler are 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. The A2AServer and its task store remain singletons; Singleton registrations are still resolved once.
    • AddA2AServer checks the agent registration with IServiceProviderIsKeyedService instead of resolving it from the root provider.
    • New MapA2AHttpJson(path, Func<HttpContext, AIAgent?>) and MapA2AJsonRpc(path, Func<HttpContext, AIAgent?>) overloads backed by the internal SelectedAgentA2ARequestHandler. A null selection returns 404 before any session/task state is loaded; the selected agent's Name keys its session store, task store and persisted state. Because the session store comes from the request services, non-streaming requests with ReturnImmediately = true are rejected with UnsupportedOperation when the run mode returns a task.
    • Microsoft.Agents.AI.Hosting.A2A exposes internals to Microsoft.Agents.AI.Hosting.A2A.AspNetCore; the AspNetCore project therefore no longer injects the Throw/DiagnosticIds shared sources, to avoid duplicate type definitions.
    • Shared source helper src/Shared/HostedAgents/HostedAgentResolution.cs (identical in each PR of this split, so they merge cleanly in any order).
  • What is the impact of these changes? Scoped/Transient agents served over A2A honor their DI lifetime; additive public API only.

Related Issue

Part of #7733 (split from #9382).

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 links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change.

…on for A2A hosting

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

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.

🟡 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

Comment thread dotnet/src/Microsoft.Agents.AI.Hosting.A2A/A2AAgentHandler.cs Outdated
…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>
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>
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>
…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>

This branch was successfully deployed

1 active deployment
github-app-auth — 6d73d581 Deployed Oct 19, 2026 by marcominerva via add_label #25728
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

None yet

Development

Successfully merging this pull request may close these issues.

2 participants