PromptRails

A2A Protocol

Enable agent-to-agent communication with Google's A2A protocol, agent cards, JSON-RPC messaging, and task lifecycle management.

A2A Protocol

PromptRails implements the Agent-to-Agent (A2A) protocol, an open standard by Google for inter-agent communication. A2A enables agents to discover each other, exchange messages, and coordinate on tasks across different systems and platforms.

What is A2A?

The A2A protocol defines a standard way for AI agents to:

  • Discover other agents through agent cards
  • Communicate using JSON-RPC messages
  • Coordinate work through a task lifecycle
  • Exchange results via task artifacts

This enables multi-agent architectures where specialized agents collaborate to solve complex problems, even when running on different platforms.

Agent Cards

An agent card is a machine-readable description of an agent's capabilities. It includes:

  • Agent name and description
  • Supported input/output formats
  • Available skills and capabilities
  • Authentication requirements
  • Endpoint URL

Agent cards enable automated discovery -- one agent can find and evaluate other agents based on their published capabilities.

# Get an agent's A2A card
card = client.a2a.get_agent_card("your-agent-id")
 
print(f"Name: {card.name}")
print(f"Description: {card.description}")
print(f"Skills: {[skill.name for skill in card.skills]}")

JSON-RPC Messaging

A2A communication uses JSON-RPC 2.0 as the transport format. Messages include:

{
  "jsonrpc": "2.0",
  "method": "tasks/send",
  "params": {
    "id": "task-id",
    "message": {
      "role": "user",
      "parts": [
        {
          "type": "text",
          "text": "Analyze this dataset and generate a report"
        }
      ]
    }
  }
}

Task Lifecycle

A2A tasks follow a defined lifecycle:

submitted -> working -> completed
                     -> failed
                     -> canceled
                     -> rejected
          -> input_required -> (user provides input) -> working

Task Statuses

StatusDescription
submittedTask has been submitted to the agent
workingAgent is actively processing the task
input_requiredAgent needs additional input to continue
completedTask finished successfully
failedTask encountered an error
canceledTask was cancelled by the requester
rejectedAgent rejected the task (e.g., outside its capabilities)

Creating and Managing Tasks

Send a Task

task = client.a2a.send_message(
    "your-agent-id",
    "Summarize the Q4 sales report",
    context_id="optional-conversation-context"
)
 
print(f"Task ID: {task.id}")
print(f"Status: {task.status.state}")

Get Task Status

task = client.a2a.get_task("task-id")
 
print(f"Status: {task.status.state}")
print(f"Messages: {len(task.messages)}")
print(f"Artifacts: {len(task.artifacts)}")

Cancel a Task

client.a2a.cancel_task("task-id")

Task Artifacts

When a task completes, the agent may produce artifacts -- structured outputs that represent the work product:

{
  "artifacts": [
    {
      "type": "text",
      "text": "The Q4 sales report shows a 15% increase..."
    },
    {
      "type": "file",
      "name": "report.pdf",
      "mimeType": "application/pdf",
      "data": "base64-encoded-content"
    }
  ]
}

Multi-Agent Coordination

A2A enables patterns like:

Sequential Processing

Agent A processes data, then passes results to Agent B for further analysis:

# Agent A: Data extraction
task_a = client.a2a.send_message(
    "data-extractor-agent",
    "Extract sales data from Q4"
)
 
# Wait for completion, then pass to Agent B
# Agent B: Analysis
task_b = client.a2a.send_message(
    "analyst-agent",
    f"Analyze: {task_a_result}",
    context_id=task_a.context_id
)

Parallel Processing

Multiple agents work on different aspects simultaneously:

import asyncio
 
async def multi_agent_analysis():
    async with AsyncPromptRails(api_key="your-key") as client:
        tasks = await asyncio.gather(
            client.a2a.send_message("sentiment-agent", "Analyze sentiment"),
            client.a2a.send_message("topic-agent", "Extract key topics"),
            client.a2a.send_message("summary-agent", "Summarize the conversation"),
        )
        return tasks

Input-Required Flow

An agent can request additional input during processing:

task = client.a2a.send_message("agent-id", initial_message)
 
# Check if the agent needs more input
if task.status and task.status.state == "input_required":
    # Provide additional input
    task = client.a2a.send_message(
        "agent-id",
        "Additional context...",
        task_id=task.id,
    )

Task Fields

FieldTypeDescription
idKSUIDUnique task identifier
context_idstringConversation context identifier
statusobjectCurrent task status payload
messagesarrayMessage history
artifactsarrayTask outputs
metadataJSONCustom metadata
created_attimestampCreation time
updated_attimestampLast update time