<p align="center">
<img src="image/logo.png" alt="velocia" width="600">
</p>
A Rust framework for building production-ready AI agents that communicate via the **A2A (Agent-to-Agent) protocol**. It wraps the [ADK-Rust](https://github.com/google/adk-rust) engine and exposes a declarative, YAML-driven API so you can go from config to a running HTTP agent server with minimal boilerplate.
## Purpose
`velocia` solves the gap between raw LLM SDKs and deployable multi-agent systems. You define an agent in a YAML file — its model, instructions, skills, tools, and auth — and the framework handles:
- **A2A protocol server** — JSON-RPC over SSE, `AgentCard` discovery at `/.well-known/agent.json`, streaming task/artifact events
- **Multi-agent orchestration** — agents can call other agents as remote tools via their A2A address
- **Tool loading** — MCP servers, custom Rust functions, or remote agent addresses declared in config
- **Session persistence** — optional AWS DynamoDB backend for conversation history
- **Observability** — optional OpenTelemetry traces to Phoenix or Arize
- **Authentication** — JWT middleware with configurable security schemes
- **Container-first deployment** — each agent is a self-contained Docker image; compose files wire up multi-agent systems
## Architecture
```
agent_config.yaml
│
▼
AgentFactory::from_config()
│
├─► AgentCard (served at /.well-known/agent.json)
│
└─► AgentExecutor (ADK-Rust engine)
│
├─► Tools (MCP / function / remote agent)
└─► Model (Gemini, OpenAI, Anthropic, …)
│
Axum HTTP server
POST / → SSE stream (A2A)
```
## Quick Start
**1. Define your agent** in `agent_config.yaml`:
```yaml
name: my_agent
description: Does something useful
url: http://my-agent:8080
version: 1.0.0
agent:
type: adk
model:
name: google_genai:gemini-2.5-flash
hyperparameters:
temperature: 0.7
instruction: |
You are a helpful assistant. Answer concisely.
capabilities:
streaming: true
skills:
- id: answer_questions
name: Answer Questions
description: Answers user questions
tags: [qa]
```
**2. Add the dependency** (`Cargo.toml`):
```toml
[dependencies]
velocia = { version = "0.3", features = ["adk"] }
tokio = { version = "1", features = ["full"] }
dotenvy = "0.15"
```
**3. Create the binary** (`src/main.rs`):
```rust
use velocia::AgentFactory;
#[tokio::main]
async fn main() {
dotenvy::dotenv().ok();
let factory = AgentFactory::from_config("agent_config.yaml").unwrap();
println!("Starting {} on port {} ...", "My Agent", 8080);
factory.run_server(8080).await.unwrap();
}
```
**4. Set your API key** (`.env`):
```env
GOOGLE_API_KEY=your_key_here
```
**5. Run it**:
```bash
cargo run
# → http://localhost:8080
# → http://localhost:8080/.well-known/agent.json
```
## Cargo Features
| `client` | | A2A client only — types, `RemoteAgentConnection`, no server, no ADK |
| `adk` | ✓ | Full agent execution + HTTP server — enables `client` automatically |
| `dynamodb` | | DynamoDB-backed session persistence |
| `observability` | | OpenTelemetry traces (Phoenix / Arize) |
| `all` | | All of the above |
`axum`, `tower`, `tower-http`, and `jsonwebtoken` are only compiled when `adk` is enabled.
```toml
# Minimal — connect to agents from your app (no server, no ADK engine)
velocia = { version = "0.3", default-features = false, features = ["client"] }
# Full agent server (default)
velocia = { version = "0.3", features = ["adk"] }
# Everything
velocia = { version = "0.3", features = ["all"] }
```
## Examples
### Hello World Agent
A minimal single agent that greets users and can analyse documents (PDF, images, URLs).
```bash
cd examples/hello_world_agent
docker compose up
```
### Travel Planning System
A multi-agent system with three cooperating agents:
| `flight-booking-assistant` | 8081 | Searches and books flights |
| `hotel-booking-assistant` | 8082 | Searches and books hotels |
| `travel-coordinator` | 8089 | Orchestrates the other two |
The coordinator discovers the sub-agents via their A2A `AgentCard` and delegates tasks to them automatically. An [A2A Inspector](https://github.com/a2aproject/a2a-inspector) is also included on port 6007 for debugging.
```bash
cd examples/travel_planning_system
cp .env.example .env # fill in API keys
docker compose up
```
### A2A Client
Connect to any A2A-compatible agent from your own Rust app without running a server or pulling in the ADK engine.
**`Cargo.toml`:**
```toml
[dependencies]
velocia = { version = "0.3", default-features = false, features = ["client"] }
tokio = { version = "1", features = ["full"] }
```
**`src/main.rs`:**
```rust
use velocia::a2a::client::app_client::A2AGatewayClient;
#[tokio::main]
async fn main() -> velocia::Result<()> {
let client = A2AGatewayClient::from_card_url(
"http://localhost:8080/.well-known/agent.json",
None,
).await?;
let task = client.send_message("Hello from velocia client!", None, None).await?;
for artifact in &task.artifacts {
for part in &artifact.parts {
if let velocia::a2a::types::Part::Text { text, .. } = part {
println!("{text}");
}
}
}
Ok(())
}
```
The built-in `examples/client` ships a fully interactive console client with spinner, session management, and multi-turn conversation:
```bash
# Against a local agent
cargo run --example client -- http://localhost:8080
# Via environment variable
A2A_AGENT_URL=http://localhost:8080 cargo run --example client
```
## Project Structure
```
src/
├── agents/ # AgentFactory, AgentExecutor, ADK builder
├── a2a/ # A2A protocol types (AgentCard, Task, Message, SSE events)
├── config/ # YAML schema (agent, model, tools, auth)
├── tools/ # Tool factory: MCP, function, remote-agent loaders
├── repositories/ # DynamoDB session repository
├── observability/ # OpenTelemetry / tracing setup
└── lib.rs # Public API surface
examples/
├── hello_world_agent/ # Single-agent example
└── travel_planning_system/ # Multi-agent orchestration example
```
## Requirements
- Rust 1.78+
- A supported LLM API key (Google Gemini by default; OpenAI and Anthropic available via ADK-Rust features)
- Docker + Docker Compose (for containerised examples)
- AWS credentials (only if using the `dynamodb` feature)
## License
Apache-2.0