Skip to main content
When a2a_server is configured in endpoints.yml, Rasa registers A2A JSON-RPC routes on the same Sanic port as REST and channel webhooks. An external orchestrator discovers capabilities via AgentCard, sends user turns, and receives task lifecycle updates mapped from Rasa’s dialogue state. This page describes the sub-agent (server) architecture. For Rasa as an orchestrator that calls external A2A agents, see Integrating External Agents via A2A. For configuration and operations, see A2A Server and Exposing Rasa as an A2A Sub-Agent.

Deployment topology

A2A sub-agent deployment topology Shaded regions show ownership: the orchestrator (A2A client) discovers skills, sends and receives turns over JSON-RPC, and optionally hosts a push callback URL. Rasa (A2A server) exposes public endpoints, runs flows, and POSTs task updates when push notifications are enabled (dashed arrow). The orchestrator owns end-user routing and multi-agent coordination. Rasa owns flow execution, slot collection, conversation repair, and NLG within its advertised skills.

The governed agent contract

Rasa exposes a bounded contract to orchestrators. Internal dialogue machinery stays private.

What Rasa exposes

What Rasa keeps internal

End-user identity and backend context belong in A2A message.metadata, DataPart slot pre-seeding, or orchestrator-side session management β€” not in the sub-agent JWT.

Context and task mapping

A2A context and task mapping Blue: identifiers the orchestrator supplies on each A2A message. Purple: how Rasa maps and tracks them server-side. ConversationInactive and tracker inactivity do not release an input_required context. With start_session_after_expiry: false (required for A2A), the next message on the same contextId resumes the flow without running action_session_start.

Task state lifecycle

After each message is processed, TaskStateMapper derives the A2A task state from the dialogue stack and latest action. Evaluation follows this priority order:
  1. auth_required β€” orchestrator bearer token missing or invalid
  2. rejected β€” CannotHandlePatternFlowStackFrame active (outside jurisdiction)
  3. failed β€” InternalErrorPatternFlowStackFrame active
  4. canceled β€” CancelPatternFlowStackFrame active or orchestrator tasks/cancel
  5. completed β€” user-facing flow emitted FlowCompleted this turn; no user flows remain on the stack; bot waits for user input (even when pattern_completed is active at action_listen)
  6. input_required β€” CompletedPatternFlowStackFrame active; no user flows on stack; include_conversation_repair is true; bot waits for user input; no user flow completed this turn
  7. completed β€” CompletedPatternFlowStackFrame active and no user flows on stack (including when conversation repair is disabled)
  8. input_required β€” last action waits for user input (collect step, greet, etc.)
  9. working β€” otherwise (processing or mid-turn streaming)
A2A task state lifecycle

State reference

When include_conversation_repair: false, conversation-repair stack frames map to completed instead of input_required.

Message processing path

A2A message processing path Blue groups: orchestrator-side request, response, and optional push callback. Purple group: Rasa server processing from JSON-RPC ingress through CALM to task status and push transport. On each turn:
  1. Optional bearer JWT is validated (orchestrator auth).
  2. Orchestrator slot pre-seeding is applied as SetSlotCommands before dialogue processing.
  3. Rasa executes flows via the standard CALM pipeline.
  4. A2AOutputChannel maps tracker state to A2A task updates, including structured DataPart and TextPart.
  5. Optional push notification POSTs fire on state transitions when enabled.

Scaling constraints (in v3.17)

Until persistent A2A task and message stores ship:
  • SANIC_WORKERS=1 per replica β€” idempotency, cancel, and max_contexts are per-worker.
  • Horizontal scaling β€” add replicas with load balancer sticky routing keyed on contextId so the same orchestrator context hits the same pod. A2A task caches, deduplication, in-flight queues, and push config are in-memory per replica until persistent stores ship. Derive the routing key from the JSON body contextId, the X-A2A-Context-Id header, or an a2a-context-id cookie set by the ingress. See Multi-replica load balancing.
  • Hot model reload β€” PUT /model does not refresh the AgentCard or re-wire the A2A executor; restart after model deploys that change advertised skills.
Not tested for 3.17Running Rasa as an A2A sub-agent while also invoking external sub-agents (sub_agents/ with protocol: a2a) is not tested for v3.17.