examples/v2/docs/reference/use-render-tool-call.mdx
useRenderToolCall is a React hook that provides a function to render visual representations of tool calls in the chat
interface. It manages the rendering of tool execution states (InProgress, Executing, Complete) based on configured
render functions.
The useRenderToolCall hook:
import { useRenderToolCall } from "@copilotkit/react-core";
import { ToolCall } from "@ag-ui/core";
function ToolCallDisplay({ toolCall, toolMessage }) {
const renderToolCall = useRenderToolCall();
return (
<div className="tool-call-container">
{renderToolCall({ toolCall, toolMessage })}
</div>
);
}
The hook returns a function with the following signature:
(props: UseRenderToolCallProps) => React.ReactElement | null;
interface UseRenderToolCallProps {
toolCall: ToolCall; // The tool call to render
toolMessage?: ToolMessage; // Optional result message
}
The render function automatically determines the tool's status:
toolMessage is providedThe function selects renderers based on priority:
*)import { useRenderToolCall } from "@copilotkit/react-core";
import { AssistantMessage } from "@ag-ui/core";
function ChatMessage({ message }: { message: AssistantMessage }) {
const renderToolCall = useRenderToolCall();
if (!message.toolCalls) {
return <div>{message.content}</div>;
}
return (
<div>
{message.content}
{message.toolCalls.map((toolCall) => (
<div key={toolCall.id} className="tool-call">
{renderToolCall({ toolCall })}
</div>
))}
</div>
);
}
import { useRenderToolCall } from "@copilotkit/react-core";
import { Message, ToolMessage } from "@ag-ui/core";
function ChatWithResults({
message,
allMessages,
}: {
message: AssistantMessage;
allMessages: Message[];
}) {
const renderToolCall = useRenderToolCall();
return (
<>
{message.toolCalls?.map((toolCall) => {
// Find the corresponding result message
const toolMessage = allMessages.find(
(m): m is ToolMessage =>
m.role === "tool" && m.toolCallId === toolCall.id,
);
return (
<div key={toolCall.id}>
{renderToolCall({
toolCall,
toolMessage, // Pass result if available
})}
</div>
);
})}
</>
);
}
The hook works with tool renderers defined at various levels:
Renderers defined in CopilotKitProvider:
import {
CopilotKitProvider,
defineToolCallRenderer,
} from "@copilotkit/react-core";
const searchRenderer = defineToolCallRenderer({
name: "search",
render: ({ args, status }) => <SearchDisplay {...args} status={status} />,
});
function App() {
return (
<CopilotKitProvider renderToolCalls={[searchRenderer]}>
</CopilotKitProvider>
);
}
Renderers registered via useFrontendTool:
function DynamicTool() {
useFrontendTool({
name: "dynamicAction",
handler: async (args) => {
/* ... */
},
render: ({ args, status }) => <div>Dynamic tool: {status}</div>,
});
// This renderer is automatically available to useRenderToolCall
return null;
}
A fallback renderer for unmatched tools:
const wildcardRenderer = defineToolCallRenderer({
name: "*",
render: ({ name, args, status }) => (
<div className="unknown-tool">
<span>Unknown tool: {name}</span>
<span>Status: {status}</span>
</div>
),
});
The hook manages three status states automatically:
Initial state when tool is called but not executing:
// Renderer receives:
{
name: string;
args: Partial<T>; // May be incomplete during streaming
status: ToolCallStatus.InProgress;
result: undefined;
}
Active execution state:
// Renderer receives:
{
name: string;
args: T; // Complete arguments
status: ToolCallStatus.Executing;
result: undefined;
}
Final state with results:
// Renderer receives:
{
name: string;
args: T; // Complete arguments
status: ToolCallStatus.Complete;
result: string; // Tool execution result
}
The hook supports agent-specific renderers:
import { useCopilotChatConfiguration } from "@copilotkit/react-core";
function AgentAwareRendering() {
const renderToolCall = useRenderToolCall();
const config = useCopilotChatConfiguration();
// The hook automatically selects renderers based on the current agent
// Priority: agent-specific > global > wildcard
return (
<div>
<h3>Agent: {config?.agentId || "default"}</h3>
{toolCalls.map((tc) => renderToolCall({ toolCall: tc }))}
</div>
);
}