A2A Protocol
A2A protocol adapter: AgentCard / Task / Message domain, port traits, A2AService sub-agent delegation, CardRegistry / SmartRouter / LlmMatcher.
The a2a module is the Agent-to-Agent (A2A) protocol adapter. It both lets Aleph talk to external A2A agents and routes internal sub-agent delegations to external implementations.
The historical "domain / port / service / adapter" five-bucket split still applies, but
service/is no longer home tosub_agentalone: it now also carriescard_builder/card_refresh/card_registry/llm_matcher/notification/smart_router. The sub-agent delegation lives at the crate root insrc/a2a/sub_agent.rs.
Overview
A2A enables:
- Agent Card discovery —
card_registrycachesAgentCards;card_refreshruns periodic refresh + health monitoring - LLM smart routing —
llm_matcher+smart_routermap natural-language task descriptions to the best-matching A2A agent - Sub-agent delegation —
A2ASubAgent(src/a2a/sub_agent.rs) re-attaches A2A sub-agents to Aleph's memory / runtime - A2A protocol messages —
domain/message.rs::A2AMessage(text / file / data Parts),A2ATask(multi-turn task with state machine),TaskStatetransitions - Client / server —
adapter/client/andadapter/server/are A2A JSON-RPC endpoints
Architecture
src/a2a/
├── mod.rs # entry; re-exports five submodules
├── config.rs # A2A configuration
├── sub_agent.rs # A2ASubAgent / DelegationOutcome: sub-agent delegation chain
├── tests.rs # module tests
├── domain/ # core A2A types
│ ├── mod.rs
│ ├── agent_card.rs # AgentCard / AgentProvider / AgentInterface / TransportProtocol / AgentSkill / AgentExtension
│ ├── message.rs # A2ARole / A2AMessage / Part (text | file | data) / FileContent / Artifact
│ ├── task.rs # TaskState (state machine) / TaskStatus / A2ATask / ListTasksParams / ListTasksResult
│ ├── events.rs # A2A events
│ ├── security.rs # security-related domain types
│ └── error.rs # A2A errors
├── port/ # protocol interfaces (traits)
│ ├── mod.rs
│ ├── agent_resolver.rs
│ ├── authenticator.rs
│ ├── message_handler.rs
│ ├── streaming.rs
│ └── task_manager.rs
├── service/ # business logic / adapter layer
│ ├── mod.rs
│ ├── card_builder.rs # AgentCard construction
│ ├── card_refresh.rs # periodic refresh + spawn_card_refresh / spawn_health_monitor / refresh_all_cards
│ ├── card_registry.rs # CardRegistry: cache + lookup
│ ├── llm_matcher.rs # SemanticLlmMatcher: LLM-based semantic matching
│ ├── notification.rs # NotificationService / PushNotificationConfig
│ └── smart_router.rs # SmartRouter / LlmMatcher / RoutingDecision / RoutingMethod
└── adapter/ # protocol implementations
├── mod.rs
├── auth/ # A2A auth adapters
├── client/ # A2A client: JSON-RPC over HTTP / stdio
└── server/ # A2A server: exposes Aleph as an A2A agentDomain types (src/a2a/domain/)
// agent_card.rs
pub struct AgentCard { /* name / description / url / version / capabilities / skills / provider / interfaces / security / extensions */ }
pub struct AgentProvider { pub organization: String, pub url: String }
pub struct AgentInterface { /* TransportProtocol + URL */ }
pub enum TransportProtocol { Grpc, HttpJson, WebSocket, /* … */ }
pub struct AgentSkill { /* id / name / description / tags / examples / input_modes / output_modes */ }
pub struct AgentExtension { /* uri / required / params */ }
// message.rs
pub enum A2ARole { User, Agent, System }
pub struct A2AMessage { pub role: A2ARole, pub parts: Vec<Part>, pub metadata: Option<JsonValue> }
pub enum Part { Text { text: String, metadata: Option<JsonValue> }, File(FileContent), Data(JsonValue) }
pub struct FileContent { pub name: Option<String>, pub mime_type: Option<String>, pub uri: String, pub bytes: Option<Vec<u8>> }
pub struct Artifact { pub name: Option<String>, pub parts: Vec<Part> }
// task.rs
pub enum TaskState { Submitted, Working, InputRequired, Completed, Canceled, Failed, Unknown }
impl TaskState { pub fn can_transition_to(&self, target: &Self) -> bool }
pub struct TaskStatus { pub state: TaskState, pub message: Option<A2AMessage> }
pub struct A2ATask { /* id / context_id / status / artifacts / history / metadata */ }
pub fn new(id: impl Into<String>, context_id: impl Into<String>) -> Self;
pub struct ListTasksParams { /* session_id / context_id / status / page_size / page_token */ }
pub struct ListTasksResult { /* tasks / next_page_token */ }Port interfaces (src/a2a/port/)
// One trait per file, implemented by both client and server adapters in adapter/
// agent_resolver.rs — resolve AgentCard / agent_id into a callable endpoint
// authenticator.rs — A2A auth scheme
// message_handler.rs — inbound A2AMessage handling
// streaming.rs — streaming responses (subscribe)
// task_manager.rs — task persistence / state advancementEach trait is implemented by adapter::client (remote A2A agents) and adapter::server (Aleph exposed as an A2A agent).
Service layer (src/a2a/service/)
pub use card_builder::CardBuilder;
pub use card_refresh::{refresh_all_cards, spawn_card_refresh, spawn_health_monitor};
pub use card_registry::CardRegistry;
pub use llm_matcher::SemanticLlmMatcher;
pub use notification::{NotificationService, PushNotificationConfig};
pub use smart_router::{LlmMatcher, RoutingDecision, RoutingMethod, SmartRouter};SmartRouter aggregates LlmMatcher and CardRegistry, mapping a user's natural-language task to the best A2A agent:
LlmMatcher::route(task_description)→RoutingDecision— LLM-scoredCardRegistry::lookup(decision)— resolve to anAgentCard+ endpointSmartRouter::route_and_invoke— end-to-end: score → pick card → delegate
spawn_card_refresh + spawn_health_monitor keep CardRegistry fresh in the background; refresh_all_cards is the one-shot full refresh.
Sub-agent delegation (src/a2a/sub_agent.rs)
pub struct A2ASubAgent { /* smart_router + client_pool */ }
pub struct DelegationOutcome { /* success / tokens / artifacts */ }
impl A2ASubAgent {
pub fn new(smart_router: Arc<SmartRouter>, client_pool: Arc<A2AClientPool>) -> Self;
pub fn with_raw_memory_writer(self, writer: Arc<dyn RawMemoryStore>) -> Self;
pub fn with_capture_registry(self, registry: Arc<MemoryExtensionRegistry>) -> Self;
}A2ASubAgent re-attaches A2A sub-agents to Aleph:
with_raw_memory_writer— write delegation results into Aleph's raw memory (src/memory/store/)with_capture_registry— register memory-extension capture so cross-agent outcomes are visible to the memory system- Closed within the delegation chain — A2A subagents can be re-authorized (the
with_*builders are exactly the re-attachment channels)
Adapter layer (src/a2a/adapter/)
adapter/
├── auth/ # A2A auth adapters (Bearer / API key / OAuth)
├── client/ # A2A client implementation: JSON-RPC over HTTP / stdio
└── server/ # A2A server implementation: projects Aleph as an externally discoverable A2A agentThe client side maps A2A JSON-RPC calls into Aleph's A2AMessage / A2ATask domain types; the server side projects Aleph's agent registry into AgentCard + handlers.
Configuration
[a2a]
enabled = true
max_sub_agents = 10
sub_agent_timeout = 300 # secondsSub-agent tree RPC
subagent.tree returns an agent's subagent tree (node identity + live events + tree RPC). Interrupt now truly cancels fan-out — no longer demoted to enqueue; long-running detached members no longer leak.
See Also
- Orchestrator — Parent-agent orchestration
- Teams — Multi-agent team management
- ACP — Agent Client Protocol for external tools
- A2A Concept — full concept
- Gateway RPC
subagent.tree
Cluster Federation
Single-center asymmetric node federation — one brain orchestrates many machines while the cluster keeps exactly one mind. Reverse RPC, node_invoke, command allowlists, and approval routing.
ACP Protocol
Agent Client Protocol — integrate external CLIs (Claude Code, Codex, Gemini) as ACP adapters; AcpAdapterManager owns the session lifecycle, the process-isolation kernel backs sandbox safety.