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: true join the open group. Assistant text, a user, reasoning or activity message, or any other call ends it. A custom renderer that leaves group unset 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 error shows 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-expanded and aria-controls. Closed content stays mounted but is inert. Expand and collapse animations are off when the user prefers reduced motion.
  • Test Hooks: The root carries data-testid="copilot-tool-call-group", data-appearance and data-state ("running", "done", "failed" or "stopped"). Rows drawn by the built-in renderer keep data-testid="copilot-tool-render" and its data-tool-name, data-status, data-args and data-result attributes.

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