Overview
The autogen.beta.a2ui module lets an AG2 Agent produce rich, interactive user interfaces — cards, forms, lists, buttons — instead of plain text, using the A2UI protocol. The LLM emits conversational prose plus a validated A2UI message block; AG2 surfaces each message as a typed event and serializes it to A2UI's transport-agnostic wire format, so any A2UI-capable client can render it.
A2UI is a transport over a plain Agent (mirroring A2A and AG-UI): you build a normal autogen.beta.Agent and wrap it in an A2UI transport — A2UIServer (REST/SSE) or A2UIAgentExecutor (A2A) — configured with flat A2UI kwargs. There is no special agent subclass.
When To Use A2UI#
Reach for A2UI when a text answer isn't enough and the user needs to see and act on something:
- A booking or settings form the user fills in and submits.
- A list of results with per-item actions (approve, schedule, open).
- A card summarising data with clickable buttons that drive the next turn.
If you only need a conversational reply, serve a plain autogen.beta.Agent directly. A2UI is additive: an A2UI-wrapped agent still answers in prose when a UI wouldn't help.
Mental Model#
┌────────────────────────────┐ ┌─────────────────────────┐
│ Agent + A2UI transport │ server→client │ A2UI client │
│ prose + <a2ui-json> block │ createSurface / │ renders surfaces │
│ ── validate vs catalog ── │ updateComponents … │ & components │
│ emits A2UIMessageEvent │ ────────────────────▶ │ │
│ │ │ user clicks a button │
│ action → handler / prompt │ client→server │ │
│ ◀──────────────────────── │ action / functionResp │ ◀──────────────────────│
└────────────────────────────┘ (the next request) └─────────────────────────┘
The transport applies A2UI behaviour to the plain agent per turn (prompt + validation middleware) and validates every A2UI message against the chosen catalog schema (with retry-on-error), so malformed UI never reaches the client — on repeated failure it gracefully degrades to prose. A button click travels back as a client→server action (or v1.0 functionResponse) envelope, which the transport rewrites into the next turn.
Core Concepts#
| Concept | Lives in | Purpose |
|---|---|---|
Agent | autogen.beta | A plain agent — wrap it in an A2UI transport to emit validated A2UI output |
a2ui_action | autogen.beta.a2ui | Decorator turning a function into a clickable button (server event action). A click runs the handler on the server — the agent is not invoked. Declared on the transport via actions=[...] |
A2UIMessageEvent | autogen.beta.a2ui | One validated A2UI server→client message on the stream — the event seam every transport consumes |
A2UIClientEvent | autogen.beta.a2ui | One client→server interaction received from the renderer (click / functionResponse / error) — the inbound observability seam |
A2UIValidationFailedEvent | autogen.beta.a2ui | Observability signal that validation exhausted its retries and the turn degraded to prose |
A2UIClientCapabilities | autogen.beta.a2ui | Catalog negotiation — tells the agent which catalogs/components the client can render |
A2UIServer | autogen.beta.a2ui | Wraps a plain Agent into an ASGI app and serves it over HTTP, using a transport= for the wire encoding (REST/SSE or AG-UI) |
A2UIAgentExecutor | autogen.beta.a2ui.a2a | Wraps a plain Agent for the A2A transport, carrying A2UI as DataParts |
Protocol Versions#
The A2UI transports accept three protocol versions via protocol_version=:
"v0.9"(default) and"v0.9.1"— server→client surfaces and components, plus servereventactions."v1.0"— adds thecallFunction/functionResponse/actionResponseround-trip for richer client→server interaction.
Note
A2UI's wire is transport-agnostic. The same validated messages serialize identically whether served over the built-in REST/SSE adapter, embedded in an A2A DataPart, or carried by AG-UI events.
Public API#
The broadly-reusable surface is re-exported from autogen.beta.a2ui:
The agent itself is a plain autogen.beta.Agent. The HTTP server picks its wire encoding from a transport=, and the A2A executor lives in its own submodule (kept out of the core import so the package never pulls in the a2a-sdk):
Quickstart#
Build a plain Agent, then wrap it in an A2UIServer — the server is the ASGI app, the wire encoding comes from transport=, and clickable buttons are declared via actions= (the agent stays plain):
See Server for the request/response contract and a client that drives this app.
Reading Order#
- Server — wrap an
AgentinA2UIServerand drive it over HTTP (SSE / NDJSON). - A2A Transport — serve the same agent over A2A, carrying A2UI messages as canonical
DataParts. - Actions — clickable buttons backed by server-side
@a2ui_actionhandlers, the click round-trip, and the inboundA2UIClientEvent. - Catalogs & Capabilities — the component schema the agent validates against, custom catalogs, and client capability negotiation.