Tool Call Rendering
Render your agent's tool calls with custom UI components.
Open your coding agent in your project's folder, or in an empty folder for a new app.This runs in a coding agent on your computer.
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 Vue 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.
Free course: See this pattern built end-to-end in Build Interactive Agents with Generative UI — a free DeepLearning.AI short course taught by CopilotKit's CEO covering the full Generative UI spectrum (Controlled, Declarative, and Open-Ended).
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 is useDefaultRenderTool() with no arguments. CopilotKit registers its built-in default renderer as the * wildcard: every tool call renders as a status card (tool name, live Running → Done state, collapsible arguments/result) without you writing any UI.
Without this composable the runtime has no * renderer and tool calls are invisible; the user only sees the assistant's final text summary.
<script setup lang="ts">
import { CopilotChat, useDefaultRenderTool } from "@copilotkit/vue/v2";
useDefaultRenderTool();
</script>
<template><CopilotChat /></template>Custom catch-all#
Once you want on-brand chrome, pass a render component or function to useDefaultRenderTool. It's a convenience wrapper around useRenderTool({ name: "*", ... }): one wildcard renderer handles every tool call, named or not.
useDefaultRenderTool({ render: BrandedToolCard });Per-tool renderers#
The most expressive path is one renderer per tool name. Each renderer receives the tool's parsed arguments, a live status, and, once the agent returns, the result.
<script setup lang="ts">
defineProps<{
parameters: { city?: string };
status: "inProgress" | "executing" | "complete";
result?: string;
}>();
</script>
<template>
<p v-if="status !== 'complete'">Checking {{ parameters.city ?? "…" }}</p>
<article v-else>
<strong>{{ parameters.city }}</strong>
<pre>{{ result }}</pre>
</article>
</template><script setup lang="ts">
import { z } from "zod";
import { CopilotChat, useDefaultRenderTool, useRenderTool } from "@copilotkit/vue/v2";
import WeatherToolCard from "./WeatherToolCard.vue";
useRenderTool({
name: "get_weather",
parameters: z.object({ city: z.string() }),
render: WeatherToolCard,
});
useDefaultRenderTool(); // wildcard fallback for every other tool
</script>
<template><CopilotChat /></template>parameters is partial while arguments stream. Read required fields only after the status advances from inProgress. The result is a string when status is complete; parse it only if your backend deliberately returns a documented serialized shape.
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. The example registers the built-in wildcard after the named get_weather renderer.
If the renderer closes over reactive values, pass Vue watch sources as the second argument:
useRenderTool({ name: "get_weather", parameters, render: WeatherToolCard }, [locale]);Finally, mount the registration component beneath the provider:
<script setup lang="ts">
import { CopilotKitProvider } from "@copilotkit/vue/v2";
import AgentExperience from "./components/AgentExperience.vue";
</script>
<template>
<CopilotKitProvider runtime-url="/api/copilotkit"><AgentExperience /></CopilotKitProvider>
</template>The backend tool definition#
The frontend renderer only sees what the agent sends down. The matching backend must expose a tool named get_weather, return structured data, and let the frontend renderer with the same name paint the card. The Vue renderer does not create or execute that backend tool.