CopilotChatToolCallGroup
Collapses tool calls the agent makes in a row into one summary
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.
Overview
CopilotChatToolCallGroup draws tool calls the agent makes in a row as one collapsed summary instead of a card per call. While a call runs, the summary names it ("Running read_file src/app.ts"). Once every call has finished, it reads "Used 3 tools" with the tools it used, and how many failed, and opens to the calls.
It is the default group slot of CopilotChatToolCallsView. CopilotChatMessageView chooses its appearance from toolCallDisplay: "grouped" draws a card, "line" a line of text and "stacked" a stack.
Only calls drawn by a renderer that opts into grouping join a group. CopilotKit's built-in card, from useDefaultRenderTool(), does, and draws itself as a compact row inside the card and line appearances and an open stack: status, tool name and main argument, opening to the arguments and result. A custom renderer opts in with group: true and draws whatever it draws inside the group:
useDefaultRenderTool({ render: MyToolRow, group: true });
// or, for one tool
useRenderTool({
name: "run_command",
parameters,
render: CommandRow,
group: true,
});The group is the group slot in the "grouped", "line" and "stacked" displays. The "turn" display draws calls as rows inside the reply and doesn't use it.
Import
import { CopilotChatToolCallGroup } from "@copilotkit/react-core/v2";
import type {
CopilotChatToolCallGroupProps,
ToolCallEntry,
} from "@copilotkit/react-core/v2";Props
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Usage
Choosing an Appearance
The usual way is the message view's toolCallDisplay:
<CopilotChat messageView={{ toolCallDisplay: "stacked" }} />The group slot sets it directly, for example on a standalone tool-calls view:
<CopilotChatToolCallsView
message={message}
messages={messages}
group={{ appearance: "line" }}
/>Restyling the Group
<CopilotChat
messageView={{
assistantMessage: {
toolCallsView: { group: "rounded-2xl border-dashed" },
},
}}
/>Replacing the Group
A replacement receives the same props as the default. Use renderCall to keep each call drawn by its registered renderer.
import type { CopilotChatToolCallGroupProps } from "@copilotkit/react-core/v2";
function ToolTimeline({ calls, renderCall }: CopilotChatToolCallGroupProps) {
const running = calls.some((call) => !call.toolMessage);
return (
<details className="my-3">
<summary>{running ? "Working…" : `Ran ${calls.length} tools`}</summary>
{calls.map((call) => (
<div key={call.toolCall.id}>{renderCall(call)}</div>
))}
</details>
);
}
<CopilotChat
messageView={{
assistantMessage: { toolCallsView: { group: ToolTimeline } },
}}
/>;Behavior
- What Groups: Calls drawn by a renderer with
group: truejoin the open group. Assistant text, a user, reasoning or activity message, or any other call ends it. A custom renderer that leavesgroupunset always shows its calls on their own, since it may draw nothing. Calls with no renderer at all render nothing and don't end it. - Collapsed by Default: Groups start closed and stay as the user leaves them.
- Failures: A call whose tool message has an
errorshows a failed icon, and the summary shows the failed count in place of "Done" ("1 failed"). - Stopped Runs: A call that never got a result before the run ended (the user pressed Stop, or the run errored) shows as stopped, not running, and the summary reads "Stopped".
- Accessibility: The summary is a button with
aria-expandedandaria-controls. Closed content stays mounted but isinert. Expand and collapse animations are off when the user prefers reduced motion. - Test Hooks: The root carries
data-testid="copilot-tool-call-group",data-appearanceanddata-state("running","done","failed"or"stopped"). Rows drawn by the built-in renderer keepdata-testid="copilot-tool-render"and itsdata-tool-name,data-status,data-argsanddata-resultattributes.
CopilotChatWorkSummary
The line at the top of each reply when the message view's toolCallDisplay is "turn". While the agent works it reads "Working" with a timer, and it stands in for the cursor. Once the reply is done it reads "Worked for 9s · 7 tools" and toggles the narration and calls that were folded away. It is the message view's workSummary slot.
Import
import { CopilotChatWorkSummary } from "@copilotkit/react-core/v2";
import type { CopilotChatWorkSummaryProps } from "@copilotkit/react-core/v2";Props
Also accepts every <button> attribute; the message view passes onClick to toggle the work.
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Prop
Type
Replacing the Summary
import type { CopilotChatWorkSummaryProps } from "@copilotkit/react-core/v2";
function WorkLine({
isWorking,
isOpen,
calls,
onClick,
}: CopilotChatWorkSummaryProps) {
return (
<button onClick={onClick} aria-expanded={isOpen}>
{isWorking ? "Thinking it through…" : `Checked ${calls.length} sources`}
</button>
);
}
<CopilotChat
messageView={{ toolCallDisplay: "turn", workSummary: WorkLine }}
/>;Related
CopilotChatMessageView-- SetstoolCallDisplayand renders the work summaryCopilotChatAssistantMessage--CopilotChatToolCallsView, which renders groups through itsgroupslotuseDefaultRenderTool-- Registers the built-in card that groups draw as rows