4d4bd19
CopilotKitDocs
  • Docs
  • Integrations
  • Reference
  • Free Developer Access
Get Started
QuickstartCoding Agents
Concepts
ArchitectureGenerative UI OverviewOSS vs Enterprise
Agentic Protocols
OverviewAG-UIAG-UI MiddlewareMCPA2A
Build Chat UIs
Prebuilt Components
CopilotChatCopilotSidebarCopilotPopup
Custom Look and Feel
CSS CustomizationSlots (Subcomponents)Fully Headless UIReasoning Messages
Multimodal AttachmentsVoice
Build Generative UI
Controlled
Tool-based Generative UITool RenderingState RenderingReasoning
Your Components
Display ComponentsInteractive Components
Declarative
A2UIDynamic Schema A2UIFixed Schema A2UI
Open-Ended
MCP Apps
Adding Agent Powers
Frontend ToolsShared State
Human-in-the-Loop
HITL OverviewPausing the Agent for InputHeadless Interrupts
Sub-AgentsAgent ConfigProgrammatic Control
Agents & Backends
Built-in Agent
Backend
Copilot RuntimeFactory ModeAG-UI
Runtime Server AdapterAuthentication
Built-in Agent (TanStack AI)
Advanced ConfigurationMCP ServersModel SelectionServer Tools
Observe & Operate
InspectorVS Code Extension
Troubleshooting
Common Copilot IssuesError Debugging & ObservabilityDebug ModeAG-UI Event InspectorHook ExplorerError Observability Connectors
Enterprise
CopilotKit PremiumHow the Enterprise Intelligence Platform WorksHow Threads & Persistence WorkObservabilitySelf-Hosting IntelligenceThreads
Deploy
AWS AgentCore
What's New
Full MCP Apps SupportLangGraph Deep Agents in CopilotKitA2UI Launches with full AG-UI SupportCopilotKit v1.50Generative UI Spec SupportA2A and MCP Handshake
Migrate
Migrate to V2Migrate to 1.8.2
Other
Contributing
Code ContributionsDocumentation Contributions
Anonymous Telemetry
Built-in Agent (TanStack AI)IntegrationsLangGraphGenerative UIA2uiFixed Schema A2UI

Fixed Schema A2UI

Pre-defined A2UI schema with dynamic data. The fastest approach — no LLM schema generation needed.

In the fixed-schema approach, you design the UI schema once (in a JSON file or using the A2UI Composer) and your agent tool only provides the data. The surface appears instantly when the tool returns.

How it works#

  1. Schema is loaded from a JSON file at startup
  2. Agent tool receives data from the LLM (e.g., flight search results)
  3. Tool returns a2ui.render() with surfaceUpdate + dataModelUpdate + beginRendering
  4. The A2UI middleware intercepts the tool result and renders the surface

Implementation#

Create the A2UI schema#

Design your schema using the A2UI Composer or write it by hand. Save it as a JSON file:

apps/agent/src/a2ui/schemas/flight_schema.json

Define the agent tool (Python)#

apps/agent/src/a2ui_fixed_schema.py
python
from copilotkit import a2ui
from langchain.tools import tool
from pathlib import Path
from typing import TypedDict

class Flight(TypedDict):
    id: str
    airline: str
    airlineLogo: str
    flightNumber: str
    origin: str
    destination: str
    date: str
    departureTime: str
    arrivalTime: str
    duration: str
    status: str
    statusIcon: str
    price: str

SURFACE_ID = "flight-search-results"
FLIGHT_SCHEMA = a2ui.load_schema(
    Path(__file__).parent / "a2ui" / "schemas" / "flight_schema.json"
)
BOOKED_SCHEMA = a2ui.load_schema(
    Path(__file__).parent / "a2ui" / "schemas" / "booked_schema.json"
)

@tool
def search_flights(flights: list[Flight]) -> str:
    """Search for flights and display results as rich cards."""
    return a2ui.render(
        operations=[
            a2ui.surface_update(SURFACE_ID, FLIGHT_SCHEMA),
            a2ui.data_model_update(SURFACE_ID, {"flights": flights}),
            a2ui.begin_rendering(SURFACE_ID, "root"),
        ],
        action_handlers={
            # Exact match: fires when a button with action.name="book_flight" is clicked
            "book_flight": [
                a2ui.surface_update(SURFACE_ID, BOOKED_SCHEMA),
                a2ui.data_model_update(SURFACE_ID, {
                    "title": "Booking Confirmed",
                    "detail": "Your flight has been booked.",
                }),
                a2ui.begin_rendering(SURFACE_ID, "root"),
            ],
            # Catch-all: fires for any button action without a specific match
            "*": [
                a2ui.data_model_update(SURFACE_ID, {
                    "status": "Action received",
                }),
            ],
        },
    )

Key points:

  • The Flight TypedDict is essential — LangGraph serializes it into the tool's JSON schema, which is what the LLM sees when deciding what data to generate.
  • action_handlers declares optimistic UI responses. When a user clicks a button, the matching handler replaces the surface instantly — no round-trip to the server.
  • "book_flight" matches the action.name from the schema button. "*" is a catch-all for any unmatched action.

Register the tool#

apps/agent/main.py
python
from src.a2ui_fixed_schema import search_flights

agent = create_agent(
    tools=[search_flights, ...],
    ...
)

Configure the runtime (TypeScript)#

Enable A2UI in your CopilotRuntime. The middleware auto-detects A2UI operations in any tool result, so no tool injection is needed here — the agent's search_flights tool returns them directly.

app/api/copilotkit/route.ts
typescript
const runtime = new CopilotRuntime({
  agents: { default: myAgent },
  a2ui: {},
});

Action handler details#

The action_handlers in the example above work together with buttons defined in the A2UI schema. Here's how the schema side looks:

Button with action context#

In your flight_schema.json, buttons declare an action with data-bound context fields. When clicked, the values are resolved from that specific card's data:

{
  "Button": {
    "label": "Book",
    "action": {
      "name": "book_flight",
      "context": [
        { "key": "flightNumber", "value": { "path": "/flightNumber" } },
        { "key": "price", "value": { "path": "/price" } }
      ]
    }
  }
}

When this button is clicked on a card showing flight AA100 at $350, the "book_flight" handler fires with context: { flightNumber: "AA100", price: "$350" }, and the surface instantly replaces with the booking confirmation.

Info

For custom frontend handling with useA2UIActionHandler, custom orchestrators, and the full resolution chain, see the Advanced — Action Handlers guide.

On this page
How it worksImplementationCreate the A2UI schemaDefine the agent tool (Python)Register the toolConfigure the runtime (TypeScript)Action handler detailsButton with action context