Some checks are pending
Documentation Lint & Validation / Markdown Linting (push) Waiting to run
Documentation Lint & Validation / Validate mdBook Configuration (push) Waiting to run
Documentation Lint & Validation / Content & Structure Validation (push) Waiting to run
Documentation Lint & Validation / Lint & Validation Summary (push) Blocked by required conditions
mdBook Build & Deploy / Build mdBook (push) Waiting to run
mdBook Build & Deploy / Documentation Quality Check (push) Blocked by required conditions
mdBook Build & Deploy / Deploy to GitHub Pages (push) Blocked by required conditions
mdBook Build & Deploy / Notification (push) Blocked by required conditions
Rust CI / Security Audit (push) Waiting to run
Rust CI / Check + Test + Lint (nightly) (push) Waiting to run
Rust CI / Check + Test + Lint (stable) (push) Waiting to run
6.7 KiB
6.7 KiB
vapora-a2a
Agent-to-Agent (A2A) Protocol Server - Production-ready implementation of the A2A specification for VAPORA.
Features
- ✅ Full A2A Protocol Compliance - JSON-RPC 2.0, Agent Card discovery
- ✅ SurrealDB Persistence - Tasks survive restarts, production-ready storage
- ✅ NATS Async Coordination - Real-time task completion via message queue
- ✅ Prometheus Metrics - Full observability with
/metricsendpoint - ✅ Type-Safe - Rust compile-time guarantees for protocol correctness
- ✅ Integration Tests - 5 comprehensive end-to-end tests
Architecture
┌─────────────────────────────────────────────────┐
│ A2A HTTP Server (Axum) │
│ /.well-known/agent.json | /a2a | /metrics │
└────────────────┬────────────────────────────────┘
│
┌───────┴────────┐
│ │
┌────▼─────┐ ┌──────▼────────┐
│ Bridge │ │ TaskManager │
│ (NATS) │ │ (SurrealDB) │
└────┬─────┘ └──────┬────────┘
│ │
│ ┌──────▼────────┐
└────────►│ AgentCoord │
└───────────────┘
Components
-
CoordinatorBridge - Maps A2A tasks to internal agent coordination
- NATS subscribers for TaskCompleted/TaskFailed events
- DashMap for async result delivery via oneshot channels
- Graceful degradation if NATS unavailable
-
TaskManager - Persistent task storage and lifecycle
- SurrealDB integration with Surreal
- Parameterized queries for security
- Tasks survive server restarts
-
Server - HTTP endpoints (Axum)
GET /.well-known/agent.json- Agent discoveryPOST /a2a- Task dispatchGET /a2a/tasks/{task_id}- Status queryGET /health- Health checkGET /metrics- Prometheus metrics
Quick Start
Prerequisites
# Start SurrealDB
docker run -d -p 8000:8000 \
surrealdb/surrealdb:latest \
start --bind 0.0.0.0:8000
# Start NATS (optional, graceful degradation)
docker run -d -p 4222:4222 nats:latest
# Run migration
surrealdb import --conn ws://localhost:8000 \
--user root --pass root \
migrations/007_a2a_tasks_schema.surql
Run Server
cargo run --bin vapora-a2a -- \
--host 127.0.0.1 \
--port 8003 \
--version 1.0.0
Server will start on http://127.0.0.1:8003
Using the Client
use vapora_a2a_client::{A2aClient, RetryPolicy};
#[tokio::main]
async fn main() {
let client = A2aClient::new("http://localhost:8003");
// Discover agent capabilities
let agent_card = client.discover_agent().await?;
println!("Agent: {} v{}", agent_card.name, agent_card.version);
// Dispatch task
let task_id = client.dispatch_task(
"task-123".to_string(),
"Write hello world function".to_string(),
Some("In Rust".to_string()),
Some("developer".to_string()),
).await?;
// Poll for completion
loop {
let status = client.get_task_status(&task_id).await?;
match status.state.as_str() {
"completed" => {
println!("Result: {:?}", status.result);
break;
}
"failed" => {
eprintln!("Error: {:?}", status.error);
break;
}
_ => tokio::time::sleep(Duration::from_millis(500)).await,
}
}
}
Configuration
Environment Variables
# SurrealDB
SURREAL_URL=ws://localhost:8000
SURREAL_USER=root
SURREAL_PASS=root
# NATS (optional)
NATS_URL=nats://localhost:4222
# Server
A2A_HOST=0.0.0.0
A2A_PORT=8003
A2A_VERSION=1.0.0
CLI Arguments
vapora-a2a \
--host 0.0.0.0 \
--port 8003 \
--version 1.0.0
Metrics
Exposed at http://localhost:8003/metrics in Prometheus text format:
vapora_a2a_tasks_total{status="waiting|working|completed|failed"}- Task countsvapora_a2a_task_duration_seconds{status="completed|failed"}- Task execution timevapora_a2a_nats_messages_total{subject,result}- NATS message handlingvapora_a2a_db_operations_total{operation,result}- Database operationsvapora_a2a_coordinator_assignments_total{skill,result}- Coordinator assignments
Testing
Unit Tests
cargo test -p vapora-a2a --lib
Integration Tests
Require SurrealDB + NATS running:
# Start dependencies
docker compose up -d surrealdb nats
# Run tests
cargo test -p vapora-a2a --test integration_test -- --ignored
# Tests:
# 1. Task persistence after restart
# 2. NATS completion updates DB
# 3. Task state transitions
# 4. Task failure handling
# 5. End-to-end dispatch with timeout
Protocol Compliance
Implements A2A Protocol Specification:
- ✅ Agent Card (
/.well-known/agent.json) - ✅ Task dispatch (
POST /a2a) - ✅ Status query (
GET /a2a/tasks/{id}) - ✅ JSON-RPC 2.0 envelope
- ✅ Task lifecycle (waiting → working → completed|failed)
- ✅ Artifact support
- ✅ Error handling
Production Deployment
Kubernetes
kubectl apply -k kubernetes/overlays/prod/
Docker
docker build -t vapora-a2a:latest -f Dockerfile .
docker run -p 8003:8003 \
-e SURREAL_URL=ws://surrealdb:8000 \
-e NATS_URL=nats://nats:4222 \
vapora-a2a:latest
Troubleshooting
Tasks not persisting
Check SurrealDB connection:
# Verify connection
curl http://localhost:8000/health
# Check migration applied
surrealdb sql --conn ws://localhost:8000 \
--user root --pass root --ns test --db main \
"SELECT * FROM a2a_tasks LIMIT 1;"
Tasks not completing
Check NATS connection:
# Subscribe to completion events
nats sub "vapora.tasks.completed"
# Server will log warnings if NATS unavailable
Metrics not showing
# Check metrics endpoint
curl http://localhost:8003/metrics | grep vapora_a2a
Related Crates
- vapora-a2a-client - Client library for calling A2A servers
- vapora-agents - Agent coordinator and registry
- vapora-backend - Main VAPORA REST API
License
MIT OR Apache-2.0