A2A (Agent-to-Agent)¶
A2A (Agent-to-Agent) Protocol Implementation for AI-Parrot.
Exposes AI-Parrot agents as A2A-compliant microservices, enabling inter-agent communication across network boundaries.
Components
Server Layer: - A2AServer: Wrap an agent as an A2A HTTP service - A2AEnabledMixin: Mixin to add A2A server capabilities
Client Layer: - A2AClient: Connect to remote A2A agents - A2AClientMixin: Mixin to add A2A client capabilities - A2AAgentConnection: Connection state for remote agents - A2ARemoteAgentTool: Use remote agent as a tool - A2ARemoteSkillTool: Use remote skill as a tool
Discovery Layer: - A2AMeshDiscovery: Centralized agent discovery service - A2AEndpoint: Configuration for an A2A endpoint - HealthCheckStrategy: How to check agent health - AgentStatus: Agent health status
Routing Layer: - A2AProxyRouter: Rule-based request routing - RoutingStrategy: How to match requests to agents - LoadBalanceStrategy: How to balance across agents - RoutingRule: Individual routing rule definition
Orchestration Layer: - A2AOrchestrator: Hybrid routing with LLM fallback - OrchestrationMode: Execution modes (rules, llm, hybrid, etc.) - OrchestrationResult: Result from orchestration - OrchestrationPlan: LLM decision plan
Security Layer (server-only — requires ai-parrot-server): - AuthScheme: Supported authentication schemes - CallerIdentity: Authenticated agent identity - SecurityPolicy: Access control policies - CredentialProvider: Abstract credential storage - InMemoryCredentialProvider: Dev/test credential store - RedisCredentialProvider: Production credential store - JWTAuthenticator: JWT token authentication - MTLSAuthenticator: Mutual TLS authentication - A2ASecurityMiddleware: Security middleware for servers - SecureA2AClient: Client with automatic authentication
Data Models: - AgentCard: Agent metadata and capabilities - AgentSkill: Skill/capability exposed by agent - AgentCapabilities: Agent feature flags - Task: A2A task with status and artifacts - Message: A2A message format - Artifact: Output produced by agent
A2AClient ¶
A2AClient(base_url: str, *, timeout: float = 60.0, headers: Optional[Dict[str, str]] = None, auth_token: Optional[str] = None, api_key: Optional[str] = None)
Client for communicating with remote A2A agents.
Example
async with A2AClient("https://remote-agent:8080") as client: # Discover agent card = await client.discover() print(f"Connected to: {card.name}")
# Send message
task = await client.send_message("Hello!")
print(task.artifacts[0].parts[0].text)
# Stream response
async for chunk in client.stream_message("Explain quantum computing"):
print(chunk, end="", flush=True)
Initialize A2A client.
| PARAMETER | DESCRIPTION |
|---|---|
base_url
|
Base URL of the A2A agent (e.g., "https://agent.example.com")
TYPE:
|
timeout
|
Request timeout in seconds
TYPE:
|
headers
|
Additional headers to send with requests
TYPE:
|
auth_token
|
Bearer token for authentication
TYPE:
|
api_key
|
API key for authentication (sent as X-API-Key header)
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/client.py
connect
async
¶
Establish connection and discover remote agent.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
disconnect
async
¶
discover
async
¶
Fetch the remote agent's card.
Tries the A2A v1.0 discovery URI (/.well-known/agent-card.json)
first and falls back to the v0.3 URI (/.well-known/agent.json).
The server's protocol version is detected from the card shape
(presence of supportedInterfaces => v1.0) and cached on
self._server_version.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
get_skills ¶
get_skill ¶
send_message
async
¶
send_message(content: str, *, context_id: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> Task
Send a message to the remote agent and wait for response.
| PARAMETER | DESCRIPTION |
|---|---|
content
|
The message content
TYPE:
|
context_id
|
Optional context ID for multi-turn conversations
TYPE:
|
metadata
|
Optional metadata to include
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Task
|
Task with the response |
Source code in packages/ai-parrot/src/parrot/a2a/client.py
stream_message
async
¶
stream_message(content: str, *, context_id: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> AsyncIterator[str]
Send a message and stream the response.
| PARAMETER | DESCRIPTION |
|---|---|
content
|
The message content
TYPE:
|
context_id
|
Optional context ID
TYPE:
|
metadata
|
Optional metadata
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
AsyncIterator[str]
|
Text chunks as they arrive |
Source code in packages/ai-parrot/src/parrot/a2a/client.py
invoke_skill
async
¶
invoke_skill(skill_id: str, params: Optional[Dict[str, Any]] = None, *, context_id: Optional[str] = None) -> Any
Invoke a specific skill on the remote agent.
| PARAMETER | DESCRIPTION |
|---|---|
skill_id
|
The skill ID to invoke
TYPE:
|
params
|
Parameters to pass to the skill
TYPE:
|
context_id
|
Optional context ID
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Any
|
The skill result (extracted from artifacts) |
Source code in packages/ai-parrot/src/parrot/a2a/client.py
get_task
async
¶
Get a task by ID.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
list_tasks
async
¶
list_tasks(context_id: Optional[str] = None, status: Optional[str] = None, page_size: int = 50) -> List[Task]
List tasks with optional filtering.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
cancel_task
async
¶
Cancel a running task.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
create_push_config
async
¶
create_push_config(task_id: str, url: str, *, config_id: str = '', authentication: Optional[Dict[str, Any]] = None, metadata: Optional[Dict[str, Any]] = None) -> TaskPushNotificationConfig
Register a push-notification webhook config for a task.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
get_push_config
async
¶
Fetch a single push-notification config.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
list_push_configs
async
¶
List all push-notification configs registered for a task.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
delete_push_config
async
¶
Delete a push-notification config; returns True on success.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
rpc_call
async
¶
Make a JSON-RPC call to the remote agent.
Source code in packages/ai-parrot/src/parrot/a2a/client.py
A2AAgentConnection
dataclass
¶
Represents a connection to a remote A2A agent.
A2ARemoteAgentTool ¶
A2ARemoteAgentTool(client: A2AClient, *, tool_name: Optional[str] = None, tool_description: Optional[str] = None, use_streaming: bool = False, **kwargs)
Bases: AbstractTool
Wraps a remote A2A agent as a tool that can be used by local agents.
This creates a tool that, when invoked, sends the query to the remote agent. Properly inherits from AbstractTool for ToolManager compatibility.
Initialize A2A Remote Agent Tool.
| PARAMETER | DESCRIPTION |
|---|---|
client
|
Connected A2AClient instance
TYPE:
|
tool_name
|
Custom name for the tool (defaults to ask_
TYPE:
|
tool_description
|
Custom description (defaults to agent card description)
TYPE:
|
use_streaming
|
Whether to use streaming for responses
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/client.py
clone ¶
Clone this tool (shares the client reference).
Source code in packages/ai-parrot/src/parrot/a2a/client.py
A2ARemoteSkillTool ¶
Bases: AbstractTool
Wraps a specific skill from a remote A2A agent as a tool.
Properly inherits from AbstractTool for ToolManager compatibility. Dynamically generates input schema from the skill's input_schema.
Initialize A2A Remote Skill Tool.
| PARAMETER | DESCRIPTION |
|---|---|
client
|
Connected A2AClient instance
TYPE:
|
skill
|
The AgentSkill to wrap as a tool
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/client.py
clone ¶
Clone this tool (shares the client and skill references).
A2AClientMixin ¶
Mixin to add A2A client capabilities to any AbstractBot.
This allows an agent to communicate with remote A2A agents, either directly or by registering them as tools.
Features
- Direct connection to remote A2A agents
- Integration with A2AMeshDiscovery for centralized discovery
- Integration with A2AProxyRouter for rule-based routing
- Integration with A2AOrchestrator for hybrid orchestration
- Automatic tool registration for remote agents/skills
Example
class MyAgent(A2AClientMixin, BasicAgent): pass
agent = MyAgent(name="Orchestrator", llm="openai:gpt-4") await agent.configure()
Option 1: Connect to remote agents directly¶
await agent.add_a2a_agent("https://data-agent:8080") await agent.add_a2a_agent("https://search-agent:8081")
Now the agent can use remote agents as tools¶
response = await agent.ask("Search for X and analyze the data")
Or call remote agents directly¶
result = await agent.ask_remote_agent("data-agent", "What's the total revenue?")
Option 2: Use mesh discovery¶
mesh = A2AMeshDiscovery.from_config("agents.yaml") await mesh.start() agent.set_mesh(mesh) await agent.discover_from_mesh(skill="data_analysis")
Option 3: Use router for rule-based routing¶
router = A2AProxyRouter(mesh) router.route_by_skill("analysis", "AnalystBot") agent.set_router(router) result = await agent.route_to_agent("Analyze this data")
Option 4: Use orchestrator for hybrid routing¶
orchestrator = A2AOrchestrator(mesh) orchestrator.set_fallback_llm(llm_client) agent.set_orchestrator(orchestrator) result = await agent.orchestrate("Complex multi-agent task")
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
set_matrix_transport ¶
Set a Matrix-based A2A transport.
When configured, the agent can use Matrix rooms for A2A communication instead of (or in addition to) HTTP.
| PARAMETER | DESCRIPTION |
|---|---|
transport
|
MatrixA2ATransport instance.
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
get_matrix_transport ¶
set_mesh ¶
Connect this agent to an A2A mesh discovery service.
The mesh provides centralized discovery and health checking of remote A2A agents.
| PARAMETER | DESCRIPTION |
|---|---|
mesh
|
A2AMeshDiscovery instance
TYPE:
|
Example
mesh = A2AMeshDiscovery.from_config("agents.yaml") await mesh.start() agent.set_mesh(mesh)
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
get_mesh ¶
discover_from_mesh
async
¶
discover_from_mesh(skill: Optional[str] = None, tag: Optional[str] = None, register_as_tools: bool = True) -> List[A2AAgentConnection]
Discover and connect to agents from the mesh.
Queries the mesh for agents matching the criteria and establishes connections to them.
| PARAMETER | DESCRIPTION |
|---|---|
skill
|
Filter by skill ID
TYPE:
|
tag
|
Filter by tag
TYPE:
|
register_as_tools
|
If True, register discovered agents as tools
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[A2AAgentConnection]
|
List of new connections established |
Example
Connect to all agents with data analysis skill¶
await agent.discover_from_mesh(skill="data_analysis")
Connect to all agents tagged as "support"¶
await agent.discover_from_mesh(tag="support")
Connect to all healthy agents¶
await agent.discover_from_mesh()
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
set_router ¶
Set an A2A router for rule-based message routing.
The router enables deterministic routing based on skills, tags, or regex patterns without LLM involvement.
| PARAMETER | DESCRIPTION |
|---|---|
router
|
A2AProxyRouter instance
TYPE:
|
Example
router = A2AProxyRouter(mesh) router.route_by_skill("analysis", "AnalystBot") router.route_by_tag("support", "SupportBot") agent.set_router(router)
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
get_router ¶
route_to_agent
async
¶
route_to_agent(message: str, *, skill_id: Optional[str] = None, tags: Optional[List[str]] = None, context_id: Optional[str] = None) -> str
Route a message to an agent using the configured router.
Uses rule-based routing (no LLM) to select the appropriate agent and forward the message.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to route
TYPE:
|
skill_id
|
Optional skill ID hint
TYPE:
|
tags
|
Optional tags hint
TYPE:
|
context_id
|
Optional context for multi-turn
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Response from the routed agent |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no router configured or no route matched |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
set_orchestrator ¶
Set an A2A orchestrator for hybrid routing.
The orchestrator combines rule-based routing with LLM-driven decision making for complex scenarios.
| PARAMETER | DESCRIPTION |
|---|---|
orchestrator
|
A2AOrchestrator instance
TYPE:
|
Example
orchestrator = A2AOrchestrator(mesh) orchestrator.route_by_skill("simple_query", "FAQBot") orchestrator.set_fallback_llm(llm_client) agent.set_orchestrator(orchestrator)
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
get_orchestrator ¶
orchestrate
async
¶
orchestrate(message: str, *, mode: Optional[str] = None, agents: Optional[List[str]] = None, context_id: Optional[str] = None) -> str
Orchestrate a message across multiple agents.
Uses the configured orchestrator which combines rules and LLM-based decision making.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to orchestrate
TYPE:
|
mode
|
Orchestration mode (rules, llm, hybrid, parallel, sequential)
TYPE:
|
agents
|
Optional explicit list of agents
TYPE:
|
context_id
|
Optional context for multi-turn
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Final response from orchestration |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no orchestrator configured |
RuntimeError
|
If orchestration fails |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
fan_out
async
¶
Send message to multiple agents in parallel.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to send
TYPE:
|
agents
|
List of agent names
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Union[str, Exception]]
|
Dict mapping agent name to response or exception |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
pipeline
async
¶
Execute sequential pipeline across agents.
Each agent's output becomes the next agent's input.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Initial message
TYPE:
|
agents
|
Ordered list of agent names
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Final output from last agent |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
add_a2a_agent
async
¶
add_a2a_agent(url: str, *, name: Optional[str] = None, auth_token: Optional[str] = None, api_key: Optional[str] = None, headers: Optional[Dict[str, str]] = None, register_as_tool: bool = True, register_skills_as_tools: bool = False, use_streaming: bool = False, timeout: float = 60.0) -> A2AAgentConnection
Connect to a remote A2A agent.
| PARAMETER | DESCRIPTION |
|---|---|
url
|
Base URL of the remote agent
TYPE:
|
name
|
Optional name override (defaults to agent's name from card)
TYPE:
|
auth_token
|
Bearer token for authentication
TYPE:
|
api_key
|
API key for authentication
TYPE:
|
headers
|
Additional headers
TYPE:
|
register_as_tool
|
If True, register the agent as a callable tool
TYPE:
|
register_skills_as_tools
|
If True, register each skill as a separate tool
TYPE:
|
use_streaming
|
If True, use streaming for tool calls
TYPE:
|
timeout
|
Request timeout
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
A2AAgentConnection
|
A2AAgentConnection with the remote agent info |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | |
remove_a2a_agent
async
¶
Disconnect from a remote A2A agent.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Name of the agent to disconnect
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
list_a2a_agents ¶
get_a2a_agent ¶
get_a2a_client ¶
ask_remote_agent
async
¶
ask_remote_agent(agent_name: str, question: str, *, context_id: Optional[str] = None, stream: bool = False) -> str
Ask a question directly to a remote A2A agent.
| PARAMETER | DESCRIPTION |
|---|---|
agent_name
|
Name of the connected agent
TYPE:
|
question
|
The question to ask
TYPE:
|
context_id
|
Optional context for multi-turn
TYPE:
|
stream
|
If True, stream the response
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
The agent's response as text |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If agent not connected |
RuntimeError
|
If agent returns error |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
invoke_remote_skill
async
¶
invoke_remote_skill(agent_name: str, skill_id: str, params: Optional[Dict[str, Any]] = None, *, context_id: Optional[str] = None) -> Any
Invoke a specific skill on a remote agent.
| PARAMETER | DESCRIPTION |
|---|---|
agent_name
|
Name of the connected agent
TYPE:
|
skill_id
|
ID of the skill to invoke
TYPE:
|
params
|
Parameters for the skill
TYPE:
|
context_id
|
Optional context
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Any
|
The skill result |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If agent not connected |
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
shutdown_a2a
async
¶
Disconnect all A2A connections and cleanup resources.
Source code in packages/ai-parrot/src/parrot/a2a/mixin.py
shutdown
async
¶
Override shutdown to cleanup A2A connections.
AgentCard
dataclass
¶
AgentCard(name: str, description: str, version: str, skills: List[AgentSkill], supported_interfaces: List[AgentInterface] = list(), capabilities: AgentCapabilities = AgentCapabilities(), default_input_modes: List[str] = (lambda: ['text/plain', 'application/json'])(), default_output_modes: List[str] = (lambda: ['text/plain', 'application/json'])(), provider: Optional[AgentProvider] = None, documentation_url: Optional[str] = None, security_schemes: Optional[Dict[str, SecurityScheme]] = None, security_requirements: Optional[List[SecurityRequirement]] = None, signatures: Optional[List[AgentCardSignature]] = None, icon_url: Optional[str] = None, tags: List[str] = list())
Self-describing manifest for an agent (A2A v1.0 structure).
Replaces the flat v0.3 url + preferredTransport with a structured
supported_interfaces array. The flat accessors remain available as
read-only backward-compat properties (url, preferred_transport,
protocol_version) so existing consumers keep working.
AgentSkill
dataclass
¶
AgentSkill(id: str, name: str, description: str, tags: List[str] = list(), input_schema: Optional[Dict[str, Any]] = None, examples: List[str] = list(), input_modes: Optional[List[str]] = None, output_modes: Optional[List[str]] = None, security_requirements: Optional[List[SecurityRequirement]] = None)
A capability exposed by an agent (maps to a tool).
AgentCapabilities
dataclass
¶
AgentCapabilities(streaming: bool = True, push_notifications: bool = False, extended_agent_card: bool = False, extensions: List[AgentExtension] = list())
Capabilities supported by an agent.
Task
dataclass
¶
Task(id: str, context_id: str, status: TaskStatus, artifacts: List[Artifact] = list(), history: List[Message] = list(), metadata: Optional[Dict[str, Any]] = None)
Unit of work with lifecycle.
TaskState ¶
Bases: str, Enum
Task lifecycle states — v1.0.0 ProtoJSON values.
The canonical member value is the v1.0 TASK_STATE_* string. The legacy
v0.3 lowercase values ("submitted" …) are handled by
:func:parse_task_state on deserialization and :func:serialize_task_state
on serialization.
TaskStatus
dataclass
¶
Current status of a task.
Message
dataclass
¶
Message(message_id: str, role: Role, parts: List[Part], context_id: Optional[str] = None, task_id: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, extensions: Optional[List[str]] = None, reference_task_ids: Optional[List[str]] = None)
Part
dataclass
¶
Part(text: Optional[str] = None, file_uri: Optional[str] = None, file_bytes: Optional[bytes] = None, file_media_type: Optional[str] = None, filename: Optional[str] = None, data: Optional[Dict[str, Any]] = None, metadata: Optional[Dict[str, Any]] = None)
Atomic content unit.
Artifact
dataclass
¶
Artifact(artifact_id: str, parts: List[Part], name: Optional[str] = None, description: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None)
Output produced by an agent.
from_response
classmethod
¶
Create artifact from an AIMessage or string response.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
RegisteredAgent
dataclass
¶
RegisteredAgent(url: str, card: AgentCard, last_seen: datetime = datetime.utcnow(), healthy: bool = True, protocol_version: str = '0.3')
Definition about a Registered Agent.
AgentConfig
dataclass
¶
AgentConfig(name: str, description: str, port: int, skills: List[Dict[str, Any]], system_prompt: str)
Configuration for an A2A agent.
AgentInterface
dataclass
¶
AgentInterface(url: str, protocol_binding: str, protocol_version: str = '1.0', tenant: Optional[str] = None)
v1.0 AgentCard interface entry.
AgentProvider
dataclass
¶
Organization that provides the agent (v1.0).
AgentExtension
dataclass
¶
AgentExtension(uri: str, description: Optional[str] = None, required: bool = False, params: Optional[Dict[str, Any]] = None)
A protocol extension declared by an agent (v1.0).
AgentCardSignature
dataclass
¶
A JWS signature over the AgentCard (v1.0). Signing itself is out of scope.
SecurityScheme
dataclass
¶
Base security scheme (v1.0 securitySchemes entry).
APIKeySecurityScheme
dataclass
¶
Bases: SecurityScheme
API key security scheme.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
HTTPAuthSecurityScheme
dataclass
¶
HTTPAuthSecurityScheme(scheme: str = 'bearer', bearer_format: Optional[str] = None, description: Optional[str] = None)
Bases: SecurityScheme
HTTP authentication security scheme (Bearer/Basic).
Source code in packages/ai-parrot/src/parrot/a2a/models.py
OAuth2SecurityScheme
dataclass
¶
Bases: SecurityScheme
OAuth 2.0 security scheme.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
OpenIdConnectSecurityScheme
dataclass
¶
Bases: SecurityScheme
OpenID Connect security scheme.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
MutualTlsSecurityScheme
dataclass
¶
Bases: SecurityScheme
Mutual TLS security scheme.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
SecurityRequirement
dataclass
¶
A security requirement: a map of scheme name -> required scopes.
SendMessageConfiguration
dataclass
¶
SendMessageConfiguration(accepted_output_modes: Optional[List[str]] = None, task_push_notification_config: Optional[TaskPushNotificationConfig] = None, history_length: Optional[int] = None, return_immediately: bool = False)
Configuration accompanying a SendMessage request (v1.0).
TaskPushNotificationConfig
dataclass
¶
TaskPushNotificationConfig(id: str, task_id: str, url: str, authentication: Optional[AuthenticationInfo] = None, metadata: Optional[Dict[str, Any]] = None)
Configuration for a task's push-notification webhook (v1.0).
AuthenticationInfo
dataclass
¶
Authentication details for a push notification webhook (v1.0).
A2AError
dataclass
¶
A2A JSON-RPC error object.
Role ¶
Bases: str, Enum
Message role — v1.0.0 ProtoJSON values.
A2AMeshDiscovery ¶
A2AMeshDiscovery(health_check_interval: float = 30.0, health_check_timeout: float = 10.0, auto_discover_on_start: bool = True, max_concurrent_health_checks: int = 10, retry_unhealthy_interval: float = 60.0, remove_after_failures: int = 0)
Centralized discovery service for remote A2A agents.
Provides a registry of remote A2A agents with automatic health checking, multiple lookup methods, and event notifications.
Features
- Register agents by URL with automatic card discovery
- Periodic health checks with configurable intervals
- Lookup by name, skill ID, skill name, or tag
- Full-text search across agent metadata
- Event callbacks for status changes
- YAML configuration with environment variable substitution
- Statistics and monitoring
Example
Basic usage¶
mesh = A2AMeshDiscovery(health_check_interval=60.0) await mesh.start()
agent_card = await mesh.register("http://my-agent:8080") print(f"Registered: {agent_card.name}")
Query by skill¶
analysts = mesh.get_by_skill("data_analysis") for agent in analysts: print(f" - {agent.card.name} at {agent.url}")
await mesh.stop()
From config file¶
mesh = A2AMeshDiscovery.from_config("config/a2a_agents.yaml") await mesh.start() # Discovers all configured endpoints
Initialize the mesh discovery service.
| PARAMETER | DESCRIPTION |
|---|---|
health_check_interval
|
Seconds between health checks for healthy agents
TYPE:
|
health_check_timeout
|
Timeout for health check requests
TYPE:
|
auto_discover_on_start
|
If True, discover all endpoints on start()
TYPE:
|
max_concurrent_health_checks
|
Max concurrent health check requests
TYPE:
|
retry_unhealthy_interval
|
Seconds between retries for unhealthy agents
TYPE:
|
remove_after_failures
|
Remove agent after N consecutive failures (0 = never)
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
from_config
classmethod
¶
Create mesh from YAML configuration file.
The YAML file supports environment variable substitution using ${VAR_NAME}.
Example YAML
settings: health_check_interval: 30 health_check_timeout: 10 auto_discover_on_start: true
agents: - url: http://sales-agent:8080 tags: [sales, revenue]
-
url: http://support-agent:8080 auth_token: ${SUPPORT_AGENT_TOKEN} tags: [support, customer]
-
url: https://external-agent.example.com api_key: ${EXTERNAL_API_KEY} timeout: 60 enabled: true
| PARAMETER | DESCRIPTION |
|---|---|
config_path
|
Path to YAML configuration file
TYPE:
|
**kwargs
|
Override settings from config
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AMeshDiscovery'
|
Configured A2AMeshDiscovery instance |
| RAISES | DESCRIPTION |
|---|---|
FileNotFoundError
|
If config file doesn't exist |
ValueError
|
If config format is invalid |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | |
start
async
¶
Start the mesh discovery service.
This will: 1. Initialize the concurrency semaphore 2. Discover all configured endpoints (if auto_discover_on_start is True) 3. Start the background health check loop
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
stop
async
¶
Stop the mesh discovery service.
Cancels the health check loop and cleans up resources.
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
add_endpoint ¶
add_endpoint(url: str, *, name: Optional[str] = None, auth_token: Optional[str] = None, api_key: Optional[str] = None, headers: Optional[Dict[str, str]] = None, tags: Optional[Union[Set[str], List[str]]] = None, timeout: float = 30.0, health_check_strategy: Union[HealthCheckStrategy, str] = HealthCheckStrategy.DISCOVERY, health_check_endpoint: Optional[str] = None, enabled: bool = True, priority: int = 0, metadata: Optional[Dict[str, Any]] = None) -> 'A2AMeshDiscovery'
Add an endpoint configuration for later discovery.
The endpoint won't be discovered until start() is called or register() is called explicitly.
| PARAMETER | DESCRIPTION |
|---|---|
url
|
Base URL of the A2A agent
TYPE:
|
name
|
Optional name hint
TYPE:
|
auth_token
|
Bearer token for authentication
TYPE:
|
api_key
|
API key for X-API-Key header
TYPE:
|
headers
|
Additional HTTP headers
TYPE:
|
tags
|
Tags for categorization
TYPE:
|
timeout
|
Request timeout
TYPE:
|
health_check_strategy
|
Strategy for health checks
TYPE:
|
health_check_endpoint
|
Custom health check endpoint
TYPE:
|
enabled
|
Whether endpoint is enabled
TYPE:
|
priority
|
Priority for load balancing
TYPE:
|
metadata
|
Additional metadata
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AMeshDiscovery'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
remove_endpoint ¶
Remove an endpoint configuration.
Also removes the discovered agent if present.
| PARAMETER | DESCRIPTION |
|---|---|
url
|
URL of the endpoint to remove
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if endpoint was removed, False if not found |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
get_endpoint ¶
list_endpoints ¶
register
async
¶
register(url: str, *, auth_token: Optional[str] = None, api_key: Optional[str] = None, headers: Optional[Dict[str, str]] = None, tags: Optional[Union[Set[str], List[str]]] = None, timeout: float = 30.0, **kwargs) -> RegisteredAgent
Register and discover an agent immediately.
Connects to the agent, fetches its AgentCard, and adds it to the registry. This method both configures the endpoint and performs discovery.
| PARAMETER | DESCRIPTION |
|---|---|
url
|
Base URL of the A2A agent
TYPE:
|
auth_token
|
Bearer token for authentication
TYPE:
|
api_key
|
API key for X-API-Key header
TYPE:
|
headers
|
Additional HTTP headers
TYPE:
|
tags
|
Additional tags to merge with agent's tags
TYPE:
|
timeout
|
Request timeout
TYPE:
|
**kwargs
|
Additional endpoint configuration
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
RegisteredAgent
|
RegisteredAgent with discovered card |
| RAISES | DESCRIPTION |
|---|---|
ConnectionError
|
If agent is unreachable |
ValueError
|
If agent card is invalid |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
unregister
async
¶
Unregister an agent by name.
Removes the agent from the registry but keeps the endpoint configuration.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Name of the agent to unregister
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if agent was unregistered, False if not found |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
get ¶
Get a registered agent by name.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Exact name of the agent
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[RegisteredAgent]
|
RegisteredAgent if found, None otherwise |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
get_by_url ¶
Get a registered agent by URL.
| PARAMETER | DESCRIPTION |
|---|---|
url
|
URL of the agent
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Optional[RegisteredAgent]
|
RegisteredAgent if found, None otherwise |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
get_by_skill ¶
get_by_skill(skill_id: str, *, include_unhealthy: bool = False, match_name: bool = True) -> List[RegisteredAgent]
Find agents that have a specific skill.
Searches by skill ID and optionally by skill name.
| PARAMETER | DESCRIPTION |
|---|---|
skill_id
|
Skill ID or name to search for
TYPE:
|
include_unhealthy
|
If True, include unhealthy agents
TYPE:
|
match_name
|
If True, also match against skill name
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of matching RegisteredAgent instances |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
get_by_tag ¶
get_by_tag(tag: str, *, include_unhealthy: bool = False, check_skill_tags: bool = True) -> List[RegisteredAgent]
Find agents that have a specific tag.
Searches agent-level tags and optionally skill-level tags.
| PARAMETER | DESCRIPTION |
|---|---|
tag
|
Tag to search for (case-insensitive)
TYPE:
|
include_unhealthy
|
If True, include unhealthy agents
TYPE:
|
check_skill_tags
|
If True, also check tags on individual skills
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of matching RegisteredAgent instances |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
search ¶
search(query: str, *, include_unhealthy: bool = False, search_fields: Optional[List[str]] = None) -> List[RegisteredAgent]
Full-text search across agent metadata.
Searches agent name, description, skill names, and skill descriptions.
| PARAMETER | DESCRIPTION |
|---|---|
query
|
Search query (case-insensitive)
TYPE:
|
include_unhealthy
|
If True, include unhealthy agents
TYPE:
|
search_fields
|
Fields to search (default: name, description, skills)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of matching RegisteredAgent instances |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
list_healthy ¶
Get all healthy agents.
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of healthy RegisteredAgent instances |
list_unhealthy ¶
Get all unhealthy agents.
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of unhealthy RegisteredAgent instances |
list_all ¶
Get all registered agents regardless of health status.
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of all RegisteredAgent instances |
list_by_priority ¶
Get agents sorted by priority.
Priority comes from the endpoint configuration.
| PARAMETER | DESCRIPTION |
|---|---|
descending
|
If True, highest priority first
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
List[RegisteredAgent]
|
List of RegisteredAgent instances sorted by priority |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
check_health_now
async
¶
Trigger immediate health check.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
If provided, only check this agent. Otherwise check all.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, bool]
|
Dict mapping agent name to health status |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
on_agent_healthy ¶
Register callback for when an agent becomes healthy.
| PARAMETER | DESCRIPTION |
|---|---|
callback
|
Async callback(agent, event_type)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AMeshDiscovery'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
on_agent_unhealthy ¶
Register callback for when an agent becomes unhealthy.
| PARAMETER | DESCRIPTION |
|---|---|
callback
|
Async callback(agent, event_type)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AMeshDiscovery'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
on_agent_registered ¶
Register callback for when a new agent is registered.
| PARAMETER | DESCRIPTION |
|---|---|
callback
|
Async callback(agent, event_type)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AMeshDiscovery'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
on_agent_removed ¶
Register callback for when an agent is removed.
| PARAMETER | DESCRIPTION |
|---|---|
callback
|
Async callback(agent, event_type)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AMeshDiscovery'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
get_info ¶
Get detailed information about the mesh state.
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Any]
|
Dictionary with mesh status information |
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
A2AEndpoint
dataclass
¶
A2AEndpoint(url: str, name: Optional[str] = None, auth_token: Optional[str] = None, api_key: Optional[str] = None, headers: Optional[Dict[str, str]] = None, tags: Set[str] = set(), timeout: float = 30.0, health_check_strategy: HealthCheckStrategy = HealthCheckStrategy.DISCOVERY, health_check_endpoint: Optional[str] = None, enabled: bool = True, priority: int = 0, metadata: Dict[str, Any] = dict())
Configuration for an A2A endpoint before discovery.
Represents a known endpoint that can be registered with the mesh. The actual AgentCard is fetched during discovery.
| ATTRIBUTE | DESCRIPTION |
|---|---|
url |
Base URL of the A2A agent
TYPE:
|
name |
Optional name hint (actual name comes from AgentCard)
TYPE:
|
auth_token |
Bearer token for authentication
TYPE:
|
api_key |
API key for X-API-Key header
TYPE:
|
headers |
Additional HTTP headers
TYPE:
|
tags |
Local tags for categorization (merged with agent's tags)
TYPE:
|
timeout |
Request timeout for this endpoint
TYPE:
|
health_check_strategy |
How to check health for this endpoint
TYPE:
|
health_check_endpoint |
Custom health check endpoint (if strategy is CUSTOM)
TYPE:
|
enabled |
Whether this endpoint is enabled
TYPE:
|
priority |
Priority for load balancing (higher = preferred)
TYPE:
|
metadata |
Additional metadata
TYPE:
|
HealthCheckStrategy ¶
Bases: str, Enum
Strategy for health checking agents.
AgentStatus ¶
Bases: str, Enum
Status of an agent in the mesh.
DiscoveryStats
dataclass
¶
DiscoveryStats(total_registered: int = 0, total_healthy: int = 0, total_unhealthy: int = 0, last_health_check: Optional[datetime] = None, health_checks_performed: int = 0, discovery_errors: int = 0)
Statistics about mesh discovery operations.
to_dict ¶
Convert stats to dictionary.
Source code in packages/ai-parrot/src/parrot/a2a/mesh.py
A2AProxyRouter ¶
A2AProxyRouter(mesh: A2AMeshDiscovery, *, name: str = 'A2ARouter', description: str = 'A2A Proxy Router', version: str = '1.0.0', aggregate_skills: bool = True, skill_prefix_with_agent: bool = True, default_timeout: float = 60.0, base_path: str = '/a2a', tags: Optional[List[str]] = None, capabilities: Optional[AgentCapabilities] = None)
Proxy/Gateway for routing requests to A2A agents without LLM processing.
This router receives requests and forwards them to appropriate downstream agents based on configurable routing rules. No LLM is involved in the routing decision - it's pure rule-based matching.
The router can also expose itself as an A2A-compliant server, presenting an aggregated view of all downstream agents' capabilities.
Use Cases
- API Gateway: Single entry point for multiple specialized agents
- Load Balancer: Distribute requests across equivalent agents
- Router: Direct requests based on content/intent
- Facade: Hide internal agent topology from clients
Example
Setup¶
mesh = A2AMeshDiscovery() await mesh.register("http://agent1:8080") await mesh.register("http://agent2:8080")
router = A2AProxyRouter(mesh, name="Gateway")
Add routing rules¶
router.route_by_skill("data_analysis", "DataAnalyst") router.route_by_tag("customer", "SupportBot") router.route_by_regex(r"urgent|emergency", "PriorityHandler") router.set_default("GeneralAssistant")
Route a message (no LLM involved!)¶
task = await router.route_message("Analyze this data...") print(task.artifacts[0].parts[0].text)
Expose as A2A server¶
app = web.Application() router.setup(app)
Initialize the A2A Proxy Router.
| PARAMETER | DESCRIPTION |
|---|---|
mesh
|
A2AMeshDiscovery instance for agent lookup
TYPE:
|
name
|
Name for this router (used in AgentCard)
TYPE:
|
description
|
Description for this router
TYPE:
|
version
|
Version string
TYPE:
|
aggregate_skills
|
If True, aggregate skills from all downstream agents
TYPE:
|
skill_prefix_with_agent
|
If True, prefix aggregated skills with agent name
TYPE:
|
default_timeout
|
Default timeout for proxied requests
TYPE:
|
base_path
|
URL prefix for A2A endpoints when exposed as server
TYPE:
|
tags
|
Tags for the router's AgentCard
TYPE:
|
capabilities
|
Capabilities to advertise
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/router.py
add_route ¶
add_route(pattern: str, target: Union[str, List[str]], *, strategy: RoutingStrategy = RoutingStrategy.SKILL_MATCH, priority: int = 0, load_balance: LoadBalanceStrategy = LoadBalanceStrategy.FIRST_HEALTHY, weights: Optional[Dict[str, float]] = None, transform_request: Optional[TransformFunc] = None, transform_response: Optional[ResponseTransformFunc] = None, enabled: bool = True, metadata: Optional[Dict[str, Any]] = None) -> 'A2AProxyRouter'
Add a routing rule.
| PARAMETER | DESCRIPTION |
|---|---|
pattern
|
Pattern to match (interpretation depends on strategy)
TYPE:
|
target
|
Agent name or list of agent names
TYPE:
|
strategy
|
How to match the pattern
TYPE:
|
priority
|
Rule priority (higher = evaluated first)
TYPE:
|
load_balance
|
How to select among multiple targets
TYPE:
|
weights
|
Weights for weighted load balancing
TYPE:
|
transform_request
|
Async function to transform request
TYPE:
|
transform_response
|
Async function to transform response
TYPE:
|
enabled
|
Whether rule is active
TYPE:
|
metadata
|
Additional metadata
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Example
router.add_route( "data_analysis", ["Analyst1", "Analyst2"], strategy=RoutingStrategy.SKILL_MATCH, load_balance=LoadBalanceStrategy.ROUND_ROBIN, priority=10 )
Source code in packages/ai-parrot/src/parrot/a2a/router.py
route_by_skill ¶
Add routing rule that matches by skill ID.
| PARAMETER | DESCRIPTION |
|---|---|
skill_id
|
Skill ID to match
TYPE:
|
target
|
Target agent(s)
TYPE:
|
**kwargs
|
Additional RoutingRule parameters
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
route_by_skill_name ¶
Add routing rule that matches by skill name (partial match).
| PARAMETER | DESCRIPTION |
|---|---|
skill_name
|
Skill name pattern to match
TYPE:
|
target
|
Target agent(s)
TYPE:
|
**kwargs
|
Additional RoutingRule parameters
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
route_by_tag ¶
Add routing rule that matches by tag.
| PARAMETER | DESCRIPTION |
|---|---|
tag
|
Tag to match
TYPE:
|
target
|
Target agent(s)
TYPE:
|
**kwargs
|
Additional RoutingRule parameters
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
route_by_regex ¶
Add routing rule that matches by regex pattern in the message.
| PARAMETER | DESCRIPTION |
|---|---|
pattern
|
Regex pattern to match against message content
TYPE:
|
target
|
Target agent(s)
TYPE:
|
**kwargs
|
Additional RoutingRule parameters
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Example
router.route_by_regex( r"urgent|emergency|critical", "PriorityHandler", priority=100 # High priority )
Source code in packages/ai-parrot/src/parrot/a2a/router.py
route_round_robin ¶
Add round-robin routing across multiple agents.
All requests matching this rule will be distributed evenly across the specified agents.
| PARAMETER | DESCRIPTION |
|---|---|
agents
|
List of agent names to rotate through
TYPE:
|
**kwargs
|
Additional RoutingRule parameters
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
set_default ¶
Set the default agent for requests that don't match any rule.
| PARAMETER | DESCRIPTION |
|---|---|
agent_name
|
Name of the default agent
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
remove_route ¶
Remove a routing rule.
| PARAMETER | DESCRIPTION |
|---|---|
pattern
|
Pattern of the rule to remove
TYPE:
|
strategy
|
If provided, only remove rule with matching strategy
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if rule was removed, False if not found |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
clear_routes ¶
Clear all routing rules.
| RETURNS | DESCRIPTION |
|---|---|
'A2AProxyRouter'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
list_routes ¶
List all configured routing rules.
| RETURNS | DESCRIPTION |
|---|---|
List[Dict[str, Any]]
|
List of rule configurations |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
find_target ¶
find_target(message: str, *, skill_id: Optional[str] = None, tags: Optional[List[str]] = None) -> RoutingResult
Find the target agent for a request.
Evaluates all rules in priority order and returns the first match.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message content
TYPE:
|
skill_id
|
Optional skill ID
TYPE:
|
tags
|
Optional tags
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
RoutingResult
|
RoutingResult with matched rule and target agent |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
route_message
async
¶
route_message(message: str, *, skill_id: Optional[str] = None, tags: Optional[List[str]] = None, context_id: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> Task
Route a message to the appropriate agent and return the response.
This is a PASSTHROUGH operation - no LLM is involved. The message is forwarded as-is to the matched agent.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message content to route
TYPE:
|
skill_id
|
Optional skill ID to help with routing
TYPE:
|
tags
|
Optional tags to help with routing
TYPE:
|
context_id
|
Optional context ID for conversations
TYPE:
|
metadata
|
Optional metadata
TYPE:
|
timeout
|
Optional timeout override
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Task
|
Task with the response from the downstream agent |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no target agent found |
ConnectionError
|
If target agent is unreachable |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | |
route_message_stream
async
¶
route_message_stream(message: str, *, skill_id: Optional[str] = None, tags: Optional[List[str]] = None, context_id: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> AsyncIterator[str]
Route a message and stream the response.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to route
TYPE:
|
skill_id
|
Optional skill ID
TYPE:
|
tags
|
Optional tags
TYPE:
|
context_id
|
Optional context ID
TYPE:
|
metadata
|
Optional metadata
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
AsyncIterator[str]
|
Text chunks as they arrive from the downstream agent |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
invoke_skill
async
¶
invoke_skill(skill_id: str, params: Optional[Dict[str, Any]] = None, *, agent_name: Optional[str] = None, context_id: Optional[str] = None) -> Any
Invoke a specific skill on a remote agent.
If agent_name is not provided, finds an agent with the skill.
| PARAMETER | DESCRIPTION |
|---|---|
skill_id
|
ID of the skill to invoke
TYPE:
|
params
|
Parameters for the skill
TYPE:
|
agent_name
|
Optional specific agent to use
TYPE:
|
context_id
|
Optional context ID
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Any
|
Skill result from the downstream agent |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If no agent found with the skill |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
close_clients
async
¶
Close all cached client connections.
ask
async
¶
Shortcut: send message and get response as string.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to send
TYPE:
|
agent
|
Optional specific agent to use
TYPE:
|
**kwargs
|
Additional arguments for route_message
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Response text |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
fan_out
async
¶
fan_out(message: str, agents: List[str], *, timeout: float = 60.0, **kwargs) -> Dict[str, Union[str, Exception]]
Send message to multiple agents in parallel.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to send
TYPE:
|
agents
|
List of agent names
TYPE:
|
timeout
|
Timeout for each request
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Union[str, Exception]]
|
Dict mapping agent name to response or exception |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
pipeline
async
¶
Execute a sequential pipeline of agents.
Each agent's output becomes the next agent's input.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Initial message
TYPE:
|
agents
|
Ordered list of agent names
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Final output from the last agent |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
get_agent_card ¶
Get the AgentCard for this router.
When aggregate_skills is True, the card includes skills from all downstream agents, making this router appear as a single agent with all capabilities.
| PARAMETER | DESCRIPTION |
|---|---|
force_refresh
|
Force refresh of cached card
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AgentCard
|
AgentCard representing this router |
Source code in packages/ai-parrot/src/parrot/a2a/router.py
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 | |
setup ¶
Mount the router as an A2A server on an aiohttp application.
This allows external services to discover and use this router as if it were a regular A2A agent.
| PARAMETER | DESCRIPTION |
|---|---|
app
|
aiohttp Application
TYPE:
|
base_path
|
Optional path prefix override
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/router.py
get_info ¶
Get detailed information about the router state.
Source code in packages/ai-parrot/src/parrot/a2a/router.py
RoutingStrategy ¶
Bases: str, Enum
Strategy for selecting target agent.
LoadBalanceStrategy ¶
Bases: str, Enum
Strategy for load balancing across multiple target agents.
RoutingRule
dataclass
¶
RoutingRule(pattern: str, strategy: RoutingStrategy, target_agents: List[str] = list(), priority: int = 0, load_balance: LoadBalanceStrategy = LoadBalanceStrategy.FIRST_HEALTHY, weights: Optional[Dict[str, float]] = None, transform_request: Optional[TransformFunc] = None, transform_response: Optional[ResponseTransformFunc] = None, enabled: bool = True, metadata: Dict[str, Any] = dict(), _compiled_regex: Optional[Pattern] = None, _round_robin_counter: int = 0, _last_used: Dict[str, datetime] = dict())
Defines a routing rule for matching requests to agents.
| ATTRIBUTE | DESCRIPTION |
|---|---|
pattern |
Pattern to match (skill_id, tag, regex, or "*" for default)
TYPE:
|
strategy |
How to match the pattern against requests
TYPE:
|
target_agents |
List of agent names that can handle matching requests
TYPE:
|
priority |
Rule priority (higher = evaluated first)
TYPE:
|
load_balance |
Strategy for selecting among multiple targets
TYPE:
|
weights |
Optional weights for weighted load balancing
TYPE:
|
transform_request |
Optional async function to transform request before sending
TYPE:
|
transform_response |
Optional async function to transform response before returning
TYPE:
|
enabled |
Whether this rule is active
TYPE:
|
metadata |
Additional metadata for the rule
TYPE:
|
RoutingResult
dataclass
¶
RoutingResult(matched: bool, rule: Optional[RoutingRule] = None, target_agent: Optional[RegisteredAgent] = None, match_details: Dict[str, Any] = dict())
Result of a routing decision.
ProxyStats
dataclass
¶
ProxyStats(requests_total: int = 0, requests_routed: int = 0, requests_failed: int = 0, requests_no_match: int = 0, total_latency_ms: float = 0.0, agents_used: Dict[str, int] = dict(), rules_matched: Dict[str, int] = dict(), last_request_time: Optional[datetime] = None)
Statistics for the proxy router.
to_dict ¶
Convert stats to dictionary.
Source code in packages/ai-parrot/src/parrot/a2a/router.py
A2AOrchestrator ¶
A2AOrchestrator(mesh: A2AMeshDiscovery, *, name: str = 'A2AOrchestrator', default_mode: OrchestrationMode = OrchestrationMode.HYBRID, default_timeout: float = 60.0, max_parallel_agents: int = 10, max_sequential_agents: int = 5, aggregate_parallel_responses: bool = True)
Hybrid orchestrator combining rule-based routing with LLM decision-making.
This orchestrator provides intelligent request routing and multi-agent coordination. It uses deterministic rules when patterns are known and falls back to LLM-based reasoning for complex or ambiguous requests.
Architecture
- Rules Engine (via A2AProxyRouter): Fast, deterministic routing
- LLM Decision Engine: Complex reasoning about agent selection
- Execution Engine: Parallel/sequential agent invocation
- Aggregation Engine: Combine responses from multiple agents
Usage Patterns
- RULES_ONLY: Pure rule-based routing, no LLM cost
- LLM_ONLY: Always use LLM for decisions
- HYBRID: Rules first, LLM fallback (recommended)
- PARALLEL: Fan-out to multiple agents
- SEQUENTIAL: Pipeline execution
Example
orchestrator = A2AOrchestrator(mesh, default_mode=OrchestrationMode.HYBRID)
Add rules (fast path)¶
orchestrator.route_by_skill("analysis", "AnalystBot") orchestrator.route_by_regex(r"urgent", "PriorityBot")
Set LLM fallback¶
orchestrator.set_fallback_llm(claude_client)
Simple case: uses rules¶
result = await orchestrator.run("Analyze this data")
Complex case: LLM decides¶
result = await orchestrator.run( "Compare our Q3 performance with competitors and suggest improvements" )
Initialize the orchestrator.
| PARAMETER | DESCRIPTION |
|---|---|
mesh
|
A2AMeshDiscovery instance for agent lookup
TYPE:
|
name
|
Name for this orchestrator
TYPE:
|
default_mode
|
Default orchestration mode
TYPE:
|
default_timeout
|
Default timeout for agent calls
TYPE:
|
max_parallel_agents
|
Maximum agents in parallel execution
TYPE:
|
max_sequential_agents
|
Maximum agents in sequential pipeline
TYPE:
|
aggregate_parallel_responses
|
Whether to combine parallel responses
TYPE:
|
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
route_by_skill ¶
Add skill-based routing rule.
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
route_by_tag ¶
Add tag-based routing rule.
route_by_regex ¶
Add regex-based routing rule.
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
set_default ¶
set_fallback_llm ¶
set_fallback_llm(llm_client: 'AbstractClient', *, decision_prompt: Optional[str] = None, model: Optional[str] = None) -> 'A2AOrchestrator'
Configure LLM for complex orchestration decisions.
The LLM is used when: - No routing rule matches (in HYBRID mode) - Explicitly requested (LLM_ONLY mode) - Task requires multiple agents
| PARAMETER | DESCRIPTION |
|---|---|
llm_client
|
Parrot AbstractClient instance (Claude, GPT, etc.)
TYPE:
|
decision_prompt
|
Custom prompt template for decisions
TYPE:
|
model
|
Specific model to use for decisions
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
'A2AOrchestrator'
|
Self for method chaining |
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
clear_llm ¶
run
async
¶
run(message: str, *, mode: Optional[OrchestrationMode] = None, agents: Optional[List[str]] = None, skill_id: Optional[str] = None, tags: Optional[List[str]] = None, context_id: Optional[str] = None, timeout: Optional[float] = None, metadata: Optional[Dict[str, Any]] = None) -> OrchestrationResult
Execute orchestration for a message.
This is the main entry point. The orchestrator will: 1. Try rule-based routing if applicable 2. Fall back to LLM decision if needed (HYBRID mode) 3. Execute on selected agent(s) 4. Aggregate results if multiple agents used
| PARAMETER | DESCRIPTION |
|---|---|
message
|
The message/request to process
TYPE:
|
mode
|
Override default orchestration mode
TYPE:
|
agents
|
Explicit list of agents to use (bypasses routing)
TYPE:
|
skill_id
|
Optional skill ID hint for routing
TYPE:
|
tags
|
Optional tags for routing
TYPE:
|
context_id
|
Optional context for multi-turn conversations
TYPE:
|
timeout
|
Override default timeout
TYPE:
|
metadata
|
Additional metadata
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
OrchestrationResult
|
OrchestrationResult with response(s) and execution details |
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 | |
close_clients
async
¶
Close all cached clients.
ask
async
¶
ask(message: str, *, agent: Optional[str] = None, mode: Optional[OrchestrationMode] = None, **kwargs) -> str
Shortcut: get response as string.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to send
TYPE:
|
agent
|
Optional specific agent
TYPE:
|
mode
|
Optional mode override
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Response text |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If orchestration fails |
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
fan_out
async
¶
Send to multiple agents and collect responses.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Message to send
TYPE:
|
agents
|
List of agent names
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
Dict[str, Union[str, Exception]]
|
Dict mapping agent name to response or exception |
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
pipeline
async
¶
Execute sequential pipeline.
| PARAMETER | DESCRIPTION |
|---|---|
message
|
Initial message
TYPE:
|
agents
|
Ordered list of agents
TYPE:
|
**kwargs
|
Additional arguments
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Final output from last agent |
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
get_info ¶
Get orchestrator state information.
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
OrchestrationMode ¶
Bases: str, Enum
Mode of orchestration.
LLMDecisionStrategy ¶
Bases: str, Enum
Strategy for LLM-based agent selection.
OrchestrationPlan ¶
Bases: BaseModel
Complete orchestration plan from LLM.
OrchestrationResult
dataclass
¶
OrchestrationResult(success: bool, mode_used: OrchestrationMode, agents_used: List[str], responses: List[AgentExecutionResult], final_output: Optional[str] = None, total_time_ms: float = 0.0, llm_fallback_used: bool = False, llm_decision: Optional[OrchestrationPlan] = None, metadata: Dict[str, Any] = dict())
Complete result from orchestration.
primary_response
property
¶
Get the primary response (first successful or final output).
to_dict ¶
Convert to dictionary.
Source code in packages/ai-parrot/src/parrot/a2a/orchestrator.py
AgentExecutionResult
dataclass
¶
AgentExecutionResult(agent_name: str, success: bool, response: Optional[str] = None, task: Optional[Task] = None, error: Optional[str] = None, latency_ms: float = 0.0, metadata: Dict[str, Any] = dict())
Result from a single agent execution.
OrchestratorStats
dataclass
¶
OrchestratorStats(total_requests: int = 0, successful_requests: int = 0, failed_requests: int = 0, rules_used: int = 0, llm_fallback_used: int = 0, parallel_executions: int = 0, sequential_executions: int = 0, total_latency_ms: float = 0.0, agents_called: Dict[str, int] = dict(), mode_usage: Dict[str, int] = dict())
Statistics for the orchestrator.
parse_task_state ¶
Parse a TaskState from either the v0.3 or the v1.0 format.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
parse_role ¶
Parse a Role from either the v0.3 or the v1.0 format.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
serialize_task_state ¶
Serialize a TaskState to the wire value for the target protocol version.
Source code in packages/ai-parrot/src/parrot/a2a/models.py
serialize_role ¶
Serialize a Role to the wire value for the target protocol version.