Skip to main content

A2UI — Agent-to-User Interface

A2UI is a structured format for agents to request input from humans. Instead of plain text prompts, agents describe what they need as a JSON spec — fields, actions, validation rules, sensitivity flags — and the rendering surface decides how to present it. A2UI is transport-agnostic. The same spec renders as a React form in the dashboard, Slack buttons, an email summary, or raw JSON in a webhook payload.

Why A2UI?

When an agent needs human input, the naive approach is to print a text message and hope the human knows what to do. That breaks down in production:
  • Approvals need structured responses. “Do you approve?” needs a yes/no button, not a free-text reply.
  • Forms need validation. An agent asking for credentials needs a password field, not a plaintext input.
  • Different channels have different capabilities. Slack can render buttons. Email can’t. The dashboard can render anything.
  • Sensitive data needs protection. Credentials should never appear in Slack notifications or logs.
A2UI solves this by separating the request definition (what the agent needs) from the rendering (how it’s presented to the human).

The Spec

An A2UI payload is a JSON object describing a set of components. Each component has a type and properties that tell the renderer what to display.

Field Types

Sensitivity

Fields can be marked sensitive: true. Sensitive fields are:
  • Never included in Slack messages, emails, or webhook payloads
  • Only rendered in the dashboard or terminal (full A2UI clients)
  • When a form contains sensitive fields, non-dashboard channels show a summary of the non-sensitive fields and a link: “This request contains sensitive fields — [complete it in the dashboard].”

Examples

Policy Approval (Simple)

When a policy guard blocks a tool invocation:
Slack renders this as: Two buttons — Approve and Deny — with the title and description as context text. Dashboard renders this as: A card with the full context, two buttons, and links to the session and agent details.

Structured Input (Credentials)

When an agent needs login credentials:
Slack renders this as: “Login Required — The agent needs credentials to access geico.com. This request contains sensitive fields — [Complete in Dashboard]” with a button linking to the dashboard. Dashboard renders this as: A form with a text input and a password input, plus a Submit button.

Multi-Field Form

When an agent needs structured data:
Slack renders this as: Too many fields for inline rendering — shows summary text + “Complete in Dashboard” button. Dashboard renders this as: Full form with two dropdowns and a text area.

How A2UI Payloads Flow

  1. Agent hits a blocking point — policy approval, tool confirmation, or explicit request_user_input call
  2. A2UI builder constructs the speca2ui_approval_builder.ts or a2ui_form_builder.ts in the mesh
  3. Spec is embedded in the A2A task — as a DataPart with MIME type application/json+a2ui
  4. Message enters input-required — the A2UI spec is persisted in task_data
  5. Notification pipeline fires — renderers translate the spec for each configured channel
  6. Human responds — from dashboard, Slack, or webhook callback
  7. Resolution flows back — field values mapped back to the A2UI field IDs, forwarded to the mesh
  8. Agent continues — receives the response and resumes execution

Rendering Surfaces

Relationship to A2A

A2UI payloads travel inside A2A messages as DataPart objects:
The application/json+a2ui MIME type tells the receiving client that this part contains a renderable A2UI spec rather than arbitrary data. When the A2A task state is input-required and the task contains an A2UI DataPart, clients know they need to render a form and send the response back.

Relationship to ADK Tool Confirmation

ADK’s require_confirmation and request_confirmation() produce tool confirmation events. Svantic maps these to A2UI specs: This means ADK tool confirmations flow through the same notification pipeline as Svantic’s policy approvals — same dashboard UI, same Slack integration, same webhook callbacks.

Further Reading