A2UI Dynamic: LLM-Driven UI Generation

Demonstrates the core A2UI value proposition: the LLM itself designs interactive UI surfaces based on user intent. .ui(UI.auto()) handles everything — it attaches the SendA2uiToClientToolset which injects the full A2UI JSON Schema at LLM request time and gives the LLM a send_a2ui_json_to_client tool.

Key concepts:

  • .ui(UI.auto()): one-line A2UI setup (schema + toolset)

  • SendA2uiToClientToolset injects schema via process_llm_request

  • The LLM generates valid A2UI JSON — no Python UI construction

  • Domain tools provide data, the LLM designs the presentation

Tip

What you’ll learn How to attach tools to an agent using the fluent API.

Source: 77_a2ui_dynamic.py

from adk_fluent import Agent
from adk_fluent._ui import UI

# --- 1. UI.auto() is the LLM-guided mode marker ---
auto = UI.auto()
assert auto.catalog == "basic"


# --- 2. Agent with .ui(UI.auto()) gets the toolset automatically ---
def get_data(query: str) -> str:
    """Get data for a query."""
    return f"Results for: {query}"


agent = (
    Agent("dynamic_ui", "gemini-2.5-flash")
    .instruct("Create interactive UIs based on user requests.")
    .tool(get_data)
    .ui(UI.auto())
)
built = agent.build()
assert built.name == "dynamic_ui"
# Has the domain tool + the A2UI toolset (when a2ui-agent is installed)
assert len(built.tools) >= 1

# --- 3. Declarative mode still works for static surfaces ---
form = UI.form("Bug Report", fields={"title": "text", "severity": ["Low", "Medium", "High"]})
form_agent = Agent("form_ui", "gemini-2.5-flash").instruct("Collect bug reports.").ui(form)
form_built = form_agent.build()
assert form_built.name == "form_ui"

# --- 4. P.ui_schema() gives lightweight component docs (safe for instruction) ---
from adk_fluent._prompt import P

schema_section = P.ui_schema()
text = schema_section.build()
assert "A2UI" in text
assert "Text" in text  # Component documented
# No JSON braces that would break ADK's {var} substitution

# --- 5. Compare: UI.auto() vs manual setup ---
# With adk-fluent (3 lines):
#   Agent("x", "gemini-2.5-flash").instruct("...").ui(UI.auto()).build()
#
# Without adk-fluent (~25 lines):
#   from a2ui.core.schema.constants import VERSION_0_9
#   from a2ui.core.schema.manager import A2uiSchemaManager
#   from a2ui.basic_catalog.provider import BasicCatalog
#   from a2ui.core.schema.common_modifiers import remove_strict_validation
#   from a2ui.adk.a2a_extension import SendA2uiToClientToolset
#   mgr = A2uiSchemaManager(VERSION_0_9, ...)
#   catalog = mgr.get_selected_catalog()
#   toolset = SendA2uiToClientToolset(a2ui_enabled=True, a2ui_catalog=catalog, ...)
#   LlmAgent(model=..., name=..., instruction=..., tools=[toolset, ...])

print("OK — 77_a2ui_dynamic")