-
Notifications
You must be signed in to change notification settings - Fork 45
Description
Is your feature request related to a problem? Please describe.
There currently seems to be a limitation that you have to know which agent you want to host when the app starts, and you can only host a single one.
This makes the following - very powerful - scenario impossible (from my limited understanding of how the SDK is currently implemented).
Suppose you need to create an enterprise application, or SaaS product, enabling business users to build their own agents using a drag & drop (or similar) UI. Basically AI agents that are generated from configuration, instead of hard-coded by developers using the SDK.
This should be fully possible (as I see it), however, the current implementation of the SDK does not make it possible because you cannot on a pr request basis resolve and execute dynamically generated AI agents based on the url. For example, you currently have to pass in the TaskManager to the MapA2A methods, but the TaskManager.OnMessageReceived does not provide information about the url. This makes sense from a point of view where there's a 1:1 mapping between a TaskManager and agent - which probably is by design.
Describe the solution you'd like
I would like to be able to host dynamically generated AI agents. I want to dynamically serve the agent card, and process the requests, based on the incoming request.
For example, I would like to do something like this:
public static IEndpointConventionBuilder MyMapA2A(this WebApplication app)
{
app.MapA2A("/a2a/tenants/{tenantId}/workspaces/{workspaceId}/agents/{agentId}");
var routeGroup = app.MapGroup("/a2a/tenants/{tenantId}/workspaces/{workspaceId}/agents/{agentId}");
routeGroup.MapGet(".well-known/agent-card.json", async (MyAgentCardService myService, HttpRequest request, CancellationToken cancellationToken) =>
{
// quick and dirty hack to remove the well-known part
var path = request.Path.ToString().Replace("/.well-known/agent-card.json", "");
var agentUrl = $"{request.Scheme}://{request.Host}{path}";
var agentCard = await myService.BuildAgentCardAsync(agentUrl, cancellationToken);
return Results.Ok(agentCard);
});
return routeGroup;
}This is almost possible today, but not quite. If A2AJsonRpcProcessor.ProcessRequestAsync was public, I could create a task manager pr request or agent, and do something like this:
public class DynamicAgentRoutingMiddleware
{
private readonly RequestDelegate _next;
private readonly IAgentFactory _agentFactory;
private readonly ConcurrentDictionary<string, ITaskManager> _taskManagers = new();
public DynamicAgentRoutingMiddleware(
RequestDelegate next,
IAgentFactory agentFactory)
{
_next = next;
_agentFactory = agentFactory;
}
public async Task InvokeAsync(HttpContext context)
{
// Extract agent identifier from request
var agentId = context.Request.RouteValues["agentId"]?.ToString();
if (string.IsNullOrEmpty(agentId))
{
await _next(context);
return;
}
// Resolve or create task manager for this agent
var taskManager = _taskManagers.GetOrAdd(agentId, id =>
{
var tm = new TaskManager();
var agent = _agentFactory.CreateAgent(id);
agent.Attach(tm);
return tm;
});
// Store task manager in HttpContext for use by endpoints
context.Items["TaskManager"] = taskManager;
await _next(context);
}
}
// In Program.cs
app.UseMiddleware<DynamicAgentRoutingMiddleware>();
app.MapPost("/a2a/tenants/{tenantId}/workspaces/{workspaceId}/agents/{agentId}", async (
HttpContext context,
HttpRequest request,
CancellationToken cancellationToken) =>
{
var taskManager = (ITaskManager)context.Items["TaskManager"]!;
// Not a public API, so I can't do this
return await A2AJsonRpcProcessor.ProcessRequestAsync(
taskManager,
request,
cancellationToken);
});Describe alternatives you've considered
No response
Additional context
No response
Code of Conduct
- I agree to follow this project's Code of Conduct