Tool Rendering

Render your agent's tool calls with custom UI components.

What is this?

Tools are how an LLM invokes predefined, typically-deterministic functions. Tool rendering lets you decide how each of those tool calls appears in the chat. Instead of showing raw JSON, you register a React component that draws a branded card for the call — arguments, live status, and the eventual result. This is the Generative UI variant CopilotKit calls tool rendering.

Live Demo: LangGraph (Python)tool-renderingOpen full demo →

When should I use this?

Render tool calls when you want to:

  • Show users exactly what tools the agent is invoking and with what arguments
  • Display live progress indicators while a tool executes
  • Render rich, polished results once a tool completes
  • Give tool-heavy agents a transparent, on-brand chat experience

Default tool rendering (zero-config)

The simplest entry point: call useDefaultRenderTool() with no arguments. CopilotKit registers its built-in DefaultToolCallRenderer as the * wildcard — every tool call renders as a tidy status card (tool name, live Running → Done pill, collapsible arguments/result) without you writing any UI.

Without this hook the runtime has no * renderer and tool calls are invisible — the user only sees the assistant's final text summary.

Live Demo: LangGraph (Python)tool-rendering-default-catchallOpen full demo →

Custom catch-all

Once you want on-brand chrome, pass a render function to useDefaultRenderTool. It's a convenience wrapper around useRenderTool({ name: "*", ... }) — one wildcard renderer handles every tool call, named or not:

Live Demo: LangGraph (Python)tool-rendering-custom-catchallOpen full demo →

Per-tool renderers

The most expressive path is one renderer per tool name. The primary tool-rendering cell wires two: get_weather draws a branded WeatherCard, search_flights draws a FlightListCard. Each renderer receives the tool's parsed arguments, a live status, and — once the agent returns — the result:

Info

The name you pass to useRenderTool must match the tool name the agent exposes — that's how the runtime routes the call to your component.

Per-tool renderers compose with a catch-all: named renderers claim the "interesting" tools and a wildcard handles everything else. In the primary cell, the same CustomCatchallRenderer from above catches get_stock_price and roll_dice:

The backend tool definition

The frontend renderer only sees what the agent sends down. Here's the matching Python definition for get_weather — a standard LangChain tool, no CopilotKit-specific plumbing required:

Choose your AI backend

See Integrations for all available frameworks (generative-ui/tool-rendering).