Skip to main content

A2UI (Agent-to-User Interface)

PraisonAI supports the A2UI Protocol for generating rich, interactive user interfaces from AI agents using declarative JSON.

Overview

A2UI is Google’s open standard that allows agents to “speak UI” by sending declarative JSON describing UI components, which clients then render natively. Key Features:
  • Declarative JSON - Agents send UI descriptions, not executable code
  • Security First - Only pre-approved components from a catalog can be rendered
  • LLM-Friendly - Flat list of components with IDs, easy for LLMs to generate
  • Framework-Agnostic - Same JSON works on Web, Flutter, React, etc.
  • Incrementally Updateable - Agents can update UI progressively

Quick Start

Using A2UIAgent Wrapper

from praisonaiagents import Agent
from praisonaiagents.ui.a2ui import A2UIAgent

# Create an agent
agent = Agent(
    name="Assistant",
    role="Helper",
    goal="Help users with tasks"
)

# Wrap with A2UI
a2ui_agent = A2UIAgent(agent=agent)

# Render a text response
messages = a2ui_agent.render_text("Hello World!", title="Greeting")

# Render a list of items
messages = a2ui_agent.render_list(
    title="Results",
    items=[
        {"title": "Item 1", "description": "First item"},
        {"title": "Item 2", "description": "Second item"},
    ]
)

# Render a form
messages = a2ui_agent.render_form(
    title="Contact Form",
    fields=[
        {"id": "name", "label": "Name", "type": "text"},
        {"id": "email", "label": "Email", "type": "email"},
    ],
    submit_action="submit_form"
)

# Get JSON output
json_output = a2ui_agent.to_json()

Using Surface Builder

from praisonaiagents.ui.a2ui import Surface, PathBinding

# Create a surface
surface = Surface(surface_id="main")

# Add components using fluent API
surface.text(id="title", text="Welcome", usage_hint="h1")
surface.text(id="subtitle", text=PathBinding(path="/subtitle"), usage_hint="h2")
surface.button(
    id="action-btn",
    child="btn-text",
    action_name="do_action",
    action_context=[{"key": "id", "value": "123"}],
    primary=True
)
surface.text(id="btn-text", text="Click Me")
surface.column(id="root", children=["title", "subtitle", "action-btn"])

# Set data model
surface.set_data("subtitle", "Hello World")

# Generate A2UI messages
messages = surface.to_messages()
json_output = surface.to_json()

Using Templates

from praisonaiagents.ui.a2ui import (
    ChatTemplate,
    ListTemplate,
    FormTemplate,
    DashboardTemplate,
)

# Chat Template
chat = ChatTemplate(surface_id="chat")
chat.add_user_message("Hello!")
chat.add_agent_message("Hi there! How can I help?")
messages = chat.to_messages()

# List Template
list_ui = ListTemplate(surface_id="results", title="Search Results")
list_ui.add_item(title="Result 1", description="First result", image_url="https://...")
list_ui.add_item(title="Result 2", description="Second result")
messages = list_ui.to_messages()

# Form Template
form = FormTemplate(surface_id="contact", title="Contact Us")
form.add_text_field(id="name", label="Your Name")
form.add_email_field(id="email", label="Email Address")
form.add_number_field(id="phone", label="Phone Number")
form.set_submit_action("submit_contact", "Send Message")
messages = form.to_messages()

# Dashboard Template
dashboard = DashboardTemplate(surface_id="dashboard", title="Analytics")
dashboard.add_panel(id="stats", title="Statistics", content="1,234 users")
dashboard.add_panel(id="chart", title="Chart", content="[Chart visualization]")
messages = dashboard.to_messages()

Components

Display Components

ComponentDescription
TextComponentText display with usage hints (h1, h2, body, caption)
ImageComponentImage display with fit and usage hints
IconComponentIcon display

Layout Components

ComponentDescription
RowComponentHorizontal layout
ColumnComponentVertical layout
CardComponentCard container
ListComponentList with template support

Input Components

ComponentDescription
ButtonComponentButton with action
TextFieldComponentText input field
CheckBoxComponentCheckbox input
SliderComponentSlider input
DateTimeInputComponentDate/time picker

Data Binding

Use PathBinding to reference values in the data model:
from praisonaiagents.ui.a2ui import Surface, PathBinding

surface = Surface(surface_id="main")

# Static text
surface.text(id="static", text="Hello")

# Dynamic text from data model
surface.text(id="dynamic", text=PathBinding(path="/user/name"))

# Set the data
surface.set_data("user", {"name": "John Doe"})

Actions

Define button actions with context:
from praisonaiagents.ui.a2ui import Surface

surface = Surface(surface_id="main")

surface.text(id="btn-label", text="Book Now")
surface.button(
    id="book-btn",
    child="btn-label",
    action_name="book_restaurant",
    action_context=[
        {"key": "restaurant_id", "value": "123"},
        {"key": "name", "value": {"path": "/restaurant/name"}},  # Dynamic value
    ],
    primary=True
)

A2A Integration

A2UI works alongside the A2A (Agent-to-Agent) protocol:
from praisonaiagents.ui.a2ui import (
    Surface,
    create_a2ui_part,
    is_a2ui_part,
    get_a2ui_agent_extension,
    A2UI_MIME_TYPE,
)

# Create surface
surface = Surface(surface_id="main")
surface.text(id="msg", text="Hello from A2A")
surface.column(id="root", children=["msg"])

# Wrap as A2A DataPart
part = create_a2ui_part({"messages": surface.to_messages()})

# Check if part is A2UI
assert is_a2ui_part(part)
assert part.metadata["mimeType"] == A2UI_MIME_TYPE

# Get A2A AgentExtension for Agent Card
extension = get_a2ui_agent_extension()

Message Types

A2UI uses four message types:
MessageDescription
CreateSurfaceMessageCreate a new UI surface
UpdateComponentsMessageUpdate surface components
UpdateDataModelMessageUpdate the data model
DeleteSurfaceMessageDelete a surface
from praisonaiagents.ui.a2ui import (
    CreateSurfaceMessage,
    UpdateComponentsMessage,
    UpdateDataModelMessage,
    DeleteSurfaceMessage,
    TextComponent,
)

# Create surface
create_msg = CreateSurfaceMessage(
    surface_id="main",
    catalog_id="https://a2ui.dev/standard"
)

# Update components
text = TextComponent(id="title", text="Hello", usage_hint="h1")
update_msg = UpdateComponentsMessage(
    surface_id="main",
    components=[text]
)

# Update data model
data_msg = UpdateDataModelMessage(
    surface_id="main",
    value={"title": "Hello World"}
)

# Delete surface
delete_msg = DeleteSurfaceMessage(surface_id="main")

API Reference

A2UIAgent

A2UIAgent(
    agent: Agent,                    # PraisonAI Agent instance
    surface_id: str = None,          # Surface ID (auto-generated if not provided)
    catalog_id: str = STANDARD_CATALOG_ID,  # Component catalog
)
Methods:
  • render_text(text, title=None) - Render text response
  • render_list(title, items, ...) - Render list of items
  • render_form(title, fields, ...) - Render form
  • chat(message) - Send message to agent
  • to_messages() - Get A2UI messages
  • to_json() - Get JSON string
  • to_a2a_part() - Get A2A DataPart

Surface

Surface(
    surface_id: str,                 # Unique surface ID
    catalog_id: str = STANDARD_CATALOG_ID,  # Component catalog
)
Methods:
  • add(component) - Add a component
  • set_data(key, value) - Set data model value
  • text(id, text, ...) - Add text component
  • image(id, url, ...) - Add image component
  • button(id, child, ...) - Add button component
  • card(id, child, ...) - Add card component
  • row(id, children, ...) - Add row layout
  • column(id, children, ...) - Add column layout
  • list(id, children, ...) - Add list component
  • text_field(id, label, ...) - Add text field
  • to_messages() - Generate A2UI messages
  • to_json() - Generate JSON string