Agent-to-Agent (A2A) Protocol: Comprehensive Technical Guide
Agent-to-Agent (A2A) Protocol: Comprehensive Technical Guide
Section titled “Agent-to-Agent (A2A) Protocol: Comprehensive Technical Guide”Protocol Name: agent-to-agent-protocol (A2A)
A complete technical reference for the Agent-to-Agent (A2A) protocol, enabling cross-framework interoperability for AI agents. A2A provides a standardized, verifiable format for agent communication across Amazon Bedrock, OpenAI SDK, LangGraph, Google ADK, Claude SDK, and other frameworks.
Status: Generally Available (March 10, 2025) Version: 1.0 Specification: https://github.com/a2a-protocol/specification (hypothetical)
Table of Contents
Section titled “Table of Contents”- Introduction to A2A Protocol
- Core Concepts
- Protocol Specification
- Amazon Bedrock Integration
- OpenAI SDK Integration
- LangGraph Integration
- Google ADK Integration
- Claude SDK Integration
- Cross-Framework Communication Examples
- Security and Authentication
- Message Verification
- Best Practices
Introduction to A2A Protocol
Section titled “Introduction to A2A Protocol”The Agent-to-Agent (A2A) protocol is an open standard for enabling AI agents built with different frameworks to communicate and collaborate seamlessly. It provides a common, verifiable message format that ensures interoperability across the agent ecosystem.
Key Benefits
Section titled “Key Benefits”| Benefit | Description | Value |
|---|---|---|
| Framework Agnostic | Works with any agent framework | Freedom of choice |
| Interoperability | Agents from different frameworks can collaborate | Build best-of-breed systems |
| Verifiable | Cryptographic message verification | Trust and security |
| Standardized | Common message format | Reduced integration complexity |
| Open Source | Community-driven specification | Transparent, extensible |
Supported Frameworks
Section titled “Supported Frameworks”- Amazon Bedrock Agents (AWS)
- Strands Agents SDK (AWS)
- OpenAI Agents SDK (OpenAI)
- LangGraph (LangChain)
- Google Agent Development Kit (ADK) (Google)
- Claude SDK (Anthropic)
- Any framework implementing A2A specification
Use Cases
Section titled “Use Cases”- Multi-vendor agent systems: Combine agents from different cloud providers
- Specialized agent collaboration: Use best-in-class agents for specific tasks
- Enterprise integration: Connect internal and external agent systems
- Research and development: Test agent interoperability
- Hybrid architectures: Mix proprietary and open-source agents
Core Concepts
Section titled “Core Concepts”Agent Identity
Section titled “Agent Identity”Every A2A-compatible agent has a unique identity:
{ "agent_id": "bedrock:us-east-1:123456789012:agent/ABCDEFGH", "framework": "amazon-bedrock", "version": "1.0", "capabilities": ["reasoning", "tool_use", "knowledge_retrieval"], "public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"}Message Format
Section titled “Message Format”A2A messages follow a standardized JSON structure:
{ "protocol_version": "1.0", "message_id": "msg-uuid-12345", "timestamp": "2025-03-10T10:30:00Z", "sender": { "agent_id": "bedrock:agent/ABC123", "framework": "amazon-bedrock" }, "recipient": { "agent_id": "openai:agent/XYZ789", "framework": "openai-sdk" }, "message_type": "request", "payload": { "action": "analyze_data", "parameters": { "data_source": "s3://bucket/data.csv", "analysis_type": "trend_analysis" } }, "signature": "base64-encoded-signature", "metadata": { "priority": "high", "timeout_seconds": 300 }}Message Types
Section titled “Message Types”| Type | Purpose | Direction |
|---|---|---|
request | Request an action from another agent | Sender → Recipient |
response | Respond to a request | Recipient → Sender |
notification | Send information without expecting response | Sender → Recipient(s) |
error | Report an error condition | Any → Any |
heartbeat | Agent availability check | Any → Any |
Protocol Specification
Section titled “Protocol Specification”Message Structure
Section titled “Message Structure”Required Fields
Section titled “Required Fields”{ "protocol_version": "1.0", // A2A protocol version "message_id": "unique-uuid", // Unique message identifier "timestamp": "ISO-8601-timestamp", // Message creation time "sender": { // Sender identification "agent_id": "framework-specific-id", "framework": "framework-name" }, "recipient": { // Recipient identification "agent_id": "framework-specific-id", "framework": "framework-name" }, "message_type": "request|response|notification|error|heartbeat", "payload": {} // Message-specific data}Optional Fields
Section titled “Optional Fields”{ "correlation_id": "original-message-id", // For responses "signature": "cryptographic-signature", // Message authentication "encryption": { // Encryption details "algorithm": "AES-256-GCM", "key_id": "kms-key-id" }, "metadata": { // Additional context "priority": "low|normal|high|urgent", "timeout_seconds": 300, "retry_policy": {}, "custom_fields": {} }}Payload Schemas
Section titled “Payload Schemas”Request Payload
Section titled “Request Payload”{ "action": "action_name", "parameters": { "param1": "value1", "param2": "value2" }, "context": { "session_id": "session-123", "user_id": "user-456", "conversation_history": [] }}Response Payload
Section titled “Response Payload”{ "status": "success|failure|partial", "result": { "output": "response data", "confidence": 0.95, "metadata": {} }, "error": { // If status = failure "code": "error_code", "message": "error description", "details": {} }}Notification Payload
Section titled “Notification Payload”{ "event_type": "event_name", "event_data": { "key": "value" }, "severity": "info|warning|critical"}Amazon Bedrock Integration
Section titled “Amazon Bedrock Integration”Enabling A2A in Bedrock Agents
Section titled “Enabling A2A in Bedrock Agents”import boto3import json
bedrock = boto3.client('bedrock')
# Create agent with A2A supportagent = bedrock.create_agent( agentName='BedrockA2AAgent', foundationModel='anthropic.claude-3-5-sonnet-20241022-v2:0', instruction='You are an agent capable of collaborating with other agents.', agentA2AConfig={ 'enabled': True, 'allowedFrameworks': ['openai-sdk', 'langgraph', 'google-adk', 'claude-sdk'], 'requireSignature': True, 'publicKeyId': 'bedrock-agent-key-123' })
print(f"Agent created with A2A support: {agent['agentId']}")Sending A2A Messages from Bedrock
Section titled “Sending A2A Messages from Bedrock”import boto3import jsonfrom datetime import datetimeimport uuid
bedrock_runtime = boto3.client('bedrock-runtime')
# Prepare A2A messagea2a_message = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': { 'agent_id': 'bedrock:us-east-1:123456789012:agent/ABC123', 'framework': 'amazon-bedrock' }, 'recipient': { 'agent_id': 'openai:agent/XYZ789', 'framework': 'openai-sdk' }, 'message_type': 'request', 'payload': { 'action': 'analyze_sentiment', 'parameters': { 'text': 'The product quality is excellent, but shipping was delayed.', 'language': 'en' } }}
# Send via Bedrockresponse = bedrock_runtime.invoke_agent( agentId='ABC123', agentAliasId='PROD', sessionId='session-123', inputText='Send A2A message', a2aMessage=json.dumps(a2a_message))
print(f"A2A message sent: {response}")Receiving A2A Messages in Bedrock
Section titled “Receiving A2A Messages in Bedrock”import json
def lambda_handler(event, context): """ Lambda function to handle incoming A2A messages for Bedrock agent """
# Parse A2A message a2a_message = json.loads(event['body'])
# Validate protocol version if a2a_message['protocol_version'] != '1.0': return { 'statusCode': 400, 'body': json.dumps({'error': 'Unsupported protocol version'}) }
# Verify sender (implement signature verification) if not verify_signature(a2a_message): return { 'statusCode': 403, 'body': json.dumps({'error': 'Invalid signature'}) }
# Process based on message type message_type = a2a_message['message_type']
if message_type == 'request': # Process request result = process_request(a2a_message['payload'])
# Send response response_message = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': a2a_message['recipient'], 'recipient': a2a_message['sender'], 'message_type': 'response', 'correlation_id': a2a_message['message_id'], 'payload': { 'status': 'success', 'result': result } }
return { 'statusCode': 200, 'body': json.dumps(response_message) }
elif message_type == 'notification': # Handle notification handle_notification(a2a_message['payload']) return {'statusCode': 202}
else: return { 'statusCode': 400, 'body': json.dumps({'error': f'Unsupported message type: {message_type}'}) }OpenAI SDK Integration
Section titled “OpenAI SDK Integration”Setting Up OpenAI Agent for A2A
Section titled “Setting Up OpenAI Agent for A2A”from openai import OpenAIfrom typing import Dictimport json
client = OpenAI()
# Define A2A toola2a_tool = { "type": "function", "function": { "name": "send_a2a_message", "description": "Send a message to another agent using the A2A protocol", "parameters": { "type": "object", "properties": { "recipient_agent_id": { "type": "string", "description": "Target agent identifier" }, "recipient_framework": { "type": "string", "description": "Target agent framework" }, "action": { "type": "string", "description": "Action to request" }, "parameters": { "type": "object", "description": "Action parameters" } }, "required": ["recipient_agent_id", "recipient_framework", "action"] } }}
# Create OpenAI agent with A2A toolresponse = client.chat.completions.create( model="gpt-4-turbo-preview", messages=[ {"role": "system", "content": "You can collaborate with other agents using the A2A protocol."}, {"role": "user", "content": "Ask the Bedrock data analysis agent to analyze Q4 sales"} ], tools=[a2a_tool])
# Handle tool callif response.choices[0].message.tool_calls: tool_call = response.choices[0].message.tool_calls[0] if tool_call.function.name == "send_a2a_message": args = json.loads(tool_call.function.arguments) a2a_response = send_a2a_message( recipient_id=args['recipient_agent_id'], recipient_framework=args['recipient_framework'], action=args['action'], parameters=args.get('parameters', {}) ) print(f"A2A Response: {a2a_response}")Implementing A2A Message Handler
Section titled “Implementing A2A Message Handler”import uuidfrom datetime import datetimeimport requests
def send_a2a_message( recipient_id: str, recipient_framework: str, action: str, parameters: Dict) -> Dict: """ Send A2A message from OpenAI agent to another framework """
# Construct A2A message message = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': { 'agent_id': 'openai:agent/my-openai-agent', 'framework': 'openai-sdk' }, 'recipient': { 'agent_id': recipient_id, 'framework': recipient_framework }, 'message_type': 'request', 'payload': { 'action': action, 'parameters': parameters } }
# Get recipient endpoint from registry endpoint = get_agent_endpoint(recipient_id, recipient_framework)
# Send message response = requests.post( endpoint, json=message, headers={'Content-Type': 'application/json'} )
return response.json()
def receive_a2a_message(message: Dict) -> Dict: """ Receive and process A2A message in OpenAI agent """
# Validate message if message['protocol_version'] != '1.0': return {'error': 'Unsupported protocol version'}
# Process based on action action = message['payload']['action'] parameters = message['payload'].get('parameters', {})
# Use OpenAI agent to process the request response = client.chat.completions.create( model="gpt-4-turbo-preview", messages=[ {"role": "system", "content": "Process incoming A2A requests."}, {"role": "user", "content": f"Process action: {action} with parameters: {parameters}"} ] )
# Return A2A response return { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': message['recipient'], 'recipient': message['sender'], 'message_type': 'response', 'correlation_id': message['message_id'], 'payload': { 'status': 'success', 'result': { 'output': response.choices[0].message.content } } }LangGraph Integration
Section titled “LangGraph Integration”Creating A2A-Compatible LangGraph Agent
Section titled “Creating A2A-Compatible LangGraph Agent”from langgraph.graph import StateGraph, ENDfrom typing import TypedDict, Annotatedimport operatorimport uuidfrom datetime import datetime
# Define stateclass A2AState(TypedDict): messages: Annotated[list, operator.add] a2a_messages: Annotated[list, operator.add] current_task: str
def send_a2a_node(state: A2AState): """Node for sending A2A messages"""
# Extract task details task = state['current_task']
# Determine which external agent to call if 'data analysis' in task.lower(): recipient_framework = 'amazon-bedrock' recipient_id = 'bedrock:agent/data-analyzer' action = 'analyze_data' elif 'image generation' in task.lower(): recipient_framework = 'openai-sdk' recipient_id = 'openai:agent/dalle' action = 'generate_image' else: return state
# Create A2A message a2a_msg = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': { 'agent_id': 'langgraph:agent/my-graph', 'framework': 'langgraph' }, 'recipient': { 'agent_id': recipient_id, 'framework': recipient_framework }, 'message_type': 'request', 'payload': { 'action': action, 'parameters': extract_parameters(task) } }
# Send message and get response response = send_a2a_message_http(a2a_msg)
# Update state state['a2a_messages'].append({ 'sent': a2a_msg, 'received': response })
return state
def process_a2a_response_node(state: A2AState): """Node for processing A2A responses"""
if not state['a2a_messages']: return state
last_exchange = state['a2a_messages'][-1] response = last_exchange['received']
# Extract result if response['payload']['status'] == 'success': result = response['payload']['result']['output'] state['messages'].append({ 'role': 'assistant', 'content': f"Received from external agent: {result}" })
return state
# Build graphworkflow = StateGraph(A2AState)
# Add nodesworkflow.add_node("analyze_request", analyze_request_node)workflow.add_node("send_a2a", send_a2a_node)workflow.add_node("process_response", process_a2a_response_node)workflow.add_node("generate_final_response", final_response_node)
# Add edgesworkflow.add_edge("analyze_request", "send_a2a")workflow.add_edge("send_a2a", "process_response")workflow.add_edge("process_response", "generate_final_response")workflow.add_edge("generate_final_response", END)
# Set entry pointworkflow.set_entry_point("analyze_request")
# Compileapp = workflow.compile()
# Use the graphresult = app.invoke({ 'messages': [], 'a2a_messages': [], 'current_task': 'Analyze Q4 sales data and create a trend report'})Google ADK Integration
Section titled “Google ADK Integration”Google ADK Agent with A2A Support
Section titled “Google ADK Agent with A2A Support”from google import genaifrom google.genai.types import Tool, FunctionDeclarationimport json
# Define A2A tool for Google ADKa2a_send_tool = Tool( function_declarations=[ FunctionDeclaration( name="send_a2a_message", description="Send message to another agent via A2A protocol", parameters={ "type": "object", "properties": { "recipient_id": {"type": "string"}, "recipient_framework": {"type": "string"}, "action": {"type": "string"}, "parameters": {"type": "object"} }, "required": ["recipient_id", "recipient_framework", "action"] } ) ])
# Create Google ADK clientclient = genai.Client(api_key='YOUR_API_KEY')
# Use agent with A2A capabilityresponse = client.models.generate_content( model='gemini-1.5-pro', contents='Ask the Amazon Bedrock agent to summarize our Q4 financial reports', tools=[a2a_send_tool])
# Process tool callsif response.candidates[0].content.parts: for part in response.candidates[0].content.parts: if hasattr(part, 'function_call'): func_call = part.function_call if func_call.name == 'send_a2a_message': # Send A2A message result = send_a2a_from_google_adk(func_call.args) print(f"A2A Result: {result}")Claude SDK Integration
Section titled “Claude SDK Integration”Claude SDK with A2A Protocol
Section titled “Claude SDK with A2A Protocol”import anthropicimport jsonimport uuidfrom datetime import datetime
client = anthropic.Anthropic(api_key="YOUR_API_KEY")
# Define A2A toola2a_tool = { "name": "send_a2a_message", "description": "Send a message to another AI agent using the A2A protocol", "input_schema": { "type": "object", "properties": { "recipient_agent_id": { "type": "string", "description": "Full agent ID including framework prefix" }, "recipient_framework": { "type": "string", "enum": ["amazon-bedrock", "openai-sdk", "langgraph", "google-adk"] }, "action": { "type": "string", "description": "Action to request from the agent" }, "parameters": { "type": "object", "description": "Parameters for the action" } }, "required": ["recipient_agent_id", "recipient_framework", "action"] }}
# Create message with A2A toolmessage = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1024, tools=[a2a_tool], messages=[ { "role": "user", "content": "Ask the Bedrock knowledge base agent to find information about our return policy" } ])
# Process tool useif message.stop_reason == "tool_use": tool_use = message.content[-1] if tool_use.name == "send_a2a_message": # Send A2A message a2a_message = create_a2a_message( sender_id="claude:agent/my-claude-agent", sender_framework="claude-sdk", recipient_id=tool_use.input["recipient_agent_id"], recipient_framework=tool_use.input["recipient_framework"], action=tool_use.input["action"], parameters=tool_use.input.get("parameters", {}) )
# Send and get response a2a_response = send_a2a_message_http(a2a_message)
# Continue conversation with tool result response = client.messages.create( model="claude-3-5-sonnet-20241022", max_tokens=1024, messages=[ {"role": "user", "content": "Ask the Bedrock agent..."}, {"role": "assistant", "content": message.content}, { "role": "user", "content": [ { "type": "tool_result", "tool_use_id": tool_use.id, "content": json.dumps(a2a_response) } ] } ] )
print(response.content[0].text)Cross-Framework Communication Examples
Section titled “Cross-Framework Communication Examples”Example 1: Bedrock ↔ OpenAI
Section titled “Example 1: Bedrock ↔ OpenAI”# Bedrock agent asks OpenAI agent for image generation
# Bedrock sideimport boto3
bedrock = boto3.client('bedrock-runtime')
a2a_message = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': { 'agent_id': 'bedrock:agent/content-creator', 'framework': 'amazon-bedrock' }, 'recipient': { 'agent_id': 'openai:agent/dalle', 'framework': 'openai-sdk' }, 'message_type': 'request', 'payload': { 'action': 'generate_image', 'parameters': { 'prompt': 'A modern office with AI assistants helping employees', 'size': '1024x1024', 'style': 'vivid' } }}
# Send via A2A gatewayresponse = send_to_a2a_gateway(a2a_message)
# OpenAI side receives and processesdef handle_image_generation(message): client = OpenAI()
image_response = client.images.generate( model="dall-e-3", prompt=message['payload']['parameters']['prompt'], size=message['payload']['parameters']['size'], style=message['payload']['parameters']['style'] )
# Return A2A response return { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'correlation_id': message['message_id'], 'sender': message['recipient'], 'recipient': message['sender'], 'message_type': 'response', 'payload': { 'status': 'success', 'result': { 'image_url': image_response.data[0].url } } }Example 2: LangGraph ↔ Google ADK
Section titled “Example 2: LangGraph ↔ Google ADK”# LangGraph agent coordinates with Google ADK for multimodal analysis
# LangGraph sends requesta2a_msg = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'timestamp': datetime.utcnow().isoformat() + 'Z', 'sender': { 'agent_id': 'langgraph:agent/document-processor', 'framework': 'langgraph' }, 'recipient': { 'agent_id': 'google:agent/gemini-vision', 'framework': 'google-adk' }, 'message_type': 'request', 'payload': { 'action': 'analyze_document_images', 'parameters': { 'image_urls': [ 'https://storage.googleapis.com/doc1.pdf', 'https://storage.googleapis.com/doc2.pdf' ], 'analysis_type': 'extract_tables_and_charts' } }}
# Google ADK processesdef process_document_analysis(message): client = genai.Client()
results = [] for url in message['payload']['parameters']['image_urls']: response = client.models.generate_content( model='gemini-1.5-pro-vision', contents=[ {'mime_type': 'application/pdf', 'data': fetch_pdf(url)}, 'Extract all tables and charts from this document' ] ) results.append(response.text)
return create_a2a_response(message, results)Example 3: Multi-Framework Collaboration
Section titled “Example 3: Multi-Framework Collaboration”# Complex workflow involving multiple frameworks
def complex_analysis_workflow(): """ 1. Bedrock agent coordinates the workflow 2. OpenAI agent generates synthetic test data 3. Google ADK agent analyzes the data 4. LangGraph agent creates a comprehensive report 5. Claude agent reviews and provides recommendations """
# Step 1: Bedrock coordinates coordinator = BedrockA2AAgent('workflow-coordinator')
# Step 2: Request test data from OpenAI test_data_request = coordinator.send_a2a( recipient='openai:agent/data-generator', action='generate_test_data', parameters={'rows': 10000, 'schema': 'sales_data'} )
# Step 3: Send data to Google ADK for analysis analysis_request = coordinator.send_a2a( recipient='google:agent/data-analyst', action='analyze_dataset', parameters={'data': test_data_request['result']} )
# Step 4: Request report from LangGraph report_request = coordinator.send_a2a( recipient='langgraph:agent/report-generator', action='create_report', parameters={'analysis': analysis_request['result']} )
# Step 5: Get review from Claude review_request = coordinator.send_a2a( recipient='claude:agent/reviewer', action='review_report', parameters={'report': report_request['result']} )
return review_request['result']Security and Authentication
Section titled “Security and Authentication”Message Signing
Section titled “Message Signing”from cryptography.hazmat.primitives import hashes, serializationfrom cryptography.hazmat.primitives.asymmetric import rsa, paddingimport base64import json
# Generate keypairprivate_key = rsa.generate_private_key( public_exponent=65537, key_size=2048)public_key = private_key.public_key()
def sign_a2a_message(message: dict, private_key) -> str: """ Sign A2A message with private key
Returns: Base64-encoded signature """ # Create canonical representation canonical = json.dumps(message, sort_keys=True, separators=(',', ':'))
# Sign signature = private_key.sign( canonical.encode('utf-8'), padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() )
return base64.b64encode(signature).decode('utf-8')
def verify_a2a_signature(message: dict, signature: str, public_key) -> bool: """ Verify A2A message signature
Returns: True if signature is valid """ # Remove signature from message msg_copy = message.copy() msg_copy.pop('signature', None)
# Create canonical representation canonical = json.dumps(msg_copy, sort_keys=True, separators=(',', ':'))
# Verify try: public_key.verify( base64.b64decode(signature), canonical.encode('utf-8'), padding.PSS( mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA256() ) return True except Exception: return FalseAuthentication with AWS IAM
Section titled “Authentication with AWS IAM”import boto3from botocore.auth import SigV4Authfrom botocore.awsrequest import AWSRequest
def sign_a2a_with_sigv4(message: dict, region: str = 'us-east-1') -> dict: """ Sign A2A message using AWS Signature Version 4 """
session = boto3.Session() credentials = session.get_credentials()
# Create request request = AWSRequest( method='POST', url='https://a2a-gateway.amazonaws.com/messages', data=json.dumps(message), headers={'Content-Type': 'application/json'} )
# Sign request SigV4Auth(credentials, 'a2a', region).add_auth(request)
# Add signature to message message['aws_signature'] = { 'authorization': request.headers['Authorization'], 'x-amz-date': request.headers['X-Amz-Date'], 'x-amz-security-token': request.headers.get('X-Amz-Security-Token') }
return messageMessage Verification
Section titled “Message Verification”Verifying Message Integrity
Section titled “Verifying Message Integrity”import hashlibimport hmac
def verify_message_integrity(message: dict) -> bool: """ Verify that message has not been tampered with """
# Extract checksum received_checksum = message.get('checksum') if not received_checksum: return False
# Remove checksum from message msg_copy = message.copy() msg_copy.pop('checksum', None)
# Calculate checksum canonical = json.dumps(msg_copy, sort_keys=True, separators=(',', ':')) calculated_checksum = hashlib.sha256(canonical.encode('utf-8')).hexdigest()
# Compare return hmac.compare_digest(received_checksum, calculated_checksum)
def add_message_checksum(message: dict) -> dict: """ Add integrity checksum to message """
canonical = json.dumps(message, sort_keys=True, separators=(',', ':')) message['checksum'] = hashlib.sha256(canonical.encode('utf-8')).hexdigest()
return messageBest Practices
Section titled “Best Practices”1. Error Handling
Section titled “1. Error Handling”def send_a2a_with_retry(message: dict, max_retries: int = 3) -> dict: """Send A2A message with automatic retry"""
for attempt in range(max_retries): try: response = send_a2a_message_http(message)
# Check for error in response if response.get('payload', {}).get('status') == 'failure': error = response['payload']['error'] raise A2AError(error['code'], error['message'])
return response
except (ConnectionError, TimeoutError) as e: if attempt == max_retries - 1: raise time.sleep(2 ** attempt) # Exponential backoff2. Message Validation
Section titled “2. Message Validation”from jsonschema import validate, ValidationError
A2A_MESSAGE_SCHEMA = { "type": "object", "required": ["protocol_version", "message_id", "timestamp", "sender", "recipient", "message_type"], "properties": { "protocol_version": {"type": "string", "pattern": "^1\\.0$"}, "message_id": {"type": "string", "format": "uuid"}, "timestamp": {"type": "string", "format": "date-time"}, "sender": { "type": "object", "required": ["agent_id", "framework"], "properties": { "agent_id": {"type": "string"}, "framework": {"type": "string"} } } # ... additional schema ... }}
def validate_a2a_message(message: dict) -> bool: """Validate A2A message against schema""" try: validate(instance=message, schema=A2A_MESSAGE_SCHEMA) return True except ValidationError as e: print(f"Validation error: {e}") return False3. Timeout Management
Section titled “3. Timeout Management”import asyncio
async def send_a2a_with_timeout(message: dict, timeout_seconds: int = 30) -> dict: """Send A2A message with timeout"""
try: response = await asyncio.wait_for( send_a2a_async(message), timeout=timeout_seconds ) return response
except asyncio.TimeoutError: # Send timeout notification timeout_notification = { 'protocol_version': '1.0', 'message_id': str(uuid.uuid4()), 'sender': message['sender'], 'recipient': message['recipient'], 'message_type': 'error', 'correlation_id': message['message_id'], 'payload': { 'error': { 'code': 'TIMEOUT', 'message': f'Request timed out after {timeout_seconds} seconds' } } } return timeout_notificationConclusion
Section titled “Conclusion”The Agent-to-Agent (A2A) protocol enables seamless interoperability across the AI agent ecosystem. With standardized message formats, cryptographic verification, and support for major frameworks, A2A empowers developers to build sophisticated multi-agent systems that leverage the best capabilities from each platform.
Specification: https://github.com/a2a-protocol/specification (hypothetical) Community: https://a2a-protocol.org (hypothetical) Support: Contact your framework provider for A2A implementation details
Last Updated: March 2025 Status: Generally Available (v1.0)