A2A Transport
A2UI's wire is transport-agnostic, so the same validated A2UI messages can ride an A2A exchange instead of the built-in REST adapter. The autogen.beta.a2ui.a2a submodule wraps a plain autogen.beta.Agent in an A2UIAgentExecutor, plugs it into a standard A2AServer, and carries each turn's A2UI messages as a canonical A2A DataPart.
Note
This page assumes familiarity with the A2A server. The A2UI integration is a drop-in executor for the same A2AServer — everything you know about cards, transports, and tasks still applies.
How It Maps#
| A2UI concept | A2A representation |
|---|---|
| Validated server→client messages | One DataPart (MIME application/a2ui+json) carrying the full message list, alongside a text Part for the prose |
Button click / functionResponse / client error | An inbound A2UI DataPart on the request message — a registered action runs its handler on the server; anything else is rewritten into the turn's prompt |
| Catalog negotiation | a2uiClientCapabilities on the A2A message metadata |
| Protocol support advertised | An AgentExtension on the agent card's capabilities.extensions |
The executor splits each completed turn into a text Part (the conversational prose) plus a single A2UI DataPart whose data is the JSON array of validated messages — the canonical A2A v1.0 encoding for A2UI.
Public API#
Minimal Server#
Wrap a plain Agent in A2UIAgentExecutor (with the same flat A2UI kwargs as A2UIServer, including actions= for clickable buttons), pass it to A2AServer via executor=, and advertise A2UI support on the card with a card_modifier that appends the extension:
A client connects by pointing A2AConfig(card_url=...) at the card URL, exactly as for any A2A agent — see the A2A client page.
Tip
get_a2ui_agent_extension() takes supported_catalog_ids= and accepts_inline_catalogs= to describe which catalogs the agent renders. With no arguments it advertises the version's default "basic" catalog.
Reading A2UI From the Client#
The A2UI messages ride a DataPart on the finalization message. Use is_a2ui_part to find it and get_a2ui_data to decode the payload (a list of canonical A2UI messages):
get_a2ui_data decodes both the canonical v1.0 form (a JSON array in one DataPart) and the legacy form (one object per DataPart), returning None for any part that is not A2UI-typed.
The Click Round-Trip#
A button click is sent back as an inbound A2UI DataPart on the next request message — an action envelope, or a functionResponse (v1.0) for a server-initiated callFunction. A click on a registered @a2ui_action runs that handler on the server (its messages lead the DataPart, the agent is not invoked); a click on any other button — plus error and functionResponse envelopes — is rewritten into the turn's prompt so the agent continues. A turn carrying only registered server-action clicks finalizes without invoking the agent. See Actions for the envelope shapes.
v1.0 pause/resume
With protocol_version="v1.0", a callFunction(wantResponse=true) transitions the A2A task to input-required, carrying the callFunction DataPart on the finalization message so the client knows which function to run. The client's functionResponse arrives on the next request and resumes the task — standard A2A task lifecycle, no extra bookkeeping.
Manually Building Parts#
If you serialize A2UI messages onto an A2A message yourself (outside the executor), create_a2ui_parts wraps one or many messages into DataParts: