New in Rasa Pro 3.17Rasa 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 ana2a_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:- Train a CALM assistant with the user-facing flows you want to expose as skills.
- Set session config in
domain.yml—start_session_after_expirymust befalseso resumed orchestrator contexts do not triggeraction_session_startand reset slots.
domain.yml
- Plan for single-worker deployment — set
SANIC_WORKERS=1until Redis-backed A2A stores ship. Scale with additional replicas and sticky load balancing bycontextIdinstead 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.
endpoints.yml
action_endpoint in the same file as usual.
Step 2 — Start the server
Run Rasa with a single Sanic worker and your trained model:rasa run SSL flags used for REST and channels — not an a2a_server.tls block in endpoints.yml:
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 givencontextId 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.
Configure consistent hashing (or session affinity) on contextId from the JSON body, the X-A2A-Context-Id header, or an a2a-context-id cookie. For Istio, apply a gateway EnvoyFilter plus a DestinationRule — see Istio on Kubernetes in the A2A server reference.
Full platform guidance: Multi-replica load balancing.
A2A routes are registered at the root of the server:
Step 3 — Verify the server is ready
Confirm the model is loaded and the AgentCard is available:agent_card_path if you configured a static card).
Step 4 — Point your orchestrator at the endpoint
Configure your orchestrator to use theurl from the AgentCard.
The orchestrator should:
- Fetch
GET /.well-known/agent-card.jsonto discover skills and capabilities. - Send user turns via
message/send(blocking) ormessage/stream(SSE streaming). - Reuse the same
contextIdacross turns in a multi-step flow. - Supply a new
messageIdper turn (retries with the samemessageIdreplay the cached result).
Example message/send request
a2a_server.auth is configured, add Authorization: Bearer <jwt> to every A2A request:
Step 5 — Read structured results from completed flows
Each orchestrator message creates a new A2Atask_id.
Rasa maps dialogue state to A2A task states: working, input_required, completed, failed, canceled, rejected, and auth_required.
Terminal and interactive-terminal responses include:
- A
TextPartwith the user-visible bot utterance (for clients that only readstatus.message). - A
DataPartwith structured state your orchestrator can parse programmatically.
input_required — flow needs more user input
The orchestrator should show the TextPart to the end user and send a follow-up message on the same contextId:
completed — flow finished
Persisted slot values from flows that declare persisted_slots are returned:
message/stream when your orchestrator needs working status updates and artifact deltas during streaming custom actions.
Blocking message/send returns only the final task.
Optional — Pass slots from the orchestrator
On each turn, the orchestrator can pre-seed domain slots before Rasa processes the user message. This is useful when the orchestrator already knows context (user ID, account type, etc.) and should not rely on the LLM parsing slot values from free text. Supply slots viamessage.metadata:
Optional — Secure the endpoint with JWT
For production, configure bearer JWT auth so only trusted orchestrators can call your sub-agent:endpoints.yml
Optional — Enable push notifications
Push notifications are disabled by default. Enable them only when your orchestrator needs HTTP callbacks for task state updates:endpoints.yml
pushNotificationConfig.url on message/send, message/stream, or via tasks/pushNotificationConfig/set.
See Push notifications for SSRF safeguards and redirect behaviour.