1. Project Overview
The A2A (Agent2Agent) .NET SDK is a .NET library that implements Google's A2A Protocol v0.2.1, enabling agent-to-agent communication in .NET applications. This SDK is designed to work with ASP.NET Core applications, providing a simple way to add A2A support to your agents.
Key Features
- Protocol Compatibility: Implements most features of A2A Protocol v0.2.1
- Multi-Framework Support: Supports .NET 9.0, .NET 8.0, and .NET Standard 2.0
- ASP.NET Core Integration: Provides simple integration methods
- Task Management: Standardized task management and execution support
- Streaming: Supports real-time streaming responses
- OpenTelemetry: Built-in telemetry and observability support
Project Status
The library has implemented most of the protocol features, but some scenarios may still be incomplete. The biggest missing feature is client callbacks using push notifications.
2. A2A .NET Core Architecture
2.1 Project Structure
src/
├── A2A/ # Core A2A protocol implementation
│ ├── Client/ # Client components
│ ├── JsonRpc/ # JSON-RPC implementation
│ ├── Models/ # Data models
│ ├── Server/ # Server-side components
│ └── openapi.yaml # API specification
└── A2A.AspNetCore/ # ASP.NET Core integration
2.2 Core Components
- A2A Core Library: Contains the core protocol implementation
- A2A.AspNetCore: Provides ASP.NET Core integration
- Sample Projects: Example code demonstrating different usage scenarios
3. A2A .NET Client Implementation
3.1 A2AClient Class
The A2AClient
class is the main client interface for communicating with agents, implementing the IA2AClient
interface.
Main Functions:
public class A2AClient : IA2AClient
{
// Send message
public Task<A2AResponse> SendMessageAsync(MessageSendParams taskSendParams)
// Get task
public Task<AgentTask> GetTaskAsync(string taskId)
// Cancel task
public Task<AgentTask> CancelTaskAsync(TaskIdParams taskIdParams)
// Stream message sending
public async IAsyncEnumerable<SseItem<A2AEvent>> SendMessageStreamAsync(MessageSendParams taskSendParams)
// Resubscribe to task
public async IAsyncEnumerable<SseItem<A2AEvent>> ResubscribeToTaskAsync(string taskId)
}
Key Features:
- JSON-RPC Communication: All communication is conducted through JSON-RPC protocol
- Streaming Response: Supports Server-Sent Events (SSE) for real-time streaming
- Serialization Optimization: Uses System.Text.Json source generators for high-performance serialization
- Error Handling: Complete error handling and state management
3.2 JsonRpcContent Class
HTTP content class specifically for JSON-RPC requests:
public class JsonRpcContent : HttpContent
{
public JsonRpcContent(JsonRpcRequest request)
{
_request = request;
Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
}
3.3 A2ACardResolver Class
Used for parsing and retrieving agent card information:
public class A2ACardResolver
{
public async Task<AgentCard> GetAgentCardAsync(Uri agentUri)
public async Task<AgentCard> GetAgentCardAsync(string agentUrl)
}
4. A2A .NET Server Implementation
4.1 TaskManager Class
TaskManager
is the core server-side component responsible for managing task lifecycles.
Main Responsibilities:
- Task Lifecycle Management: Create, update, cancel tasks
- Message Processing: Handle incoming messages and task updates
- Event Distribution: Manage task state change events
- Storage Abstraction: Task persistence through
ITaskStore
interface
Core Methods:
public class TaskManager : ITaskManager
{
// Event handlers
public Func<MessageSendParams, Task<Message>>? OnMessageReceived { get; set; }
public Func<AgentTask, Task> OnTaskCreated { get; set; }
public Func<AgentTask, Task> OnTaskCancelled { get; set; }
public Func<AgentTask, Task> OnTaskUpdated { get; set; }
public Func<string, AgentCard> OnAgentCardQuery { get; set; }
// Core operations
public async Task<AgentTask> CreateTaskAsync(string? contextId = null)
public async Task<AgentTask?> CancelTaskAsync(TaskIdParams? taskIdParams)
public async Task<A2AResponse?> SendMessageAsync(MessageSendParams messageSendParams)
public async Task<IAsyncEnumerable<A2AEvent>> SendMessageStreamAsync(MessageSendParams messageSendParams)
public async Task UpdateStatusAsync(string taskId, TaskState status, Message? message = null, bool final = false)
public async Task ReturnArtifactAsync(string taskId, Artifact artifact)
}
4.2 ITaskStore Interface
Abstract interface for task storage:
public interface ITaskStore
{
Task<AgentTask?> GetTaskAsync(string taskId);
Task SetTaskAsync(AgentTask task);
Task UpdateStatusAsync(string taskId, TaskState status);
}
4.3 ASP.NET Core Integration
Through extension methods provided by the A2A.AspNetCore
library:
// Add JSON-RPC A2A support
app.MapA2A(taskManager, "/echo");
// Add HTTP A2A support
app.MapHttpA2A(taskManager, "/echo");
5. A2A .NET Data Models
5.1 Core Model Classes
AgentCard - Agent Card
public class AgentCard
{
public string Name { get; set; } // Agent name
public string Description { get; set; } // Agent description
public string Url { get; set; } // Agent URL
public AgentProvider? Provider { get; set; } // Provider information
public string Version { get; set; } // Version information
public AgentCapabilities Capabilities { get; set; } // Agent capabilities
public List<AgentSkill> Skills { get; set; } // Agent skills
public List<string> DefaultInputModes { get; set; } // Default input modes
public List<string> DefaultOutputModes { get; set; }// Default output modes
}
AgentTask - Agent Task
public class AgentTask : A2AResponse
{
public string Id { get; set; } // Task ID
public string? ContextId { get; set; } // Context ID
public AgentTaskStatus Status { get; set; } // Task status
public List<Artifact>? Artifacts { get; set; } // Task artifacts
public List<Message>? History { get; set; } // Message history
public Dictionary<string, JsonElement>? Metadata { get; set; } // Metadata
}
Message - Message
public class Message : A2AResponse
{
public MessageRole Role { get; set; } // Message role (User/Agent)
public List<Part> Parts { get; set; } // Message parts
public string? MessageId { get; set; } // Message ID
public string? TaskId { get; set; } // Associated task ID
public string? ContextId { get; set; } // Context ID
public Dictionary<string, JsonElement>? Metadata { get; set; } // Metadata
}
5.2 Task States
public enum TaskState
{
Submitted, // Submitted
Working, // Working
InputRequired, // Input required
Completed, // Completed
Canceled, // Canceled
Failed, // Failed
Rejected // Rejected
}
5.3 Message Part Types
Supports multiple message part types:
TextPart
: Text contentFilePart
: File contentDataPart
: Data content
6. A2A .NET AgentServer Example Detailed Analysis
6.1 Project Overview
The AgentServer example demonstrates how to create and deploy multiple different types of agents, including:
- EchoAgent: Simple echo agent
- EchoAgentWithTasks: Echo agent with task support
- HostedClientAgent: Hosted client agent
- ResearcherAgent: Researcher agent (state machine implementation)
6.2 EchoAgent Implementation
public class EchoAgent
{
private ITaskManager? _taskManager;
public void Attach(TaskManager taskManager)
{
_taskManager = taskManager;
taskManager.OnMessageReceived = ProcessMessage;
taskManager.OnAgentCardQuery = GetAgentCard;
}
public Task<Message> ProcessMessage(MessageSendParams messageSendParams)
{
var messageText = messageSendParams.Message.Parts.OfType<TextPart>().First().Text;
var message = new Message()
{
Role = MessageRole.Agent,
MessageId = Guid.NewGuid().ToString(),
ContextId = messageSendParams.Message.ContextId,
Parts = [new TextPart() { Text = $"Echo: {messageText}" }]
};
return Task.FromResult(message);
}
}
6.3 ResearcherAgent Implementation
ResearcherAgent demonstrates a more complex state machine implementation:
public class ResearcherAgent
{
private enum AgentState
{
Planning, // Planning phase
WaitingForFeedbackOnPlan, // Waiting for plan feedback
Researching // Research phase
}
public async Task Invoke(string taskId, string message)
{
switch (_agentStates[taskId])
{
case AgentState.Planning:
await DoPlanning(taskId, message);
break;
case AgentState.WaitingForFeedbackOnPlan:
if (message == "go ahead")
await DoResearch(taskId, message);
else
await DoPlanning(taskId, message);
break;
case AgentState.Researching:
await DoResearch(taskId, message);
break;
}
}
}
7. How to Run AgentServer Example
7.1 Environment Requirements
- .NET 9.0 SDK or higher
- Optional: OpenTelemetry Collector (for telemetry data)
7.2 Running Steps
-
Clone the project:
git clone https://github.com/a2aproject/a2a-dotnet cd a2a-dotnet
-
Navigate to example directory:
cd samples/AgentServer
-
Run the project:
dotnet run
-
Verify service is running: The service will start on the following ports:
- HTTP: http://localhost:5048
- HTTPS: https://localhost:7014
7.3 Available Endpoints
/echo
- Simple echo agent/echotasks
- Echo agent with task support/hostedclient
- Hosted client agent/researcher
- Researcher agent
7.4 Testing API Calls
Get Agent Card
curl -X GET http://localhost:5048/echo/.well-known/agent.json
Send Message to Echo Agent
curl -X POST http://localhost:5048/echo \
-H "Content-Type: application/json" \
-d '{
"id": "1",
"jsonrpc": "2.0",
"method": "message/send",
"params": {
"message": {
"messageId": "12345",
"role": "user",
"parts": [
{
"kind": "text",
"text": "Hello, world!"
}
]
}
}
}'
Create Researcher Agent Task
curl -X POST http://localhost:5048/researcher \
-H "Content-Type: application/json" \
-d '{
"id": "1",
"jsonrpc": "2.0",
"method": "message/send",
"params": {
"message": {
"messageId": "research-1",
"role": "user",
"parts": [
{
"kind": "text",
"text": "Research the current price of butter"
}
]
}
}
}'
8. Sequence Diagrams
8.1 Simple Message Processing Sequence Diagram
sequenceDiagram
participant Client as Client
participant Server as A2A Server
participant Agent as Agent Implementation
participant TaskMgr as TaskManager
Client->>Server: POST /echo (JSON-RPC message/send)
Server->>TaskMgr: SendMessageAsync()
TaskMgr->>Agent: OnMessageReceived()
Agent->>Agent: ProcessMessage()
Agent-->>TaskMgr: Return Message
TaskMgr-->>Server: Return A2AResponse
Server-->>Client: JSON-RPC Response
8.2 Task Processing Sequence Diagram
sequenceDiagram
participant Client as Client
participant Server as A2A Server
participant TaskMgr as TaskManager
participant Agent as Agent Implementation
participant Store as TaskStore
Client->>Server: POST /researcher (message/send)
Server->>TaskMgr: SendMessageAsync()
TaskMgr->>TaskMgr: CreateTaskAsync()
TaskMgr->>Store: SetTaskAsync()
TaskMgr->>Agent: OnTaskCreated()
Agent->>Agent: State Change (Planning)
Agent->>TaskMgr: UpdateStatusAsync(Working)
TaskMgr->>Store: UpdateStatusAsync()
Agent->>TaskMgr: ReturnArtifactAsync()
Agent->>TaskMgr: UpdateStatusAsync(InputRequired)
TaskMgr-->>Server: Return AgentTask
Server-->>Client: JSON-RPC Response
Note over Client,Store: Client sends follow-up message
Client->>Server: POST /researcher (message/send, taskId)
Server->>TaskMgr: SendMessageAsync()
TaskMgr->>Store: GetTaskAsync()
TaskMgr->>Agent: OnTaskUpdated()
Agent->>Agent: State processing logic
Agent->>TaskMgr: UpdateStatusAsync(Completed)
TaskMgr-->>Server: Return AgentTask
Server-->>Client: JSON-RPC Response
8.3 Streaming Processing Sequence Diagram
sequenceDiagram
participant Client as Client
participant Server as A2A Server
participant TaskMgr as TaskManager
participant Agent as Agent Implementation
Client->>Server: POST /echo (JSON-RPC message/stream)
Server->>TaskMgr: SendMessageStreamAsync()
TaskMgr->>Agent: OnMessageReceived()
loop Streaming Response
Agent->>TaskMgr: Generate Event
TaskMgr->>Server: A2AEvent
Server->>Client: Server-Sent Event
end
Agent->>TaskMgr: Complete Processing
TaskMgr->>Server: End Stream
Server->>Client: Close Connection
9. A2A .NET Key Design Patterns
9.1 Event-Driven Architecture
TaskManager uses event-driven patterns:
OnMessageReceived
: Handle incoming messagesOnTaskCreated
: Task creation eventsOnTaskUpdated
: Task update eventsOnTaskCancelled
: Task cancellation events
9.2 Strategy Pattern
Different agent implementations can have different processing strategies:
- Stateless processing (EchoAgent)
- Stateful processing (ResearcherAgent)
- Task-oriented processing (EchoAgentWithTasks)
9.3 Storage Abstraction
Task storage abstracted through ITaskStore
interface:
InMemoryTaskStore
: In-memory storage implementation- Extensible to database storage implementations
10. A2A .NET Performance and Observability
10.1 Performance Optimization
- Source-Generated Serialization: Uses System.Text.Json source generators
- AOT Compatibility: Supports Native AOT compilation
- Asynchronous Processing: Comprehensive use of async/await patterns
- Streaming Processing: Supports large data volume streaming
10.2 Observability
Integrated OpenTelemetry support:
- Distributed Tracing: ActivitySource integration
- Metrics Collection: Task status and performance metrics
- Logging: Structured logging support
// OpenTelemetry configuration example
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource(TaskManager.ActivitySource.Name)
.AddSource(A2AJsonRpcProcessor.ActivitySource.Name)
.AddConsoleExporter()
.AddOtlpExporter());
11. A2A .NET Summary
The A2A .NET SDK provides a complete, production-ready solution for implementing agent-to-agent communication in .NET applications.
11.1 Main Advantages
- Standardized Protocol: Based on Google's A2A Protocol standard
- Easy Integration: Simple ASP.NET Core integration
- Flexible Architecture: Supports multiple agent implementation patterns
- High Performance: Optimized serialization and asynchronous processing
- Observability: Built-in telemetry and monitoring support
- Extensibility: Abstract interfaces support custom implementations
11.2 Use Cases
- AI Agent Systems: Building intelligent agent interaction systems
- Microservice Architecture: Intelligent communication between services
- Workflow Engines: Agent-based processing of complex business processes
- Chatbots: Multi-agent collaborative dialogue systems
11.3 Future Development
- Push Notifications: Complete client callback support
- More Storage Backends: Database and distributed storage support
- Security Enhancements: More comprehensive authentication and authorization mechanisms
- Protocol Updates: Keep up with the latest versions of A2A Protocol
11.4 Development Recommendations
- Start Simple: Use EchoAgent to understand basic concepts
- Understand State Management: Study ResearcherAgent's state machine implementation
- Emphasize Error Handling: Implement comprehensive error handling and recovery mechanisms
- Monitoring and Debugging: Utilize OpenTelemetry for system monitoring
- Test-Driven: Write comprehensive unit tests and integration tests
This SDK provides .NET developers with a powerful and flexible platform for building next-generation intelligent agent systems. Through its clear architecture and rich examples, developers can quickly get started and build complex agent-to-agent communication applications.