Skip to content

Conversation

@TheEagleByte
Copy link

@TheEagleByte TheEagleByte commented Jan 11, 2026

Summary

  • Add MapAGUI overload accepting a factory delegate for dynamic agent resolution at request time
  • Add MapAGUI overload using IAGUIAgentResolver from dependency injection
  • Add AddAGUI<TResolver>() generic method for registering custom resolvers
  • Return 404 Not Found when factory/resolver returns null
  • Return 500 Internal Server Error with logging when factory throws an exception

Test plan

  • Unit tests pass for factory overload behavior (5 new tests)
  • Integration tests pass for route-based agent resolution (3 new tests)
  • Existing unit tests continue to pass (32 total)
  • Existing integration tests continue to pass (33 total)
  • Step06 sample builds successfully
  • Manual testing with Step06 sample (requires Azure OpenAI credentials)

Related Issue

Closes #2988

Changes

New Files

File Description
IAGUIAgentResolver.cs Interface for DI-based dynamic agent resolution
DynamicAgentResolutionTests.cs Integration tests for dynamic resolution
Step06_DynamicAgentResolution/Server/ Sample server with route-based agent selection
Step06_DynamicAgentResolution/Client/ Sample client demonstrating agent switching

Modified Files

File Description
AGUIEndpointRouteBuilderExtensions.cs Added factory and resolver overloads, extracted ExecuteAgentAsync
ServiceCollectionExtensions.cs Added AddAGUI<TResolver>() generic method
AGUIEndpointRouteBuilderExtensionsTests.cs Added 5 unit tests for factory overload
README.md Added Step06 documentation

Usage Examples

Factory Delegate

app.MapAGUI("/agents/{agentId}", async (context, cancellationToken) =>
{
    string? agentId = context.GetRouteValue("agentId")?.ToString();
    if (string.IsNullOrEmpty(agentId))
        return null; // Returns 404

    return await agentRepository.GetAgentByIdAsync(agentId, cancellationToken);
});

DI-based Resolver

// Registration
builder.Services.AddAGUI<MyAgentResolver>();

// Endpoint
app.MapAGUI("/agents/{agentId}");

// Resolver implementation
public class MyAgentResolver : IAGUIAgentResolver
{
    public ValueTask<AIAgent?> ResolveAgentAsync(HttpContext context, CancellationToken cancellationToken)
    {
        // Resolution logic here
    }
}

Copilot AI review requested due to automatic review settings January 11, 2026 00:51
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation .NET labels Jan 11, 2026
Copy link
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

This pull request adds dynamic agent resolution capabilities to AG-UI endpoints, enabling scenarios like multi-tenant applications, agent selection by ID, and runtime agent configuration. The PR introduces three new MapAGUI overloads: one accepting a static agent (refactored), one accepting a factory delegate for dynamic resolution, and one using dependency injection with IAGUIAgentResolver.

Changes:

  • Added IAGUIAgentResolver interface for DI-based dynamic agent resolution
  • Introduced factory delegate and DI-based MapAGUI overloads with proper error handling (404 for null, 500 with logging for exceptions)
  • Added AddAGUI<TResolver>() generic method for registering custom resolvers
  • Extracted common agent execution logic into ExecuteAgentAsync helper method
  • Added comprehensive unit tests (5 new tests) and integration tests (3 new tests) for factory-based resolution
  • Created Step06 sample demonstrating route-based agent selection with server and client implementations

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/IAGUIAgentResolver.cs New interface for DI-based dynamic agent resolution with comprehensive XML documentation
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs Added factory delegate and resolver-based MapAGUI overloads, refactored original overload, extracted ExecuteAgentAsync helper
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/ServiceCollectionExtensions.cs Added generic AddAGUI() method for registering custom resolvers
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs Added 5 new unit tests covering factory overload scenarios including null handling, exception handling, and cancellation token propagation
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/DynamicAgentResolutionTests.cs New integration test suite with 3 tests for route-based agent resolution scenarios
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/Program.cs Sample server demonstrating dynamic agent resolution with three agent configurations
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Client/Program.cs Sample client with interactive agent switching and error handling
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/Server.csproj Project configuration for Step06 server sample
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Client/Client.csproj Project configuration for Step06 client sample
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/appsettings.json Standard ASP.NET Core configuration for Step06 server
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/appsettings.Development.json Development environment configuration for Step06 server
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/Properties/launchSettings.json Launch profiles for Step06 server
dotnet/samples/GettingStarted/AGUI/README.md Updated documentation to include Step06 sample and dynamic agent resolution feature

@TheEagleByte
Copy link
Author

@microsoft-github-policy-service agree

@TheEagleByte TheEagleByte force-pushed the feature/dynamic-agent-resolution-2988 branch from e727f7c to 5d8912d Compare January 11, 2026 01:35
…soft#2988)

Add new MapAGUI overloads that support dynamic agent resolution at
request time, enabling multi-tenant applications, agent selection by ID,
and agent marketplaces.

New features:
- MapAGUI factory overload that accepts a delegate for dynamic resolution
- MapAGUI overload using IAGUIAgentResolver from DI container
- AddAGUI<TResolver> generic method for registering custom resolvers
- 404 Not Found when factory returns null
- 500 Internal Server Error with logging when factory throws

Implementation:
- Added IAGUIAgentResolver interface for DI-based resolution
- Refactored existing MapAGUI to delegate to factory overload
- Extracted common agent execution logic to ExecuteAgentAsync
- Added DynamicallyAccessedMembers attribute for trim compatibility

Testing:
- Unit tests for factory overload behavior
- Integration tests for route-based agent resolution
- Step06 sample demonstrating dynamic agent selection
Copy link
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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

- Use explicit types in Step06 sample code per guidelines
- Clarify thread-safety documentation for IAGUIAgentResolver and factory
- Add test for OperationCanceledException re-throw behavior
- Add documentation for CreateRequestDelegateWithFactory helper
Copy link
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

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

@TheEagleByte
Copy link
Author

@javiercn Can you please review?

@Davidlmkh
Copy link

Thank you @TheEagleByte for this PR which would need to be reproducted on the A2A exposition that embraces the same static pattern.

This is a true lack in exposition abilities which conducts to a fork of this repo or to a dedicated infrastructure part for each agent, which is really painful.

+1 here

@javiercn
Copy link
Contributor

@TheEagleByte thanks for the contribution.

Before we move forward with this change, we'd rather have a broader discussion to establish the pattern here, as this needs to be applied not only to AG-UI but to Open AI responses and A2A and we'd rather do everything simultaneously.

With that said, it is already possible to perform dynamic agent selection with a delegating agent that uses IHttpContextAccessor to get a hold of the current request, resolve the agent dynamically and dispatch to it.

Alternatively, you can use forwarded props in your AG-UI client to control the agent selection.

Here is a sketch of what that looks like

public class HttpContextRoutingAgent : AIAgent
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HttpContextRoutingAgent(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override string?  Name => "HttpContextRoutingAgent";

    public override string? Description => "Routes requests to agents based on HTTP route data";

    protected override Task<AgentResponse> RunCoreAsync(
        IEnumerable<ChatMessage> messages,
        AgentThread?  thread = null,
        AgentRunOptions? options = null,
        CancellationToken cancellationToken = default)
    {
        var agent = ResolveAgentFromHttpContext();
        return agent.RunAsync(messages, thread, options, cancellationToken);
    }

    protected override IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingAsync(
        IEnumerable<ChatMessage> messages,
        AgentThread? thread = null,
        AgentRunOptions? options = null,
        CancellationToken cancellationToken = default)
    {
        var agent = ResolveAgentFromHttpContext();
        return agent.RunStreamingAsync(messages, thread, options, cancellationToken);
    }

    private AIAgent ResolveAgentFromHttpContext()
    {
        var httpContext = _httpContextAccessor.HttpContext
            ?? throw new InvalidOperationException("No HttpContext available");

        // Get the "agent" parameter from route data
        var agentName = httpContext.GetRouteValue("agent")?.ToString()
            ?? throw new InvalidOperationException("No 'agent' route parameter found");

        // Resolve the agent by name from DI
        var agent = httpContext.RequestServices.GetKeyedService<AIAgent>(agentName)
            ?? throw new InvalidOperationException($"No agent registered with name '{agentName}'");

        return agent;
    }

@TheEagleByte
Copy link
Author

@javiercn Thanks for the feedback. A few thoughts:

On the broader consistency discussion: I agree this pattern should be applied consistently across A2A, OpenAI responses, etc. However, the approach here with factory delegate overloads with a resolver interface is the standard ASP.NET Core pattern used by AddDbContext<T>(), AddAuthentication<THandler>(), minimal API delegates, and similar framework-level extension points. This PR establishes that pattern for AG-UI; the same approach can be applied to other endpoints for consistency, but I don't think this should block this PR.

On the HttpContextRoutingAgent alternative: While this works as an application-level workaround, it has some drawbacks:

  1. It couples agent logic to HTTP transport concerns via IHttpContextAccessor - agents should ideally be transport agnostic
  2. It conflates two responsibilities (agent behavior + request routing) that are better separated
  3. It requires every consumer to implement their own delegating wrapper rather than solving it once at the framework level

The factory/resolver approach keeps these concerns cleanly separated: the endpoint layer handles routing and resolution, the agent layer handles agent behavior.

Happy to discuss further or adjust if there's a broader architectural direction I'm missing. Should this be moved to a design discussion issue? Who needs to be a part of that discussion?

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

None yet

Development

Successfully merging this pull request may close these issues.

.NET: Support dynamic agent resolution in AG-UI endpoints (MapAGUI with factory delegate)

4 participants