Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.svantic.com/llms.txt

Use this file to discover all available pages before exploring further.

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.
{
  "type": "Form",
  "props": {
    "title": "Approve Bulk Deletion",
    "description": "The agent wants to delete 47 records older than 30 days.",
    "fields": [
      {
        "id": "decision",
        "type": "action",
        "label": "Your decision",
        "options": [
          { "value": "approve", "label": "Approve", "style": "primary" },
          { "value": "deny", "label": "Deny", "style": "danger" }
        ]
      }
    ]
  }
}

Field Types

TypeRenders AsSlack Support
actionButtons (approve/deny, custom actions)Yes — buttons
textText inputYes — plain text input in modal
selectDropdownYes — static select (≤5 options)
numberNumeric inputPartial — text input with hint
passwordMasked input (sensitive)No — always links to dashboard
textareaMulti-line textPartial — plain text input
checkboxCheckboxNo — links to dashboard
dateDate pickerNo — links to dashboard

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:
{
  "type": "Form",
  "props": {
    "title": "Approval Required",
    "description": "bulk_delete_records requires approval per your security policy.",
    "context": {
      "agent": "executor",
      "tool": "bulk_delete_records",
      "session_id": "sess-42",
      "policy": "bulk_operation_guard"
    },
    "fields": [
      {
        "id": "decision",
        "type": "action",
        "options": [
          { "value": "approve", "label": "Approve" },
          { "value": "deny", "label": "Deny" }
        ]
      }
    ]
  }
}
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:
{
  "type": "Form",
  "props": {
    "title": "Login Required",
    "description": "The agent needs credentials to access geico.com.",
    "fields": [
      { "id": "username", "type": "text", "label": "Username", "required": true },
      { "id": "password", "type": "password", "label": "Password", "required": true, "sensitive": true }
    ]
  }
}
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:
{
  "type": "Form",
  "props": {
    "title": "Invoice Categorization",
    "description": "Please categorize these ambiguous line items.",
    "fields": [
      {
        "id": "item_1_category",
        "type": "select",
        "label": "Server Hosting (Line 3)",
        "options": [
          { "value": "infrastructure", "label": "Infrastructure" },
          { "value": "saas", "label": "SaaS" },
          { "value": "other", "label": "Other" }
        ]
      },
      {
        "id": "item_2_category",
        "type": "select",
        "label": "Consulting Fee (Line 7)",
        "options": [
          { "value": "professional_services", "label": "Professional Services" },
          { "value": "legal", "label": "Legal" },
          { "value": "other", "label": "Other" }
        ]
      },
      { "id": "notes", "type": "textarea", "label": "Additional notes", "required": false }
    ]
  }
}
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

SurfaceA2UI SupportInteractiveSensitive Fields
DashboardFullYes — forms, buttons, inputsYes
Terminal (CLI)FullYes — Ink componentsYes
SlackPartialYes — buttons, selects, modalsNo — links to dashboard
EmailSummary onlyNo — links to dashboardNo
WebhookFull spec as JSONYes — receiving system interpretsDepends on receiver
Angular appFullYes — @a2ui/angularYes

Relationship to A2A

A2UI payloads travel inside A2A messages as DataPart objects:
{
  "kind": "data",
  "data": { "type": "Form", "props": { ... } },
  "metadata": { "mimeType": "application/json+a2ui" }
}
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:
ADK ConceptA2UI Mapping
Boolean confirmation (require_confirmation: true)A2UI form with single action field (approve/deny)
Advanced confirmation (request_confirmation(hint, payload))A2UI form with fields derived from the payload schema
FunctionResponse with confirmed: true/falseResolution with decision: approve/deny
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