Skip to content

Commit fc2acea

Browse files
docs(shell-docs): update useRenderToolCall reference + schema-free tool-render opt-out (CopilotKit#5504)
## What Updates the v2 `useRenderToolCall` reference page and makes opting a tool out of the default rendering a single, schema-free call. ## Why The reference page had drifted out of sync with the hook implementation (`packages/react-core/src/v2/hooks/use-render-tool-call.tsx`) — most notably `toolCallId` in the render props, added after the doc was last touched. While documenting how to opt out of rendering, the natural example (`useRenderTool({ name: "...", render: () => <></> })`) only type-checked for the wildcard `"*"`; a named tool required a `parameters` schema, forcing a throwaway `z.any()`. This PR re-aligns the doc and removes that rough edge. ## Changes ### Docs (`showcase/shell-docs`) - `useRenderToolCall.mdx`: - Document `toolCallId` in the render-prop shape (previously undocumented). - Describe agentId-scoped lookup priority: agent-specific → unscoped → wildcard `"*"` → built-in `DefaultToolCallRenderer`. - Note args are parsed with `partialJSONParse` (streaming), not strict `JSON.parse`. - Correct `toolCall` prop to `toolCall.function.name` / `toolCall.function.arguments`. - Rewrite the Status Resolution table to match real logic (`toolMessage` presence + provider executing set). - New **"Disable default tool rendering"** section, ordered least→most specific: wildcard first (all tools), then a **"For specific tools"** subsection. Both use a schema-free `useRenderTool` call; dropped the old `useFrontendTool` handler/schema boilerplate. - `useRenderTool.mdx`: document the render-only (no-schema) named overload. ### react-core - Make `parameters` optional on the named `useRenderTool` overload, mirroring the existing wildcard path; `defineToolCallRenderer` defaults the args schema to `z.any()` when none is given. - This lets `useRenderTool({ name: "myTool", render: () => <></> }, [])` type-check with no Zod schema. Typed `parameters` behavior is unchanged. - Added a test for the named render-only registration. ## Verification - `@copilotkit/react-core` tests pass (1280) including the new case; `build` (tsc) passes. - Opt-out snippets type-checked in-package (`tsc`): wildcard, specific-name (no schema), and named-with-schema all compile. - `oxlint` (shell-docs) passes — 0 errors. - Previewed locally at `/reference/hooks/useRenderToolCall`.
2 parents 6b1421b + 62acb88 commit fc2acea

2 files changed

Lines changed: 66 additions & 10 deletions

File tree

showcase/shell-docs/src/content/reference/hooks/useRenderTool.mdx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ function App() {
107107
}
108108
```
109109

110+
### Disable rendering for a tool
111+
112+
Return an empty fragment to suppress the default UI. The wildcard (`"*"`) needs no schema; a named tool takes a pass-through schema (`z.any()`).
113+
114+
```tsx
115+
import { z } from "zod";
116+
117+
function App() {
118+
// One specific tool…
119+
useRenderTool(
120+
{ name: "searchDocs", parameters: z.any(), render: () => <></> },
121+
[],
122+
);
123+
// …or everything without its own renderer.
124+
useRenderTool({ name: "*", render: () => <></> }, []);
125+
126+
return null;
127+
}
128+
```
129+
110130
## Related
111131

112132
- [`useDefaultRenderTool`](/reference/hooks/useDefaultRenderTool)

showcase/shell-docs/src/content/reference/hooks/useRenderToolCall.mdx

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: "React hook that returns a renderer function for tool calls in the
99
The v2 `useRenderToolCall` (this page, from `@copilotkit/react-core/v2`) is a **no-argument hook** that *returns* a renderer function for consuming tool calls. It is **not** the v1 [`useRenderToolCall`](/reference/v1/hooks/useRenderToolCall), which takes a `{ name, parameters, render }` config object to *register* a renderer. To register renderers in v2, use [`useFrontendTool`](/reference/hooks/useFrontendTool) or [`useHumanInTheLoop`](/reference/hooks/useHumanInTheLoop).
1010
</Callout>
1111

12-
`useRenderToolCall` returns a renderer function that maps tool calls to React elements. The returned function looks up the first matching render configuration by tool name (falling back to a wildcard `"*"` renderer if no exact match is found), parses the JSON arguments, determines the current `ToolCallStatus`, and returns the appropriate React element. When neither a per-tool nor a wildcard renderer is registered, it falls back to the framework's built-in `DefaultToolCallRenderer`, so the returned element is effectively always non-null (the signature keeps `ReactElement | null` for type compatibility).
12+
`useRenderToolCall` returns a renderer function that maps tool calls to React elements. The returned function looks up the matching render configuration by tool name (preferring a renderer scoped to the active `agentId`, then an unscoped one, then a wildcard `"*"` renderer if no exact match is found), partially parses the JSON arguments, determines the current `ToolCallStatus`, and returns the appropriate React element. When neither a per-tool nor a wildcard renderer is registered, it falls back to the framework's built-in `DefaultToolCallRenderer`, so the returned element is effectively always non-null (the signature keeps `ReactElement | null` for type compatibility).
1313

1414
This hook is primarily used by chat UI components to display visual feedback for tool calls. In most applications you will not call it directly; instead, you register render components via `useFrontendTool` or `useHumanInTheLoop`, and the chat components use `useRenderToolCall` internally to resolve them.
1515

@@ -32,7 +32,7 @@ function useRenderToolCall(): (
3232
The input object describing the tool call to render.
3333

3434
<PropertyReference name="toolCall" type="ToolCall" required>
35-
The tool call object containing the tool `name` and its JSON-encoded `args`.
35+
The tool call object. The tool name is read from `toolCall.function.name` and the JSON-encoded arguments from `toolCall.function.arguments`.
3636
</PropertyReference>
3737

3838
<PropertyReference name="toolMessage" type="ToolMessage">
@@ -46,11 +46,11 @@ function useRenderToolCall(): (
4646

4747
The renderer determines the `ToolCallStatus` based on the inputs:
4848

49-
| Condition | Status | `result` |
50-
| ---------------------------------------------------------- | --------------------------- | --------------------------------------- |
51-
| No `toolMessage` and tool call is still loading | `ToolCallStatus.InProgress` | `undefined` |
52-
| Tool call is executing (arguments resolved, no result yet) | `ToolCallStatus.Executing` | `undefined` |
53-
| A matching `toolMessage` exists | `ToolCallStatus.Complete` | The result string from the tool message |
49+
| Condition | Status | `result` |
50+
| ------------------------------------------------------------------ | --------------------------- | --------------------------------------- |
51+
| No `toolMessage`, tool call id **not** in the executing set | `ToolCallStatus.InProgress` | `undefined` |
52+
| No `toolMessage`, tool call id **is** in the provider executing set | `ToolCallStatus.Executing` | `undefined` |
53+
| A `toolMessage` is present | `ToolCallStatus.Complete` | The result string from the tool message |
5454

5555
## ToolCallStatus
5656

@@ -168,14 +168,50 @@ function App() {
168168

169169
## Behavior
170170

171-
- **Name-based lookup**: The renderer searches registered render configurations for an exact tool name match first, then falls back to a wildcard (`"*"`) renderer, and finally to the framework's built-in `DefaultToolCallRenderer`.
172-
- **JSON parsing**: The tool call's `args` string is parsed from JSON before being passed to the render component. If parsing fails, args default to an empty object.
173-
- **Status inference**: Status is determined from the presence and state of the `toolMessage` prop. The render component always receives a consistent shape with `name`, `args`, `status`, and `result`.
171+
- **Name-based lookup with agent scoping**: The renderer searches registered render configurations for an exact tool name match first. When multiple match the same name, it prefers the one scoped to the active `agentId`, then an unscoped renderer, then the first match. If no exact match exists, it falls back to a wildcard (`"*"`) renderer, and finally to the framework's built-in `DefaultToolCallRenderer`.
172+
- **Partial JSON parsing**: The tool call's `arguments` string is parsed with `partialJSONParse` before being passed to the render component, so partially-streamed arguments can render incrementally while the tool call is still `InProgress`.
173+
- **Status inference**: Status is determined from the presence of the `toolMessage` prop and whether the tool call id is in the provider's executing set. The render component always receives a consistent shape with `name`, `toolCallId`, `args`, `status`, and `result`.
174174
- **Default renderer for unmatched tools**: If no renderer is registered for the tool name and no wildcard renderer exists, the function falls back to the built-in `DefaultToolCallRenderer` rather than returning `null`, so unhandled tool calls still paint out-of-the-box.
175175
- **Used internally by chat components**: The built-in `CopilotChat`, `CopilotPopup`, and `CopilotSidebar` components use this hook to render tool calls. You only need to call it directly when building custom chat UIs.
176176

177+
### Disable default tool rendering
178+
179+
Because the hook falls back to the built-in `DefaultToolCallRenderer` when no renderer matches, tool calls paint UI out-of-the-box. To turn that off, register a renderer that produces no UI (an empty fragment, `() => <></>`). A registered renderer takes priority over the default, so no fallback UI is shown.
180+
181+
Register a wildcard (`"*"`) renderer with [`useRenderTool`](/reference/hooks/useRenderTool) to disable the default for **all** tool calls. The wildcard overload takes no `parameters` schema, so no Zod is required. Any tool with its own named renderer still paints.
182+
183+
```tsx
184+
function App() {
185+
// Suppress the built-in DefaultToolCallRenderer for every tool call
186+
// without its own named renderer.
187+
useRenderTool({ name: "*", render: () => <></> }, []);
188+
189+
return <YourApp />;
190+
}
191+
```
192+
193+
#### For specific tools
194+
195+
To disable rendering for a single tool, register a renderer under that tool's name. Named renderers take a `parameters` schema; when you only want to suppress UI, pass a pass-through schema (`z.any()`):
196+
197+
```tsx
198+
import { z } from "zod";
199+
200+
function App() {
201+
useRenderTool(
202+
{ name: "specificTool", parameters: z.any(), render: () => <></> },
203+
[],
204+
);
205+
206+
return <YourApp />;
207+
}
208+
```
209+
210+
You can also opt out conditionally — render nothing for some statuses and real UI for others (for example, hide while `InProgress` but show a result on `Complete`), since the `render` function receives the current `status`.
211+
177212
## Related
178213

214+
- [`useRenderTool`](/reference/hooks/useRenderTool) -- register a renderer by tool name or wildcard (no schema needed for `"*"`)
179215
- [`useFrontendTool`](/reference/hooks/useFrontendTool) -- register tools with render components
180216
- [`useHumanInTheLoop`](/reference/hooks/useHumanInTheLoop) -- register interactive tools with render components
181217
- [`CopilotKit`](/reference/v2) -- configure static render tool calls at the provider level

0 commit comments

Comments
 (0)