Exposing Rasa as an A2A Sub-Agent | Rasa Documentation

Build Your First Agent in Just a Few Minutes with Rasa Copilot

New in Rasa Pro 3.17

Rasa can expose your assistant as a native Agent-to-Agent (A2A) sub-agent.

Overview

In the orchestrator model, Rasa calls external A2A agents from flows. This guide covers the inverse role: your Rasa assistant runs as an A2A sub-agent that an external orchestrator discovers and invokes.

With an a2a_server block in endpoints.yml, rasa run exposes the A2A protocol on the same port as REST and channel webhooks. The orchestrator fetches your AgentCard, sends user turns over JSON-RPC, and receives structured task lifecycle updates mapped from Rasa's dialogue state.

For full configuration reference, see A2A Server.

Prerequisites

Before enabling A2A server mode:

  1. Train a CALM assistant with the user-facing flows you want to expose as skills.
  2. Set session config in domain.ymlstart_session_after_expiry must be false so resumed orchestrator contexts do not trigger action_session_start and reset slots.
session_config:
  session_expiration_time: 60
  start_session_after_expiry: false  # required when a2a_server is enabled
  1. Plan for single-worker deployment — set SANIC_WORKERS=1 until Redis-backed A2A stores ship. Scale with additional replicas and sticky load balancing by contextId instead of multiple Sanic workers per pod.

Step 1 — Add a2a_server to endpoints.yml

Only description is required. Add a public url when orchestrators reach Rasa through a load balancer or ingress rather than localhost.

a2a_server:
  url: "http://localhost:5005"
  description: "Banking assistant for transfers and appointments"
  include_conversation_repair: true

If you use custom actions, include your action_endpoint in the same file as usual.

Step 2 — Start the Server

Run Rasa with a single Sanic worker and your trained model:

SANIC_WORKERS=1 rasa run -m models/your-model.tar.gz --endpoints endpoints.yml

To serve HTTPS directly, pass the same rasa run SSL flags used for REST and channels — not an a2a_server.tls block in endpoints.yml:

SANIC_WORKERS=1 rasa run \
  --ssl-certificate /certs/server.pem \
  --ssl-keyfile /certs/server-key.pem \
  -m models/your-model.tar.gz \
  --endpoints endpoints.yml

When Rasa sits behind a reverse proxy or ingress, set a2a_server.url to the public https://... base URL orchestrators use. See TLS in the A2A server reference.

Multi-replica Deployments

If you run more than one Rasa pod, configure your ingress or load balancer to route all A2A traffic for a given contextId to the same replica. Without this, follow-up turns, messageId deduplication, tasks/cancel, and push callbacks can break because A2A state is in-memory per pod.

Step 3 — Verify the Server is Ready

Confirm the model is loaded and the AgentCard is available:

# Model loaded (no auth configured)
curl http://localhost:5005/status

# Model loaded (Rasa auth token configured)
curl -H "Authorization: Bearer <rasa-auth-token>" http://localhost:5005/status

# Capability discovery (no A2A bearer auth configured)
curl http://localhost:5005/.well-known/agent-card.json

# Capability discovery (A2A bearer auth configured via a2a_server.auth)
curl -H "Authorization: Bearer <jwt>" http://localhost:5005/.well-known/agent-card.json

The AgentCard lists your user flows as skills. The primary signal an orchestrator uses when deciding which sub-agent to route a task to is the AgentCard.

Step 4 — Point Your Orchestrator at the Endpoint

Configure your orchestrator to use the url from the AgentCard.

Example message/send Request

curl -X POST http://localhost:5005/ \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "req-1",
    "method": "message/send",
    "params": {
      "message": {
        "role": "user",
        "parts": [{"kind": "text", "text": "I want to book an appointment"}],
        "messageId": "msg-1",
        "contextId": "ctx-user-42"
      }
    }
  }'

Step 5 — Read Structured Results from Completed Flows

Each orchestrator message creates a new A2A task_id. Rasa maps dialogue state to A2A task states: working, input_required, completed, failed, canceled, rejected, and auth_required.