A2A Protocol

A2A .NET SDK Comprehensive Documentation

MILO
Share
A2A .NET SDK Comprehensive Documentation

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

  1. A2A Core Library: Contains the core protocol implementation
  2. A2A.AspNetCore: Provides ASP.NET Core integration
  3. 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:

  1. JSON-RPC Communication: All communication is conducted through JSON-RPC protocol
  2. Streaming Response: Supports Server-Sent Events (SSE) for real-time streaming
  3. Serialization Optimization: Uses System.Text.Json source generators for high-performance serialization
  4. 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:

  1. Task Lifecycle Management: Create, update, cancel tasks
  2. Message Processing: Handle incoming messages and task updates
  3. Event Distribution: Manage task state change events
  4. 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 content
  • FilePart: File content
  • DataPart: 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:

  1. EchoAgent: Simple echo agent
  2. EchoAgentWithTasks: Echo agent with task support
  3. HostedClientAgent: Hosted client agent
  4. 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

  1. Clone the project:

    git clone https://github.com/a2aproject/a2a-dotnet
    cd a2a-dotnet
    
  2. Navigate to example directory:

    cd samples/AgentServer
    
  3. Run the project:

    dotnet run
    
  4. Verify service is running: The service will start on the following ports:

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 messages
  • OnTaskCreated: Task creation events
  • OnTaskUpdated: Task update events
  • OnTaskCancelled: 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

  1. Source-Generated Serialization: Uses System.Text.Json source generators
  2. AOT Compatibility: Supports Native AOT compilation
  3. Asynchronous Processing: Comprehensive use of async/await patterns
  4. 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

  1. Standardized Protocol: Based on Google's A2A Protocol standard
  2. Easy Integration: Simple ASP.NET Core integration
  3. Flexible Architecture: Supports multiple agent implementation patterns
  4. High Performance: Optimized serialization and asynchronous processing
  5. Observability: Built-in telemetry and monitoring support
  6. Extensibility: Abstract interfaces support custom implementations

11.2 Use Cases

  1. AI Agent Systems: Building intelligent agent interaction systems
  2. Microservice Architecture: Intelligent communication between services
  3. Workflow Engines: Agent-based processing of complex business processes
  4. Chatbots: Multi-agent collaborative dialogue systems

11.3 Future Development

  1. Push Notifications: Complete client callback support
  2. More Storage Backends: Database and distributed storage support
  3. Security Enhancements: More comprehensive authentication and authorization mechanisms
  4. Protocol Updates: Keep up with the latest versions of A2A Protocol

11.4 Development Recommendations

  1. Start Simple: Use EchoAgent to understand basic concepts
  2. Understand State Management: Study ResearcherAgent's state machine implementation
  3. Emphasize Error Handling: Implement comprehensive error handling and recovery mechanisms
  4. Monitoring and Debugging: Utilize OpenTelemetry for system monitoring
  5. 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.