Building Agent Systems with A2A Outbound Adapter
The A2A Outbound Adapter is the easiest and most robust way to connect your uAgent-based agents to the broader A2A ecosystem. By using the adapter, you can:
- Achieve Interoperability: Seamlessly connect agents built on different frameworks, or platforms, regardless of where they are hosted.
- Enable Agent-to-Agent Collaboration: Allow your agents to discover, communicate, and collaborate with other agents in real time, unlocking new workflows and capabilities.
- Abstract Complexity: The adapter handles protocol details, health checks, routing, and error handling, so you can focus on your agent's logic and value.
- Scale Easily: Add, remove, or update agents at runtime without changing your core infrastructure.
- Future-Proof Your Agents: Adopt open standards and modular design, ensuring your agents remain compatible as the ecosystem evolves.
Whether you are building a single specialized agent or a large-scale multi-agent system, the A2A Outbound Adapter provides the foundation for secure, scalable, and innovative agentic applications.
Features
Agent Management
- Configure and manage multiple A2A agents with different specialties
- Automatic agent discovery and registration
- Health monitoring and status tracking
- Registers Agent Cards for multiple A2A servers and runs them alongside the uAgent in a single terminal using different ports
- Supports communication with both single and multiple A2A servers
- Dynamically determines the appropriate A2A server based on the user query, sends the request via HTTP, and returns the response back to ASI:One
Intelligent Routing
- Keyword Matching: Route queries based on agent keywords and specialties
- LLM-Based Routing: Use AI to intelligently select the best agent for complex queries
- Round-Robin: Distribute load evenly across available agents
- Priority-Based: Assign priorities to agents for preferential routing
Communication Protocols
- Full uAgent chat protocol support
- Asynchronous message handling
- Acknowledgment and error handling
- Real-time agent communication
Reliability Features
- Health checking and agent discovery
- Fallback executor support
- Graceful error handling
- Timeout management
Installation
pip install "uagents-adapter[a2a]"
Class Reference
A2AAdapter
Main adapter class for managing A2A agents.
Constructor Parameters
Parameter | Type | Default | Description |
---|---|---|---|
name | str | Required | Name of the adapter |
description | str | Required | Description of the adapter |
asi_api_key | str | Required | ASI:One API Keys |
port | int | 8000 | uAgent port |
mailbox | bool | True | Enable mailbox functionality |
seed | str | None | Seed for uAgent (auto-generated if None) |
agent_configs | List[A2AAgentConfig] | [] | List of agent configurations |
fallback_executor | AgentExecutor | None | Fallback executor for unrouted queries |
routing_strategy | str | "keyword_match" | Routing strategy to use |
Methods
add_agent_config(config: A2AAgentConfig)
Add a new agent configuration to the adapter.
run()
Start the adapter and begin processing messages.
A2AAgentConfig
Configuration class for individual A2A agents.
Constructor Parameters
Parameter | Type | Default | Description |
---|---|---|---|
name | str | Required | Agent name |
description | str | Required | Agent description |
url | str | Required | Agent URL |
port | int | Required | Agent port |
specialties | List[str] | Required | Agent specialties |
skills | List[str] | Auto-generated | Agent skills |
examples | List[str] | Auto-generated | Usage examples |
keywords | List[str] | Auto-generated | Routing keywords |
priority | int | 1 | Agent priority (higher = preferred) |
Components
1. A2AAgentConfig
A dataclass for configuring each agent, including name, description, URL, specialties, skills, and routing metadata.
class A2AAgentConfig:
"""Configuration for an A2A agent (name, description, URL, specialties, etc.)."""
Example: Writing an Agent Config
A2AAgentConfig(
name="research_specialist",
description="AI Research Specialist for research and analysis",
port=8100,
a2a_port=10020,
specialties=["research", "analysis", "fact-finding", "summarization"],
executor_class="ResearchAgentExecutor"
)
2. SingleA2AAdapter
Wraps a single uAgent and exposes it as an A2A HTTP server. Handles incoming chat messages, forwards them to the agent, and returns responses. Supports direct execution fallback if HTTP endpoints are unavailable.
class SingleA2AAdapter:
"""Expose a single uAgent as an A2A HTTP server with fallback support."""
3. MultiA2AAdapter
Manages multiple agent configurations. Discovers and health-checks available agents at runtime. Routes queries to the best agent using keyword matching, round-robin, or LLM-based strategies. Provides fallback execution if no agent matches.
class MultiA2AAdapter:
"""Manage and route between multiple A2A agent configs with advanced strategies."""
4. a2a_servers
Starts one or more A2A agent servers, each with its own manifest and port. This function is used to launch the HTTP servers for your agents, making them discoverable and accessible via the A2A protocol.
Function:
def a2a_servers(agent_configs: List[A2AAgentConfig], executors: Dict[str, AgentExecutor]):
"""Start individual A2A servers for each agent config and executor in separate threads."""
AgentCard Creation
How AgentCard Content is Created and Used
-
A2AAgentConfig
- This dataclass is where you define the agent's core metadata:
name
: The agent's unique name (e.g., "research_specialist").description
: A human-readable summary of what the agent does (e.g., "AI Research Specialist for research and analysis").url
andport
: Where the agent's HTTP server will be accessible.specialties
: List of topics or domains the agent is good at (e.g.,["research", "analysis"]
).skills
,examples
,keywords
,priority
: Optional fields for routing and discovery. If not provided, they are auto-generated from specialties.
- How to write:
- Use clear, concise, and descriptive text for
name
anddescription
. - List all relevant specialties for accurate routing.
- Use clear, concise, and descriptive text for
- This dataclass is where you define the agent's core metadata:
-
Agent Executor
- The executor (e.g.,
ResearchAgentExecutor
) is the logic that processes queries. It receives the config and uses its fields to:- Set up prompts, system messages, or capabilities.
- Inform the agent's behavior and response style.
- The executor (e.g.,
-
Agent Skill (AgentSkill)
- Created using the config's fields:
id
,name
,description
,tags
(from specialties), andexamples
.
- How to write:
id
: Usually a lowercase, underscored version of the name.tags
: Use specialties for discoverability.examples
: Short sample queries or tasks.
- Created using the config's fields:
-
Agent Card (AgentCard)
- Combines all the above into a manifest for the A2A server:
name
,description
,a2a_port
,version
,defaultInputModes
,defaultOutputModes
,capabilities
,skills
(list of AgentSkill).
- This card is served at
/.well-known/agent.json
and is what platforms like AgentVerse use to discover and display your agent. - How to write:
- Ensure all fields are filled and accurate.
defaultInputModes
/defaultOutputModes
should include "text" for chat.capabilities
can be left empty or set as needed.
- Combines all the above into a manifest for the A2A server:
-
A2A HTTP Server (A2AStarletteApplication)
- Uses the AgentCard to expose the agent over HTTP.
- The manifest is automatically generated from the AgentCard.
-
uAgent (MultiA2AAdapter/SingleA2AAdapter)
- Handles chat protocol and routes queries to the correct A2A server based on the agent card.
Quick Start Example
Step 1: Install Dependencies
pip install "uagents-adapter[a2a-outbound]"
pip install "a2a-sdk[all]"
Step 2: Create Agent Configurations
from uagents_adapter.a2a_outbound.adapter import A2AAgentConfig
# Research Agent Configuration
research_config = A2AAgentConfig(
name="research_specialist",
description="AI Research Specialist for research and analysis",
url="http://localhost:8100",
port=8100,
specialties=["research", "analysis", "fact-finding", "summarization"],
priority=1
)
# Coding Agent Configuration
coding_config = A2AAgentConfig(
name="coding_assistant",
description="AI Coding Assistant for code review and development",
url="http://localhost:8200",
port=8200,
specialties=["coding", "programming", "code_review", "debugging"],
priority=2
)
Step 3: Create Agent Executors
from uagents_adapter.a2a_outbound.executor import AgentExecutor
class ResearchAgentExecutor(AgentExecutor):
def __init__(self, config: A2AAgentConfig):
super().__init__(config)
async def execute(self, message: str) -> str:
# Implement research logic here
return f"Research results for: {message}"
class CodingAgentExecutor(AgentExecutor):
def __init__(self, config: A2AAgentConfig):
super().__init__(config)
async def execute(self, message: str) -> str:
# Implement coding logic here
return f"Coding assistance for: {message}"
Step 4: Set Up the Adapter
import os
from uagents_adapter.a2a_outbound.adapter import A2AAdapter
# Set your ASI:One API key
os.environ["ASI_API_KEY"] = "your_asi_api_key_here"
# Create the adapter
adapter = A2AAdapter(
name="Multi-Agent System",
description="A system with research and coding capabilities",
asi_api_key=os.environ["ASI_API_KEY"],
port=8000,
routing_strategy="keyword_match"
)
# Add agent configurations
adapter.add_agent_config(research_config)
adapter.add_agent_config(coding_config)
# Run the adapter
if __name__ == "__main__":
adapter.run()
Step 5: Start A2A Servers
from uagents_adapter.a2a_outbound.server import a2a_servers
# Create executors dictionary
executors = {
"research_specialist": ResearchAgentExecutor(research_config),
"coding_assistant": CodingAgentExecutor(coding_config)
}
# Start A2A servers
a2a_servers([research_config, coding_config], executors)
Step 6: Test Your System
# Test research agent
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "Research quantum computing trends"}'
# Test coding agent
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "Review this Python code"}'
Advanced Features
Custom Routing Strategies
You can implement custom routing logic by extending the base routing class:
from uagents_adapter.a2a_outbound.routing import BaseRoutingStrategy
class CustomRoutingStrategy(BaseRoutingStrategy):
async def route(self, message: str, agents: List[A2AAgentConfig]) -> A2AAgentConfig:
# Implement your custom routing logic
# Example: Route based on message length
if len(message) > 100:
return agents[0] # Research agent for long queries
else:
return agents[1] # Coding agent for short queries
Health Monitoring
The adapter automatically monitors agent health:
# Check agent health
health_status = await adapter.check_agent_health(agent_config)
# Get all healthy agents
healthy_agents = await adapter.get_healthy_agents()
Error Handling
Implement robust error handling:
try:
response = await adapter.process_message(message)
except AgentUnavailableError:
# Handle agent unavailability
response = await fallback_executor.execute(message)
except TimeoutError:
# Handle timeout
response = "Request timed out. Please try again."
Production Deployment
Environment Setup
# Set environment variables
export ASI_API_KEY="your_production_api_key"
export UAGENTS_MAILBOX_KEY="your_mailbox_key"
export LOG_LEVEL="INFO"
Docker Deployment
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "main.py"]
Monitoring and Logging
import logging
from uagents_adapter.a2a_outbound.monitoring import HealthMonitor
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Monitor agent health
monitor = HealthMonitor(adapter)
monitor.start_monitoring()
Troubleshooting
Common Issues
-
Agent Not Responding
- Check if the A2A server is running
- Verify the agent URL and port
- Check firewall settings
-
Routing Issues
- Verify agent specialties are correctly set
- Check routing strategy configuration
- Review agent health status
-
Authentication Errors
- Verify ASI:One API key is correct
- Check API key permissions
- Ensure proper environment variable setup
Debug Mode
Enable debug logging for troubleshooting:
import logging
logging.basicConfig(level=logging.DEBUG)
Resources
Happy building! 🚀