Skip to content

EmilLindfors/a2a-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

42 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

A2A-RS - Agent-to-Agent Protocol Implementation for Rust

Crates.io Documentation License: MIT

A comprehensive Rust implementation of the Agent-to-Agent (A2A) Protocol, providing both a robust framework library and practical agent examples. This project demonstrates production-ready agent communication with modern Rust practices and hexagonal architecture.

🎯 Quick Start - Try the Reimbursement Agent

See the A2A protocol in action with our reimbursement agent - a complete example that handles expense reimbursement requests:

# Clone the repository
git clone https://github.com/emillindfors/a2a-rs.git
cd a2a-rs

# Run the reimbursement agent
cd a2a-agents
cargo run --bin reimbursement_server

The reimbursement agent showcases:

  • πŸ’¬ Interactive conversations with users about expenses
  • πŸ“‹ Dynamic form generation for expense submissions
  • βœ… Request validation and approval workflows
  • πŸ“Š Structured responses with proper task state management
  • πŸ”„ Real-time updates via the A2A protocol

Try it out: Send a POST request to http://localhost:3030/sendMessage with a reimbursement question!

πŸ—οΈ Project Structure

This repository contains a complete A2A ecosystem:

πŸ“¦ a2a-rs - Core Framework Library

The main library published on crates.io:

  • πŸš€ Complete A2A Protocol Implementation
  • πŸ”„ HTTP & WebSocket Support with streaming
  • πŸ›οΈ Hexagonal Architecture with clean separation
  • 🧩 Modular Features - use only what you need
  • πŸ“š Comprehensive Documentation with examples

πŸ€– a2a-agents - Production Agent Examples

Real-world agent implementations demonstrating best practices:

  • πŸ’° Reimbursement Agent - Handles expense requests with interactive workflows
  • πŸ”§ Modern Architecture using the a2a-rs framework
  • πŸ“– Full Documentation with setup guides

πŸ”Œ a2a-mcp - MCP Integration

Bridges A2A agents with the Model Context Protocol ecosystem:

  • πŸŒ‰ Bidirectional Integration - A2A agents as MCP tools and vice versa
  • πŸ”— Protocol Translation between A2A and MCP formats
  • πŸ› οΈ Developer Tools for cross-protocol communication

πŸ’» a2a-client - Web Interface

Browser-based client for interacting with A2A agents:

  • 🌐 Web UI for agent communication
  • πŸ’¬ Chat Interface with real-time updates
  • πŸ“± Responsive Design for all devices

✨ Key Features

🎯 Framework Library (a2a-rs)

  • Type-Safe Protocol - Rust's type system ensures protocol compliance
  • Async-First Design - Built on Tokio with full async/await support
  • Multiple Transports - HTTP, WebSocket with automatic fallback
  • Streaming Support - Real-time task updates and progress tracking
  • Authentication - JWT, OAuth2, OpenID Connect, API keys
  • Storage Backends - SQLx integration for PostgreSQL, MySQL, SQLite
  • Observability - Structured logging and tracing throughout

πŸ€– Agent Examples

  • Production Ready - Complete implementations following best practices
  • Interactive Workflows - Dynamic form generation and multi-step processes
  • Business Logic Examples - Real use cases like expense reimbursement
  • Framework Integration - Shows how to use a2a-rs effectively

πŸ”§ Developer Experience

  • Comprehensive Documentation - API docs, guides, and examples
  • Working Examples - Copy-paste code that actually works
  • Test Coverage - Integration tests and property-based testing
  • Error Handling - Structured errors with helpful messages

πŸš€ Quick Integration

Add to your Cargo.toml:

[dependencies]
a2a-rs = "0.1.0"

# For HTTP client
a2a-rs = { version = "0.1.0", features = ["http-client"] }

# For HTTP server  
a2a-rs = { version = "0.1.0", features = ["http-server"] }

# Everything
a2a-rs = { version = "0.1.0", features = ["full"] }

Simple Client Example

use a2a_rs::{HttpClient, Message};
use a2a_rs::port::AsyncA2AClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = HttpClient::new("http://localhost:3030".to_string());
    
    let message = Message::user_text("I need to submit a $50 lunch expense".to_string());
    let task = client.send_task_message("task-123", &message, None, None).await?;
    
    println!("Response: {:?}", task);
    Ok(())
}

Simple Server Example

use a2a_rs::{HttpServer, SimpleAgentInfo, DefaultRequestProcessor};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = HttpServer::new(
        DefaultRequestProcessor::new(),
        SimpleAgentInfo::new("my-agent".to_string(), "1.0.0".to_string()),
        "127.0.0.1:3030".to_string(),
    );
    
    server.start().await?;
    Ok(())
}

πŸŽͺ Advanced Examples

Streaming Client with WebSocket

use a2a_rs::{WebSocketClient, Message};
use a2a_rs::services::StreamItem;
use futures::StreamExt;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = WebSocketClient::new("ws://localhost:3030/ws".to_string());
    
    let message = Message::user_text("Process my reimbursement request".to_string());
    let mut stream = client.subscribe_to_task("task-456", &message, None, None).await?;
    
    while let Some(result) = stream.next().await {
        match result? {
            StreamItem::Task(task) => println!("Initial task: {:?}", task),
            StreamItem::StatusUpdate(update) => {
                println!("Status: {:?}", update);
                if update.final_ { break; }
            }
            StreamItem::ArtifactUpdate(artifact) => {
                println!("New artifact: {:?}", artifact);
            }
        }
    }
    
    Ok(())
}

πŸ›οΈ Architecture

The project follows hexagonal architecture principles:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Application Layer                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  JSON-RPC       β”‚    β”‚     HTTP/WebSocket          β”‚ β”‚
β”‚  β”‚  Handlers       β”‚    β”‚     Transport               β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Port Layer                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ MessageHandler   β”‚    β”‚  StreamingHandler       β”‚   β”‚
β”‚  β”‚ TaskManager      β”‚    β”‚  NotificationManager    β”‚   β”‚
β”‚  β”‚ Authenticator    β”‚    β”‚  RequestProcessor       β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚                       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Domain Layer                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚   Message    β”‚ β”‚     Task     β”‚ β”‚   AgentCard     β”‚  β”‚
β”‚  β”‚   Artifact   β”‚ β”‚ TaskStatus   β”‚ β”‚ Capabilities    β”‚  β”‚
β”‚  β”‚     Part     β”‚ β”‚   History    β”‚ β”‚    Skills       β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“š Documentation

πŸ§ͺ Testing

# Test the core library
cd a2a-rs && cargo test --all-features

# Test agent examples  
cd a2a-agents && cargo test

# Test MCP integration
cd a2a-mcp && cargo test

# Run integration tests
cargo test --workspace

πŸ›£οΈ Roadmap

  • Core Protocol - Complete A2A specification implementation
  • Documentation - Comprehensive docs and examples
  • Agent Examples - Production-ready reimbursement agent
  • MCP Integration - Cross-protocol compatibility
  • More Agent Types - Additional domain examples
  • Performance Optimization - Benchmarking and improvements
  • Advanced Auth - Enterprise authentication patterns

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/emillindfors/a2a-rs.git
cd a2a-rs
cargo build --workspace
cargo test --workspace

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

🌟 Showcase

Built with a2a-rs? We'd love to feature your project! Open an issue to let us know.


Ready to build intelligent agents? Start with our reimbursement agent example or dive into the core library documentation!

About

Agent2Agent in Rust

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages