Components as Tools
Let your agent render rich React components directly in the chat by calling them as tools.
"""LlamaIndex agent for the Tool-Based Generative UI demo.The frontend registers `render_bar_chart` and `render_pie_chart` tools via`useComponent`. The AG-UI protocol forwards those tool definitions to theagent at request time, so the backend agent itself declares no bespoketools — the LLM sees the frontend tools through the AG-UI request payloadand picks one to call when the user asks for a chart.Mirrors `langgraph-python/src/agents/gen_ui_tool_based.py`."""from __future__ import annotationsimport osfrom llama_index.llms.openai import OpenAIfrom llama_index.protocols.ag_ui.router import get_ag_ui_workflow_routerSYSTEM_PROMPT = """You are a data visualization and creative assistant.When the user asks for a chart, call `render_bar_chart` or `render_pie_chart`with a concise title, short description, and a `data` array of`{label, value}` items. Pick bar for comparisons over a small set ofcategories; pick pie for composition / share-of-whole.When the user asks for a haiku, call `generate_haiku` with the Japanesetext, English translation, an image name, and a gradient color.Keep chat responses brief -- let the visual output do the talking."""_openai_kwargs = {}if os.environ.get("OPENAI_BASE_URL"): _openai_kwargs["api_base"] = os.environ["OPENAI_BASE_URL"]gen_ui_tool_based_router = get_ag_ui_workflow_router( llm=OpenAI(model="gpt-4o-mini", **_openai_kwargs), frontend_tools=[], backend_tools=[], system_prompt=SYSTEM_PROMPT, initial_state={},)What is this?#
Tool-based Generative UI is the simplest form of Generative UI: you register
a React component with useComponent, and CopilotKit exposes it to the
agent as a tool. When the agent calls the tool, CopilotKit renders your
component inline in the chat, passing the tool's arguments straight through
as typed props.
Unlike tool rendering, which wraps a real backend tool in a custom UI, tool-based GenUI is the component. There is no handler, no user interaction, no server-side execution. The agent decides when to show it, populates the data, and CopilotKit paints it.
When should I use this?#
Use useComponent when you want to:
- Display rich UI (cards, charts, tables, dashboards) inline in the chat
- Show structured data the agent has derived from its reasoning
- Render previews, status indicators, or visual summaries
- Let the agent present information beyond plain text
For components that need user interaction, see Human-in-the-loop. For operational transparency around a real backend tool, see Tool rendering.
How it works in code#
Nothing to wire on the agent
The AG-UI protocol forwards frontend tool definitions to the agent at
request time, so the backend agent declares no bespoke tools. The LLM sees
a component registered with useComponent through the AG-UI request payload
and picks it when the user asks for what it draws.
from llama_index.llms.openai import OpenAI
llm = OpenAI(model="gpt-4.1-mini")Tell the model when to call it
The tool arrives on every run, but a model with no instruction about it will answer in prose instead of calling it. Name the tool in the system prompt.
SYSTEM_PROMPT = """You are a data visualization assistant.
When the user asks for a chart, call `render_bar_chart` with a concise
title and a `data` array of `{label, value}` items."""useComponent takes a name, a Zod schema for its props, and the component
to render. The runtime registers it as a frontend tool so the agent can
discover it, and Zod validates the LLM's arguments before they reach your
component.
useComponent({ name: "render_bar_chart", description: "Display a bar chart with labeled numeric values.", parameters: barChartPropsSchema, render: BarChart, });The component itself is ordinary React: it reads only its props and can stream in as the agent fills the payload. The example above uses Recharts for the bar chart; it doesn't know anything about CopilotKit.
The name you pass to useComponent is what the agent sees as the tool
name. Make it a verb like render_bar_chart or show_weather so the LLM
reliably picks it when the user asks for that visualization.