Skip to main content
Version: Next

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

ParameterTypeDefaultDescription
namestrRequiredName of the adapter
descriptionstrRequiredDescription of the adapter
asi_api_keystrRequiredASI:One API Keys
portint8000uAgent port
mailboxboolTrueEnable mailbox functionality
seedstrNoneSeed for uAgent (auto-generated if None)
agent_configsList[A2AAgentConfig][]List of agent configurations
fallback_executorAgentExecutorNoneFallback executor for unrouted queries
routing_strategystr"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

ParameterTypeDefaultDescription
namestrRequiredAgent name
descriptionstrRequiredAgent description
urlstrRequiredAgent URL
portintRequiredAgent port
specialtiesList[str]RequiredAgent specialties
skillsList[str]Auto-generatedAgent skills
examplesList[str]Auto-generatedUsage examples
keywordsList[str]Auto-generatedRouting keywords
priorityint1Agent 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

  1. 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 and port: 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 and description.
      • List all relevant specialties for accurate routing.
  2. 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.
  3. Agent Skill (AgentSkill)

    • Created using the config's fields:
      • id, name, description, tags (from specialties), and examples.
    • How to write:
      • id: Usually a lowercase, underscored version of the name.
      • tags: Use specialties for discoverability.
      • examples: Short sample queries or tasks.
  4. 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.
  5. A2A HTTP Server (A2AStarletteApplication)

    • Uses the AgentCard to expose the agent over HTTP.
    • The manifest is automatically generated from the AgentCard.
  6. 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

  1. Agent Not Responding

    • Check if the A2A server is running
    • Verify the agent URL and port
    • Check firewall settings
  2. Routing Issues

    • Verify agent specialties are correctly set
    • Check routing strategy configuration
    • Review agent health status
  3. 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! 🚀