A2UI – Agent-to-UI Composition¶
The UI namespace lets agents define rich, interactive user interfaces declaratively. Agents emit A2UI protocol JSON that clients render as native widgets – no frontend code required from the agent developer.
Install
The UI namespace ships with the core package – no extra install needed:
pip install adk-fluent
The full A2UI toolset (SendA2uiToClientToolset) will be available via pip install adk-fluent[a2ui] when the a2ui-agent package is published. Until then, all composition, compilation, and presets work out of the box.
Architecture¶
Python (adk-fluent) Client (Flutter/React/Angular)
┌─────────────────────┐ ┌───────────────────────────┐
│ UI.text("Hello") │ │ │
│ >> UI.text_field() │ compile_surface() │ createSurface │
│ >> UI.button() │ ─────────────────► │ updateComponents │
│ │ A2UI JSON │ updateDataModel │
│ UISurface │ │ → Native Widgets │
└─────────────────────┘ └───────────────────────────┘
Three layers of support:
Layer |
What it provides |
Extra install? |
|---|---|---|
Core UI |
|
None |
Agent integration |
|
None |
Full A2UI toolset |
|
|
Quick Start¶
Declarative Surface¶
from adk_fluent import Agent, UI
agent = (
Agent("signup", "gemini-2.5-flash")
.instruct("Help users sign up.")
.ui(
UI.text("Create Account", variant="h1")
>> (UI.text_field("First Name") | UI.text_field("Last Name"))
>> UI.text_field("Email")
>> UI.button("Sign Up")
)
)
LLM-Guided Mode¶
from adk_fluent import Agent, T, UI
from adk_fluent._prompt import P
agent = (
Agent("creative", "gemini-2.5-pro")
.instruct(P.role("UI designer") + P.ui_schema() + P.task("Build a dashboard"))
.tools(T.google_search() | T.a2ui())
.ui(UI.auto())
)
Component Factories¶
Every A2UI component has a typed factory on UI:
from adk_fluent import UI
# Content
UI.text("Hello, World!", variant="h1") # Text (h1-h5, caption, body)
UI.image("photo.jpg", alt="Photo") # Image
UI.button("Click Me") # Button
# Input
UI.text_field("Name", bind="/user/name") # TextField with data binding
UI.text_field("Bio", variant="longText") # Long text variant
# Generic escape hatch (any A2UI component)
UI.component("BarChart", data="/data", x="date", y="value")
Layout Operators¶
Python operators compose components into layouts:
Operator |
Layout |
Example |
|---|---|---|
|
Row (horizontal) |
|
|
Column (vertical) |
|
Nest them for complex layouts:
layout = (
UI.text("Header", variant="h1")
>> (UI.text_field("Email") | UI.text_field("Password"))
>> (UI.button("Submit") | UI.button("Cancel"))
)
Data Binding and Validation¶
# Two-way data binding
field = UI.text_field("Email", bind="/user/email")
# Standalone binding object
binding = UI.bind("/user/name")
# Validation checks
UI.required("Name is required")
UI.email("Invalid email address")
Surfaces¶
A UISurface is the compilation root – a named UI that gets sent to the client:
surface = UI.surface("contact", UI.text("Contact Us") >> UI.text_field("Name"))
# Theme customization
surface = surface.with_theme(primaryColor="#3b82f6")
# Initial data model
surface = surface.with_data(name="", email="")
Compilation¶
compile_surface() converts the nested Python tree into flat A2UI JSON messages:
from adk_fluent._ui import compile_surface
msgs = compile_surface(surface)
# msgs[0] = {"createSurface": {"surfaceId": "contact", ...}}
# msgs[1] = {"updateComponents": {"components": [...]}}
Presets¶
High-level factories for common UI patterns:
# Form with typed fields
UI.form("Contact", fields={"name": "text", "email": "email", "bio": "longText"})
# Dashboard with metric cards
UI.dashboard("Metrics", cards=[
{"title": "Users", "bind": "/users"},
{"title": "Revenue", "bind": "/revenue"},
])
# Multi-step wizard
UI.wizard("Onboarding", steps=[
("Welcome", UI.text("Welcome!")),
("Profile", UI.text_field("Name")),
])
# Confirmation dialog
UI.confirm("Delete this item?", yes="Delete", no="Cancel")
# Data table
UI.table(["Name", "Email", "Role"], data_bind="/users")
Cross-Namespace Integration¶
The UI namespace integrates with every other adk-fluent namespace:
T.a2ui() – Tool Composition¶
from adk_fluent import T
# Give the agent full A2UI toolset for LLM-guided UI
agent.tools(T.google_search() | T.a2ui())
G.a2ui() – Output Guard¶
from adk_fluent._guards import G
# Validate LLM-generated UI output
agent.guard(G.pii() | G.a2ui(max_components=30))
P.ui_schema() – Prompt Injection¶
from adk_fluent._prompt import P
# Inject A2UI catalog schema into the prompt
agent.instruct(P.role("UI designer") + P.ui_schema() + P.task("Build a form"))
S.to_ui() / S.from_ui() – State Bridges¶
from adk_fluent import S
# Bridge agent state → A2UI data model
pipeline = Agent("calc").writes("total") >> S.to_ui("total", surface="dash")
# Bridge A2UI data model → agent state
pipeline = S.from_ui("name", "email", surface="form") >> Agent("processor")
M.a2ui_log() – Middleware¶
from adk_fluent._middleware import M
# Log A2UI surface operations
agent.middleware(M.a2ui_log(level="debug"))
C.with_ui() – Context¶
from adk_fluent._context import C
# Include UI surface state in agent context
agent.context(C.with_ui("dashboard"))
Agent Integration¶
.ui() Builder Method¶
Attach a UI surface to any agent:
# Declarative surface
agent = Agent("support").ui(UI.form("ticket", fields={"issue": "longText"}))
# LLM-guided mode
agent = Agent("creative").ui(UI.auto())
# Component tree
agent = Agent("form").ui(
UI.text("Sign Up") >> UI.text_field("Email") >> UI.button("Submit")
)
Pattern Helpers¶
from adk_fluent.patterns import ui_form_agent, ui_dashboard_agent
# Pre-configured form agent
intake = ui_form_agent(
"intake", "gemini-2.5-flash",
fields={"name": "text", "email": "email"},
instruction="Collect user info.",
)
# Pre-configured dashboard agent
dash = ui_dashboard_agent(
"metrics", "gemini-2.5-flash",
cards=[{"title": "Users", "bind": "/users"}],
)
Introspection¶
# .explain() shows UI surface info
agent.explain()
# => ui: {mode: declarative, surface: ticket, components: 3}
# .data_flow() includes UI concern
flow = agent.data_flow()
print(flow)
# => ui: declarative surface 'ticket'
# .doctor() warns about unbound input fields
agent.doctor()
# => [INFO] support: UI input 'Email' has no data binding
# Hint: Add bind='/path' to connect this field to the data model.
A2UI Protocol Version¶
adk-fluent bundles the A2UI v0.10 specification JSON schemas. The upstream A2UI project is at v0.8 Public Preview. Our bundled schemas are forward-compatible and will be updated as the spec evolves. Run just a2ui-scan to re-scan against newer spec versions.
Cookbook Examples¶
# |
Example |
What you’ll learn |
|---|---|---|
70 |
Components, operators, binding, surfaces, compilation |
|
71 |
|
|
72 |
|
|
73 |
|
|
74 |
|