A2UI — Agent-to-UI for ADK¶
A2UI lets your agent generate real UI — cards, forms, charts, tables — not just text. Your agent outputs structured JSON, and a renderer on the client turns it into interactive components.
It's transport-agnostic: A2UI payloads work over A2A, MCP, REST, WebSockets, or any other protocol. The agent describes what to show; the client decides how to render it.
Learn more about A2UI
a2ui.org has the full specification, component gallery, catalog reference, and renderer documentation.
Quickstart¶
Install the SDK¶
1. Set up the Schema Manager¶
The A2uiSchemaManager loads component catalogs and generates system prompts
that teach the LLM how to produce valid A2UI JSON.
from a2ui.core.schema.manager import A2uiSchemaManager
from a2ui.basic_catalog.provider import BasicCatalog
schema_manager = A2uiSchemaManager(
catalogs=[
BasicCatalog.get_config(
examples_path="examples",
),
],
)
Note
The schema manager will automatically detect the A2UI version from
incoming client requests. You can also set a version explicitly by
passing version=VERSION_0_9 if needed.
Tip
If you omit the catalogs parameter, the schema manager uses the
Basic Catalog maintained by the
A2UI team, which includes common components like Text, Card, Button,
Image, and more. You can also create custom catalogs
with domain-specific components, or mix the basic catalog with your own
— see Advanced patterns below.
2. Generate the system prompt¶
The generate_system_prompt method combines your agent's role description with
the A2UI JSON schema and few-shot examples, so the LLM knows exactly how to
format its output.
instruction = schema_manager.generate_system_prompt(
role_description="You are a helpful assistant that presents information with rich UI.",
workflow_description="Analyze the user's request and return structured UI when appropriate.",
ui_description="Use cards for summaries, tables for comparisons, and forms for user input.",
include_schema=True,
include_examples=True,
allowed_components=["Heading", "Text", "Card", "Button", "Table"],
)
3. Create your ADK agent¶
Use the generated instruction as the agent's system prompt:
from google.adk.agents.llm_agent import LlmAgent
agent = LlmAgent(
model="gemini-flash-latest",
name="ui_agent",
description="An agent that generates rich UI responses.",
instruction=instruction,
)
4. Validate and stream A2UI output¶
Always validate the LLM's JSON output before sending it to the client. The SDK provides parsing, fixing, and validation utilities:
from a2ui.core.parser.parser import parse_response
from a2ui.a2a import parse_response_to_parts
# Get the active catalog's validator
selected_catalog = schema_manager.get_selected_catalog()
# Option A: Manual parse + validate
response_parts = parse_response(llm_output_text)
for part in response_parts:
if part.a2ui_json:
selected_catalog.validator.validate(part.a2ui_json)
# Option B: One-liner that returns A2A Parts
parts = parse_response_to_parts(
llm_output_text,
validator=selected_catalog.validator,
fallback_text="Here's what I found.",
)
A2UI payloads are wrapped in A2A DataPart with the MIME type
application/json+a2ui so renderers can identify them:
from a2ui.a2a import create_a2ui_part
part = create_a2ui_part({"type": "Card", "props": {"title": "Hello"}})
# → DataPart(data={...}, metadata={"mimeType": "application/json+a2ui"})
Advanced patterns¶
Dynamic catalogs¶
For agents that need different UI components depending on context (e.g., charts for data queries, forms for configuration), resolve the catalog at runtime and store it in session state:
async def _prepare_session(self, context, run_request, runner):
session = await super()._prepare_session(context, run_request, runner)
# Determine client capabilities from request metadata
capabilities = context.message.metadata.get("a2ui_client_capabilities")
# Select the right catalog
a2ui_catalog = self.schema_manager.get_selected_catalog(
client_ui_capabilities=capabilities
)
examples = self.schema_manager.load_examples(a2ui_catalog, validate=True)
# Store in session state for tool access
await runner.session_service.append_event(
session,
Event(
actions=EventActions(
state_delta={
"system:a2ui_enabled": True,
"system:a2ui_catalog": a2ui_catalog,
"system:a2ui_examples": examples,
}
),
),
)
return session
Custom catalogs¶
You can define your own component catalogs for domain-specific UI:
from a2ui.core.schema.manager import CatalogConfig
schema_manager = A2uiSchemaManager(
catalogs=[
BasicCatalog.get_config(),
CatalogConfig.from_path(
name="my_dashboard_catalog",
catalog_path="catalogs/dashboard.json",
examples_path="catalogs/dashboard_examples",
),
],
)
Multi-agent orchestration¶
Orchestrator agents can aggregate A2UI capabilities from sub-agents and advertise them in the agent card:
from a2ui.a2a import get_a2ui_agent_extension
# Collect catalog IDs from sub-agents
supported_catalog_ids = set()
for subagent in subagents:
for extension in subagent_card.capabilities.extensions:
if extension.uri == "https://a2ui.org/a2a-extension/a2ui/v0.9":
supported_catalog_ids.update(
extension.params.get("supportedCatalogIds") or []
)
# Advertise in the orchestrator's AgentCard
agent_card = AgentCard(
capabilities=AgentCapabilities(
extensions=[
get_a2ui_agent_extension(
supported_catalog_ids=list(supported_catalog_ids),
)
]
)
)
Samples¶
The A2UI repository includes ADK sample agents you can run immediately:
| Sample | Description |
|---|---|
| contact_lookup | Simple agent with static schema — looks up contacts and displays results as cards |
| restaurant_finder | Static schema agent for searching and displaying restaurant information |
| rizzcharts | Dynamic catalog agent that selects chart components based on context |
| orchestrator | Multi-agent setup that delegates to sub-agents and aggregates UI capabilities |