-
Notifications
You must be signed in to change notification settings - Fork 4k
.Net: Initial check-in for the A2A Agent implementation #12050
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: Initial check-in for the A2A Agent implementation #12050
Conversation
Hi @hansmbakker |
|
||
<ItemGroup> | ||
<PackageReference Include="SharpA2A.Core" /> | ||
<PackageReference Include="SharpA2A.AspNetCore" /> |
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.
Do we need the asp.net package in the client? I would have expected it's only required for the server?
|
||
// Connect to the remote agents via A2A | ||
var createAgentTasks = agentUrls.Select(agentUrl => this.CreateAgentAsync(agentUrl)); | ||
var agents = await Task.WhenAll(createAgentTasks); |
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.
Might be nice to also have a basic example where we are interacting directly with a single A2AAgent instance.
This multiagent sample is also great and we should keep it. I'm just thinking it might be easier for people to grasp a single agent one first.
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.
I see you have a single agent demonstration under samples, so maybe this isn't necessary here then after all.
resolution in SAP CRM and notify the customer via email within 2 business days, referencing the | ||
original invoice and the credit memo number. Use the 'Formal Credit Notification' email | ||
template." | ||
Always reply with exactly this text: |
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.
Is this text intentionally repeated?
|
||
1. Run the A2A client: | ||
```bash | ||
cd A2AClient |
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.
Here we are already in the A2AClient directory
/// <param name="client">A2AClient instance to associate with the agent.</param> | ||
/// <param name="agentCard">AgentCard instance associated ith the agent.</param> |
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.
/// <param name="client">A2AClient instance to associate with the agent.</param> | |
/// <param name="agentCard">AgentCard instance associated ith the agent.</param> | |
/// <param name="client"><see cref="A2AClient"/> instance to associate with the agent.</param> | |
/// <param name="agentCard"><see cref="AgentCard"/> instance associated with the agent.</param> |
} | ||
} | ||
|
||
private async IAsyncEnumerable<AgentResponseItem<ChatMessageContent>> InvokeAgentAsync(string name, ChatMessageContent message, A2AAgentThread thread, AgentInvokeOptions options, [EnumeratorCancellation] CancellationToken cancellationToken) |
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.
I don't see the name param being used in the method. Am I missing something?
this.AgentCard = agentCard; | ||
this.Name = agentCard.Name; | ||
this.Description = agentCard.Description; |
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.
It doesn't look like these are required to ensure the functioning of the Agent. Could we make agentCard optional?
.Build(); | ||
var apiKey = configRoot["A2AClient:ApiKey"] ?? throw new ArgumentException("A2AClient:ApiKey must be provided"); | ||
var modelId = configRoot["A2AClient:ModelId"] ?? "gpt-4.1"; | ||
var agentUrls = configRoot["A2AClient:AgentUrls"] ?? "http://localhost:5000/ http://localhost:5001/ http://localhost:5002/"; |
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.
nit: Wondering if comma separator or ;
will work as well here, since space separator is a little bit unclear.
this._httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); | ||
|
||
// Create a retry policy for transient HTTP errors | ||
this._retryPolicy = Policy |
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.
nit: I would configure retry policy on HttpClient
level, so CurrencyPlugin
will be decoupled from HTTP-related logic, but since it's a demo app, it's not critical, so feel free to skip.
{ | ||
Verify.NotNull(messages); | ||
|
||
foreach (var message in messages) |
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.
Mmm, this is interesting. In the CopilotChatAgent we concatenate the input messages and invoke once where here we invoke for each message.
For inference type agents we invoke once with all messages too, so they are processed in one go. Not sure if we want to follow that approach everywhere.
}; | ||
|
||
A2AResponse response = await this.Client.SendMessageAsync(messageSendParams).ConfigureAwait(false); | ||
if (response is AgentTask agentTask) |
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.
What's an AgentTask?
/// <summary> | ||
/// Gets the session id of the current thread. | ||
/// </summary> | ||
public string SessionId { get; init; } |
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.
Do we need SessionId as well if we already have id?
/// Attach the <see cref="A2AAgent"/> to the provided <see cref="ITaskManager"/> | ||
/// </summary> | ||
/// <param name="taskManager"></param> | ||
public void Attach(ITaskManager taskManager) |
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.
Looks like you need a new TaskManager instance for each agent instance. Do we think it would be necessary to add the same agent to multiple task managers? It doesn't look like that's supported since we only have one taskmanager field here.
It might be easier for the consumer if we just wrapped the TaskManager in the A2AHostAgent, so that the consumer doesn't have to know about it.
And maybe add an extension method for just mapping an Agent like this:
app.MapA2A(myA2AHostAgent);
|
||
namespace A2A; | ||
|
||
internal abstract class AzureAIHostAgent : A2AHostAgent |
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.
Instead of inheriting from A2AHostAgent also consider instantiating an A2AHostAgent with an Agent instance, so it is just a standalone utility. Forcing users to inherit from A2AHostAgent to get the adapter functionality seems somewhat opinionated to me.
I can see a case where we may just want to support:
var myA2AAgent = myAgent.ToA2AAgent(card);
app.MapA2A(myA2AAgent);
using System.Diagnostics.CodeAnalysis; | ||
|
||
// This assembly is currently experimental. | ||
[assembly: Experimental("SKEXP0110")] |
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.
Isn't this implied by it being alpha?
Motivation and Context
Description
Contribution Checklist