-
Notifications
You must be signed in to change notification settings - Fork 1k
.NET: Support dynamic agent resolution in AG-UI endpoints #3162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
.NET: Support dynamic agent resolution in AG-UI endpoints #3162
Conversation
There was a problem hiding this 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
IAGUIAgentResolverinterface for DI-based dynamic agent resolution - Introduced factory delegate and DI-based
MapAGUIoverloads 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
ExecuteAgentAsynchelper 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 |
.../Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/DynamicAgentResolutionTests.cs
Show resolved
Hide resolved
.../Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/DynamicAgentResolutionTests.cs
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/ServiceCollectionExtensions.cs
Show resolved
Hide resolved
|
@microsoft-github-policy-service agree |
e727f7c to
5d8912d
Compare
…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
5d8912d to
cdb15aa
Compare
There was a problem hiding this 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.
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/Program.cs
Show resolved
Hide resolved
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/Program.cs
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/IAGUIAgentResolver.cs
Outdated
Show resolved
Hide resolved
dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
...osoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs
Show resolved
Hide resolved
...osoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs
Show resolved
Hide resolved
- 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
There was a problem hiding this 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.
dotnet/samples/GettingStarted/AGUI/Step06_DynamicAgentResolution/Server/Program.cs
Show resolved
Hide resolved
|
@javiercn Can you please review? |
|
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 |
|
@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;
} |
|
@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 On the
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? |
Summary
MapAGUIoverload accepting a factory delegate for dynamic agent resolution at request timeMapAGUIoverload usingIAGUIAgentResolverfrom dependency injectionAddAGUI<TResolver>()generic method for registering custom resolversTest plan
Related Issue
Closes #2988
Changes
New Files
IAGUIAgentResolver.csDynamicAgentResolutionTests.csStep06_DynamicAgentResolution/Server/Step06_DynamicAgentResolution/Client/Modified Files
AGUIEndpointRouteBuilderExtensions.csExecuteAgentAsyncServiceCollectionExtensions.csAddAGUI<TResolver>()generic methodAGUIEndpointRouteBuilderExtensionsTests.csREADME.mdUsage Examples
Factory Delegate
DI-based Resolver