Skip to content

[Feat]: Refactor A2ARouteBuilderExtensions to leverage dependency injection #185

@cdavernas

Description

@cdavernas

Is your feature request related to a problem? Please describe.

Currently, all methods in A2ARouteBuilderExtensions require explicitly passing an ITaskManager. This feels awkward and clutters otherwise clean .NET application code.

Describe the solution you'd like

I’d like A2ARouteBuilderExtensions to resolve the ITaskManager from the request’s IServiceProvider. As far as I know, it’s already established that a server application can only host a single agent, due to restrictions around well-known documents that must be rooted. Consequently, we can safely assume only one ITaskManager will ever be registered—likely through a new IServiceCollection.AddA2A extension. This makes dependency injection the natural choice.

With this change, we could eliminate the awkward Attach pattern and instead allow handler registration directly in the agent’s constructor, resulting in cleaner, more idiomatic .NET code.

Describe alternatives you've considered

Doing something ugly like the following:

var taskManager = new TaskManager(); // <= this should have been registered/constructured through DI instead
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
builder.Services.AddSingleton<ITaskManager>(taskManager);
builder.Services.AddSingleton<Agent>();

var app = builder.Build();
app.Services.GetRequiredService<Agent>(); // <- this ugly trick is required, so that my agent is actually constructured before someone hits the discovery endpoint, thus registering the TaskManager's handlers
app.MapA2A(taskManager, "/chat"); // <= this shouldn't require passing the TaskManager, and differs from 99% of .NET extensions
app.MapWellKnownAgentCard(taskManager, "/chat"); // <= this shouldn't require passing the TaskManager, and differs from 99% of .NET extensions
await app.RunAsync();
public class Agent
{

    ITaskManager _taskManager;

    public Agent(ITaskManager taskManager)
    {
        _taskManager = taskManager;
        _taskManager.OnTaskCreated = ExecuteTaskAsync;
        _taskManager.OnTaskUpdated = ExecuteTaskAsync;
        _taskManager.OnMessageReceived = ProcessMessageAsync;
        _taskManager.OnTaskCancelled = CancelTaskAsync;
        _taskManager.OnAgentCardQuery = GetCardAsync;
    }
  
    //Omitted for brevity

}

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions