Skip to content

Commit b2e6f0b

Browse files
author
Manuel Naujoks
committed
dotnet: MapAGUI supports per-request agent selection
1 parent 99689ad commit b2e6f0b

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

dotnet/samples/AGUIClientServer/AGUIDojoServer/Program.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,21 @@
4040
var jsonOptions = app.Services.GetRequiredService<IOptions<Microsoft.AspNetCore.Http.Json.JsonOptions>>();
4141
app.MapAGUI("/shared_state", ChatClientAgentFactory.CreateSharedState(jsonOptions.Value.SerializerOptions));
4242

43+
app.MapAGUI("/agents/{agentId}", async (context) =>
44+
{
45+
var agentId = context.Request.RouteValues["agentId"]?.ToString() ?? string.Empty;
46+
return agentId switch
47+
{
48+
"agentic_chat" => ChatClientAgentFactory.CreateAgenticChat(),
49+
"backend_tool_rendering" => ChatClientAgentFactory.CreateBackendToolRendering(),
50+
"human_in_the_loop" => ChatClientAgentFactory.CreateHumanInTheLoop(),
51+
"tool_based_generative_ui" => ChatClientAgentFactory.CreateToolBasedGenerativeUI(),
52+
"agentic_generative_ui" => ChatClientAgentFactory.CreateAgenticUI(),
53+
"shared_state" => ChatClientAgentFactory.CreateSharedState(jsonOptions.Value.SerializerOptions),
54+
_ => throw new ArgumentException($"Unknown agent ID: {agentId}"),
55+
};
56+
});
57+
4358
await app.RunAsync();
4459

4560
public partial class Program { }

dotnet/samples/AGUIClientServer/AGUIServer/Program.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,14 @@
4848
// Map the AG-UI agent endpoint
4949
app.MapAGUI("/", agent);
5050

51+
app.MapAGUI("/agents/{agentId}", async (context) =>
52+
{
53+
var agentId = context.Request.RouteValues["agentId"]?.ToString() ?? string.Empty;
54+
return agentId switch
55+
{
56+
"0" => agent,
57+
_ => throw new ArgumentException($"Unknown agent ID: {agentId}"),
58+
};
59+
});
60+
5161
await app.RunAsync();

dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIEndpointRouteBuilderExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3+
using System;
34
using System.Collections.Generic;
45
using System.Diagnostics.CodeAnalysis;
56
using System.Linq;
67
using System.Threading;
8+
using System.Threading.Tasks;
79
using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.Shared;
810
using Microsoft.AspNetCore.Builder;
911
using Microsoft.AspNetCore.Http;
@@ -32,6 +34,21 @@ public static IEndpointConventionBuilder MapAGUI(
3234
this IEndpointRouteBuilder endpoints,
3335
[StringSyntax("route")] string pattern,
3436
AIAgent aiAgent)
37+
{
38+
return endpoints.MapAGUI(pattern, _ => ValueTask.FromResult(aiAgent));
39+
}
40+
41+
/// <summary>
42+
/// Maps an AG-UI agent endpoint.
43+
/// </summary>
44+
/// <param name="endpoints">The endpoint route builder.</param>
45+
/// <param name="pattern">The URL pattern for the endpoint.</param>
46+
/// <param name="aiAgentSelector">A function to select the agent instance based on the HTTP context.</param>
47+
/// <returns>An <see cref="IEndpointConventionBuilder"/> for the mapped endpoint.</returns>
48+
public static IEndpointConventionBuilder MapAGUI(
49+
this IEndpointRouteBuilder endpoints,
50+
[StringSyntax("route")] string pattern,
51+
Func<HttpContext, ValueTask<AIAgent>> aiAgentSelector)
3552
{
3653
return endpoints.MapPost(pattern, async ([FromBody] RunAgentInput? input, HttpContext context, CancellationToken cancellationToken) =>
3754
{
@@ -63,6 +80,9 @@ public static IEndpointConventionBuilder MapAGUI(
6380
}
6481
};
6582

83+
// Determine the agent to use
84+
var aiAgent = await aiAgentSelector(context).ConfigureAwait(false);
85+
6686
// Run the agent and convert to AG-UI events
6787
var events = aiAgent.RunStreamingAsync(
6888
messages,

dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ public void MapAGUIAgent_MapsEndpoint_AtSpecifiedPattern()
4444
Assert.NotNull(result);
4545
}
4646

47+
[Fact]
48+
public void MapAGUIAgent_MapsEndpoint_WithOnDemandAgentSelection()
49+
{
50+
// Arrange
51+
Mock<IEndpointRouteBuilder> endpointsMock = new();
52+
Mock<IServiceProvider> serviceProviderMock = new();
53+
54+
endpointsMock.Setup(e => e.ServiceProvider).Returns(serviceProviderMock.Object);
55+
endpointsMock.Setup(e => e.DataSources).Returns([]);
56+
57+
const string Pattern = "/api/agent";
58+
AIAgent agent = new TestAgent();
59+
60+
// Act
61+
IEndpointConventionBuilder? result = AGUIEndpointRouteBuilderExtensions.MapAGUI(endpointsMock.Object, Pattern, (httpContext) => ValueTask.FromResult(agent));
62+
63+
// Assert
64+
Assert.NotNull(result);
65+
}
66+
4767
[Fact]
4868
public async Task MapAGUIAgent_WithNullOrInvalidInput_Returns400BadRequestAsync()
4969
{

0 commit comments

Comments
 (0)