Back to Crewai

A2UI

docs/v1.15.16/en/guides/frontend/a2ui.mdx

1.15.165.9 KB
Original Source

The agent assembles the UI

Tool-based rendering maps one tool to one component: the agent picks a component, you draw it. A2UI is the declarative tier of the generative-UI spectrum — instead of picking a single component, the agent assembles a surface by combining building blocks from a catalog you define.

You still own the components. The agent can only use what is in your catalog, so it can never render something you did not ship. What the agent decides is the layout and the data — how those building blocks come together into a panel, and what goes in them.

<Note> A2UI works with [Flows](/en/concepts/flows). Both modes below — dynamic and fixed-schema — run as Flows served over AG-UI, exactly like the rest of this section. </Note>

The catalog (same for every mode)

The frontend wiring is identical no matter which backend mode you use: you register a catalog on the <CopilotKit> provider with the a2ui prop.

tsx
import { CopilotKit } from "@copilotkit/react-core";
import { catalog } from "@/a2ui-catalog";

<CopilotKit runtimeUrl="/api/copilotkit" agent="assistant" a2ui={{ catalog }}>
</CopilotKit>

The catalog is your set of React components keyed by a catalog id — a FlightCard, a HotelCard, a Chart, whatever your app needs. The agent references catalog ids; CopilotKit paints your components with the data the agent supplies.

<Note> Authoring the catalog itself — the id schema, prop mapping, and composition rules — is deeper than this page covers. See the [CopilotKit A2UI docs](https://docs.copilotkit.ai) for the full authoring reference. Here we focus on the two backend modes and when to reach for each. </Note>

Two backend modes

A2UI backends come in two shapes. In dynamic mode the agent designs the surface; in fixed-schema mode you pre-author the layout and the agent only fills in data.

ModeWho designs the layoutBackendPredictability
DynamicThe agent, from the conversationNo A2UI tool — auto-injectedNovel layouts, LLM layout step
Fixed-schemaYou, up frontBackend tools return an envelopeDeterministic, no layout step

Dynamic

The Flow wires no A2UI tool. Enable A2UI on the runtime for this agent and it gains a generate_a2ui tool automatically. A sub-agent designs a surface from the conversation against your catalog, streams it to the frontend progressively, and self-heals invalid output through a validate-then-retry recovery pass. You write a normal agentic-chat Flow; the tool is injected for you.

<Steps> <Step title="Register the catalog on the provider">

Same as above — pass your catalog through the a2ui prop:

tsx
<CopilotKit runtimeUrl="/api/copilotkit" agent="assistant" a2ui={{ catalog }}>
</CopilotKit>
</Step> <Step title="Serve a normal Flow">

Your backend is a plain agentic-chat Flow. You do not define an A2UI tool — the runtime injects generate_a2ui when A2UI is enabled for the agent, and the sub-agent invents the layout from the conversation.

</Step> <Step title="Let the agent compose">

When a turn calls for UI, the agent assembles a surface from your catalog, streams the components in as it designs them, and repairs any invalid output before it reaches the screen. Your registered components render in the layout the agent chose.

</Step> </Steps>

Fixed-schema

When you already know the layout and only the data changes per call, pre-author the surface and let the agent fill it. The Flow wires backend tools (for example search_flights, search_hotels). Each tool returns an A2UI operations envelope as its result — createSurface -> updateComponents -> updateDataModel — which the frontend paints. There is no sub-agent, no generation, and no recovery pass: the layout JSON is authored by you, and only the data varies.

Install the toolkit that provides the envelope helpers:

bash
pip install ag-ui-a2ui-toolkit

Build the envelope with the toolkit helpers and emit it as the tool result:

python
from ag_ui_a2ui_toolkit import (
    A2UI_OPERATIONS_KEY,
    create_surface,
    update_components,
    update_data_model,
)
from ag_ui_crewai.sdk import copilotkit_emit_tool_result, copilotkit_stream

The tool assembles the createSurface -> updateComponents -> updateDataModel operations into an envelope keyed by A2UI_OPERATIONS_KEY, then hands it back with copilotkit_emit_tool_result(...). Because the layout is fixed, the same tool always produces the same shape — only the values differ from call to call.

When to use which

<CardGroup cols={2}> <Card title="Dynamic" icon="wand-magic-sparkles"> The layout is not known ahead of time and you want the agent to compose novel surfaces from your primitives. You gain flexibility and pay for an LLM layout step. </Card> <Card title="Fixed-schema" icon="table-cells"> The layout is known and only the data varies. More predictable and deterministic — no generation, no recovery, no LLM in the layout path. </Card> </CardGroup>

Both modes share the same frontend: one catalog, registered once on the provider. Start with fixed-schema when your surfaces are stable, and reach for dynamic when you want the agent to design layouts you did not anticipate.

<CardGroup cols={3}> <Card title="Generative UI" icon="wand-magic-sparkles" href="/edge/en/guides/frontend/generative-ui"> The full spectrum — A2UI is its declarative tier. </Card> <Card title="Tool-Based Generative UI" icon="puzzle-piece" href="/edge/en/guides/frontend/tool-based-generative-ui"> Map one tool to one component (controlled). </Card> <Card title="Agentic Generative UI" icon="list-check" href="/edge/en/guides/frontend/agentic-generative-ui"> Render live agent state (controlled). </Card> </CardGroup>