@copilotkit/react-core 1.70.3 → 1.71.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{copilotkit-BU3OvveB.cjs → copilotkit-BkVEkUS0.cjs} +369 -154
  2. package/dist/copilotkit-BkVEkUS0.cjs.map +1 -0
  3. package/dist/{copilotkit-Bs98akp9.d.mts → copilotkit-ChjzWqn6.d.mts} +33 -8
  4. package/dist/copilotkit-ChjzWqn6.d.mts.map +1 -0
  5. package/dist/{copilotkit-Ap_yisA5.mjs → copilotkit-D5BTo0YG.mjs} +368 -153
  6. package/dist/copilotkit-D5BTo0YG.mjs.map +1 -0
  7. package/dist/{copilotkit-X2eGbOwf.d.cts → copilotkit-DCIXZawe.d.cts} +33 -8
  8. package/dist/copilotkit-DCIXZawe.d.cts.map +1 -0
  9. package/dist/index.cjs +3 -3
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +1 -1
  12. package/dist/index.d.mts +1 -1
  13. package/dist/index.mjs +4 -4
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/index.umd.js +180 -139
  16. package/dist/index.umd.js.map +1 -1
  17. package/dist/v2/context.cjs +4 -0
  18. package/dist/v2/context.cjs.map +1 -1
  19. package/dist/v2/context.d.cts +3 -1
  20. package/dist/v2/context.d.cts.map +1 -1
  21. package/dist/v2/context.d.mts +3 -1
  22. package/dist/v2/context.d.mts.map +1 -1
  23. package/dist/v2/context.mjs +3 -1
  24. package/dist/v2/context.mjs.map +1 -1
  25. package/dist/v2/headless.cjs +20 -5
  26. package/dist/v2/headless.cjs.map +1 -1
  27. package/dist/v2/headless.d.cts +9 -4
  28. package/dist/v2/headless.d.cts.map +1 -1
  29. package/dist/v2/headless.d.mts +9 -4
  30. package/dist/v2/headless.d.mts.map +1 -1
  31. package/dist/v2/headless.mjs +21 -6
  32. package/dist/v2/headless.mjs.map +1 -1
  33. package/dist/v2/index.cjs +1 -1
  34. package/dist/v2/index.css +1 -1
  35. package/dist/v2/index.d.cts +1 -1
  36. package/dist/v2/index.d.mts +1 -1
  37. package/dist/v2/index.mjs +1 -1
  38. package/dist/v2/index.umd.js +495 -278
  39. package/dist/v2/index.umd.js.map +1 -1
  40. package/package.json +8 -9
  41. package/dist/copilotkit-Ap_yisA5.mjs.map +0 -1
  42. package/dist/copilotkit-BU3OvveB.cjs.map +0 -1
  43. package/dist/copilotkit-Bs98akp9.d.mts.map +0 -1
  44. package/dist/copilotkit-X2eGbOwf.d.cts.map +0 -1
  45. package/skills/react-core/SKILL.md +0 -110
  46. package/skills/react-core/references/agent-access.md +0 -355
  47. package/skills/react-core/references/attachments.md +0 -311
  48. package/skills/react-core/references/capabilities.md +0 -138
  49. package/skills/react-core/references/chat-components.md +0 -229
  50. package/skills/react-core/references/client-side-tools.md +0 -358
  51. package/skills/react-core/references/custom-message-renderers.md +0 -223
  52. package/skills/react-core/references/debug-mode.md +0 -140
  53. package/skills/react-core/references/human-in-the-loop.md +0 -312
  54. package/skills/react-core/references/provider-setup.md +0 -358
  55. package/skills/react-core/references/rendering-activity-messages.md +0 -201
  56. package/skills/react-core/references/rendering-tool-calls.md +0 -319
  57. package/skills/react-core/references/suggestions.md +0 -211
  58. package/skills/react-core/references/switching-agents-recipes.md +0 -161
  59. package/skills/react-core/references/switching-agents.md +0 -240
  60. package/skills/react-core/references/threads.md +0 -289
@@ -1,138 +0,0 @@
1
- # CopilotKit Capabilities (React)
2
-
3
- This skill builds on `copilotkit/agent-access`. `useCapabilities` internally
4
- calls `useAgent` and reads the `capabilities` field populated from the
5
- runtime `/info` response.
6
-
7
- `AgentCapabilities` is from `@ag-ui/core`. The hook is synchronous — there
8
- is no loading state, but the value is `undefined` until the handshake
9
- completes.
10
-
11
- ## Setup
12
-
13
- ```tsx
14
- "use client";
15
- import { useCapabilities } from "@copilotkit/react-core/v2";
16
-
17
- export function VoiceButton() {
18
- const caps = useCapabilities(); // defaults to DEFAULT_AGENT_ID
19
-
20
- // Handshake pending — show a placeholder
21
- if (caps === undefined) return <div className="skeleton h-8 w-8" />;
22
-
23
- // Handshake complete — feature-gate
24
- if (!caps.transcription) return null;
25
-
26
- return <button>Record</button>;
27
- }
28
- ```
29
-
30
- ## Core Patterns
31
-
32
- ### Scope to a specific agent
33
-
34
- ```tsx
35
- const caps = useCapabilities("research");
36
- ```
37
-
38
- ### Feature-gate tools UI
39
-
40
- ```tsx
41
- const caps = useCapabilities("default");
42
-
43
- if (caps === undefined) return <ToolsSkeleton />;
44
- if (caps.tools?.supported === false) return null;
45
- return <ToolsPanel />;
46
- ```
47
-
48
- ### Narrow optional fields defensively
49
-
50
- `AgentCapabilities` is a partial declaration — fields may be absent when
51
- the agent opts not to declare them.
52
-
53
- ```tsx
54
- const caps = useCapabilities();
55
- const maxTokens = caps?.maxOutputTokens ?? "unknown";
56
- ```
57
-
58
- ## Common Mistakes
59
-
60
- ### HIGH — Treating `undefined` as "no capabilities"
61
-
62
- Wrong:
63
-
64
- ```tsx
65
- function VoiceButton() {
66
- const caps = useCapabilities();
67
- if (!caps?.transcription) return null; // hides button forever while handshake pending
68
- return <button>Record</button>;
69
- }
70
- ```
71
-
72
- Correct:
73
-
74
- ```tsx
75
- function VoiceButton() {
76
- const caps = useCapabilities();
77
- if (caps === undefined) return <div className="skeleton h-8 w-8" />;
78
- if (!caps.transcription) return null;
79
- return <button>Record</button>;
80
- }
81
- ```
82
-
83
- `useCapabilities` returns `undefined` until the runtime `/info` handshake
84
- completes. Treating `undefined` the same as `{ transcription: false }`
85
- hides features that should be visible post-handshake.
86
-
87
- Source: `packages/react-core/src/v2/hooks/use-capabilities.tsx:7-9`
88
-
89
- ### MEDIUM — Non-null assertion on optional fields
90
-
91
- Wrong:
92
-
93
- ```tsx
94
- const caps = useCapabilities();
95
- return <div>Max tokens: {caps!.maxOutputTokens}</div>;
96
- // Crashes if agent didn't declare capabilities, or didn't declare maxOutputTokens.
97
- ```
98
-
99
- Correct:
100
-
101
- ```tsx
102
- const caps = useCapabilities();
103
- return <div>Max tokens: {caps?.maxOutputTokens ?? "unknown"}</div>;
104
- ```
105
-
106
- `AgentCapabilities` is a partial declaration. Agents opt in to each
107
- capability, so every field is optional. Narrow before deref.
108
-
109
- Source: `packages/react-core/src/v2/hooks/use-capabilities.tsx:20-22`
110
-
111
- ### MEDIUM — Expecting deep merge from server-side `capabilities`
112
-
113
- Wrong:
114
-
115
- ```ts
116
- // Server:
117
- new BuiltInAgent({
118
- // ...
119
- capabilities: { tools: { supported: true } },
120
- });
121
- // Client expects caps.tools.clientProvided to still be set by the default
122
- ```
123
-
124
- Correct:
125
-
126
- ```ts
127
- // Server — provide full category:
128
- new BuiltInAgent({
129
- // ...
130
- capabilities: { tools: { supported: true, clientProvided: true } },
131
- });
132
- ```
133
-
134
- BuiltInAgent shallow-merges capabilities at the category level — providing
135
- `tools: {...}` replaces the whole category, not just the specified fields.
136
- The client then sees exactly what was declared.
137
-
138
- Source: `packages/runtime/src/agent/index.ts:821-829,883-887`
@@ -1,229 +0,0 @@
1
- # CopilotKit Chat Components (React)
2
-
3
- This skill builds on `copilotkit/provider-setup`. Read it first — every
4
- chat component must be inside the `CopilotKit` provider (from
5
- `@copilotkit/react-core/v2`).
6
-
7
- All chat components live on `@copilotkit/react-core/v2`. The legacy
8
- `@copilotkit/react-ui` package is v1-only; its `/v2` subpath is a CSS-only
9
- import.
10
-
11
- ## Setup
12
-
13
- ```tsx
14
- "use client";
15
- import { CopilotChat } from "@copilotkit/react-core/v2";
16
- import "@copilotkit/react-core/v2/styles.css";
17
-
18
- export function ChatPanel() {
19
- return <CopilotChat agentId="default" />;
20
- }
21
- ```
22
-
23
- `<CopilotChat>` manages messages, input, streaming, attachments, and
24
- suggestions internally via `useAgent`. You do not pass `messages` or
25
- `isRunning` — they are managed for you.
26
-
27
- ## Core Patterns
28
-
29
- ### Floating popup
30
-
31
- ```tsx
32
- import { CopilotPopup } from "@copilotkit/react-core/v2";
33
-
34
- <CopilotPopup agentId="default" defaultOpen={false} />;
35
- ```
36
-
37
- ### Persistent sidebar
38
-
39
- ```tsx
40
- import { CopilotSidebar } from "@copilotkit/react-core/v2";
41
-
42
- <CopilotSidebar agentId="default">
43
- <MainAppContent />
44
- </CopilotSidebar>;
45
- ```
46
-
47
- ### Headless composition with slot primitives
48
-
49
- Use `CopilotChatView` plus the individual slot components when you need
50
- full control over messages, input, or layout. This is the path when you
51
- want to manage `messages`/`isRunning` yourself.
52
-
53
- ```tsx
54
- import {
55
- CopilotChatView,
56
- useAgent,
57
- useCopilotKit,
58
- } from "@copilotkit/react-core/v2";
59
-
60
- export function HeadlessChat() {
61
- const { agent } = useAgent({ agentId: "default" });
62
- const { copilotkit } = useCopilotKit();
63
-
64
- return (
65
- <CopilotChatView
66
- messages={agent.messages}
67
- isRunning={agent.isRunning}
68
- onSubmitMessage={async (text) => {
69
- agent.addMessage({
70
- id: crypto.randomUUID(),
71
- role: "user",
72
- content: text,
73
- });
74
- await copilotkit.runAgent({ agent });
75
- }}
76
- >
77
- {({ messageView, input }) => (
78
- <>
79
- {messageView}
80
- {input}
81
- </>
82
- )}
83
- </CopilotChatView>
84
- );
85
- }
86
- ```
87
-
88
- ### Custom labels
89
-
90
- ```tsx
91
- <CopilotChat
92
- agentId="default"
93
- labels={{
94
- chatInputPlaceholder: "Ask about the data…",
95
- welcomeMessageText: "What would you like to analyze?",
96
- }}
97
- />
98
- ```
99
-
100
- ## Common Mistakes
101
-
102
- ### CRITICAL — Importing `CopilotPanel`
103
-
104
- Wrong:
105
-
106
- ```tsx
107
- import { CopilotPanel } from "@copilotkit/react-core/v2";
108
- ```
109
-
110
- Correct:
111
-
112
- ```tsx
113
- import {
114
- CopilotChat,
115
- CopilotPopup,
116
- CopilotSidebar,
117
- CopilotChatView,
118
- } from "@copilotkit/react-core/v2";
119
- ```
120
-
121
- `CopilotPanel` does not exist in v2 (or v1). This is a common hallucination.
122
- The four chat surfaces are `CopilotChat`, `CopilotPopup`, `CopilotSidebar`,
123
- and the headless `CopilotChatView`.
124
-
125
- Source: `packages/react-core/src/v2/components/chat/index.ts` (no `CopilotPanel` export)
126
-
127
- ### CRITICAL — Importing chat components from `@copilotkit/react-ui` in v2
128
-
129
- Wrong:
130
-
131
- ```tsx
132
- import { CopilotPopup } from "@copilotkit/react-ui";
133
- import "@copilotkit/react-ui/styles.css";
134
- ```
135
-
136
- Correct:
137
-
138
- ```tsx
139
- import { CopilotPopup } from "@copilotkit/react-core/v2";
140
- import "@copilotkit/react-core/v2/styles.css";
141
- ```
142
-
143
- `@copilotkit/react-ui` is v1 only. The v2 subpath of `react-ui` is a
144
- CSS-only import — the components are not there. All v2 chat components ship
145
- from `@copilotkit/react-core/v2`.
146
-
147
- Source: `packages/react-ui/src/v2/index.ts` (CSS-only); v2 migration guide
148
-
149
- ### HIGH — Passing `messages` or `isRunning` to `<CopilotChat>`
150
-
151
- Wrong:
152
-
153
- ```tsx
154
- <CopilotChat agentId="default" messages={myMessages} isRunning={busy} />
155
- ```
156
-
157
- Correct:
158
-
159
- ```tsx
160
- // CopilotChat manages messages and isRunning internally.
161
- <CopilotChat agentId="default" />
162
-
163
- // For manual control, drop down to headless CopilotChatView. Its `children`
164
- // is a render prop that receives the bound slot elements:
165
- <CopilotChatView
166
- messages={myMessages}
167
- isRunning={busy}
168
- onSubmitMessage={handleSubmit}
169
- >
170
- {({ messageView, input }) => (
171
- <>
172
- {messageView}
173
- {input}
174
- </>
175
- )}
176
- </CopilotChatView>
177
- ```
178
-
179
- `CopilotChatProps` explicitly `Omit`s `messages` and `isRunning` — passing
180
- them is a TypeScript error, and `<CopilotChat>` always reads from its
181
- internal `useAgent` call.
182
-
183
- Source: `packages/react-core/src/v2/components/chat/CopilotChat.tsx:37-52`
184
-
185
- ### MEDIUM — Two `<CopilotChat>` with the same `agentId` + `threadId`
186
-
187
- Wrong:
188
-
189
- ```tsx
190
- <CopilotChat agentId="research" threadId="t1" />
191
- <CopilotChat agentId="research" threadId="t1" />
192
- ```
193
-
194
- Correct:
195
-
196
- ```tsx
197
- // Either use distinct threadIds...
198
- <CopilotChat agentId="research" threadId="panel-a" />
199
- <CopilotChat agentId="research" threadId="panel-b" />
200
-
201
- // ...or mount only one <CopilotChat> instance per agent/thread.
202
- ```
203
-
204
- Both components resolve to the same per-thread clone (cached in a
205
- module-level WeakMap) and submit duplicate messages. See `agent-access` for
206
- the clone semantics.
207
-
208
- Source: `packages/react-core/src/v2/hooks/use-agent.tsx:78-119`
209
-
210
- ### MEDIUM — Missing the v2 CSS import
211
-
212
- Wrong:
213
-
214
- ```tsx
215
- import { CopilotChat } from "@copilotkit/react-core/v2";
216
- // …no styles imported
217
- ```
218
-
219
- Correct:
220
-
221
- ```tsx
222
- import { CopilotChat } from "@copilotkit/react-core/v2";
223
- import "@copilotkit/react-core/v2/styles.css";
224
- ```
225
-
226
- The chat components ship unstyled without the v2 stylesheet. Import it once
227
- at the root of the app or in the same file that sets up the provider.
228
-
229
- Source: `packages/react-core/src/v2/index.ts:3` (imports `./index.css`)
@@ -1,358 +0,0 @@
1
- # CopilotKit Client-Side Tools (React)
2
-
3
- This skill builds on `copilotkit/provider-setup`. Tools registered via
4
- `useFrontendTool` execute in the browser and are exposed to the agent over
5
- AG-UI.
6
-
7
- Hook signature:
8
-
9
- ```ts
10
- useFrontendTool<T>(tool: ReactFrontendTool<T>, deps?: ReadonlyArray<unknown>);
11
- ```
12
-
13
- The hook re-registers when `tool.name`, `tool.available`, or any entry in
14
- `deps` changes. Closures inside `handler` capture React state at
15
- registration time — pass `deps` when the handler references state.
16
-
17
- ## UI-kit detection rule
18
-
19
- Before writing any `render` JSX, check the consumer's `package.json` for a
20
- UI kit and reuse its primitives:
21
-
22
- - `components/ui/*` (shadcn)
23
- - `@mui/material` (MUI)
24
- - `@chakra-ui/react` (Chakra)
25
- - `antd` (Ant Design)
26
- - `@mantine/core` (Mantine)
27
-
28
- Only write raw JSX if no kit is present.
29
-
30
- ## Setup
31
-
32
- ```tsx
33
- "use client";
34
- import { useFrontendTool } from "@copilotkit/react-core/v2";
35
- import { z } from "zod";
36
-
37
- export function SearchToolHost() {
38
- useFrontendTool({
39
- name: "searchDocs",
40
- description: "Search the in-app documentation",
41
- parameters: z.object({ query: z.string() }),
42
- handler: async ({ query }, { signal }) => {
43
- const r = await fetch(`/api/search?q=${encodeURIComponent(query)}`, {
44
- signal,
45
- });
46
- return (await r.json()).results.join("\n");
47
- },
48
- });
49
- return null;
50
- }
51
- ```
52
-
53
- `zod` is a hard peer dependency — install it alongside `@copilotkit/react-core`.
54
-
55
- ## Core Patterns
56
-
57
- ### Handler with React state + deps
58
-
59
- ```tsx
60
- const [cart, setCart] = useState<string[]>([]);
61
-
62
- useFrontendTool(
63
- {
64
- name: "addItem",
65
- parameters: z.object({ id: z.string() }),
66
- handler: async ({ id }) => {
67
- setCart((c) => [...c, id]);
68
- },
69
- },
70
- [setCart],
71
- );
72
- ```
73
-
74
- ### Forward `signal` into fetch (so `stopAgent` cancels in-flight calls)
75
-
76
- ```tsx
77
- useFrontendTool({
78
- name: "search",
79
- parameters: z.object({ q: z.string() }),
80
- handler: async ({ q }, { signal }) => {
81
- const r = await fetch(`/search?q=${q}`, { signal });
82
- return r.text();
83
- },
84
- });
85
- ```
86
-
87
- ### Render progress UI for a tool (reuse the consumer's UI kit)
88
-
89
- ```tsx
90
- // Consumer has shadcn → use Card + Skeleton
91
- import { Card, CardContent } from "@/components/ui/card";
92
- import { Skeleton } from "@/components/ui/skeleton";
93
-
94
- useFrontendTool({
95
- name: "show",
96
- parameters: z.object({ id: z.string() }),
97
- handler: async ({ id }) => fetchItem(id),
98
- render: ({ status, parameters, result }) => (
99
- <Card>
100
- {status === "inProgress" ? (
101
- <Skeleton className="h-24 w-full" />
102
- ) : (
103
- <CardContent>{result}</CardContent>
104
- )}
105
- </Card>
106
- ),
107
- });
108
- ```
109
-
110
- ### Programmatic invocation with string follow-up
111
-
112
- `copilotkit.runTool` accepts `followUp: boolean | "generate" | string`.
113
- A string is injected as a synthetic user message before the agent runs.
114
-
115
- ```tsx
116
- import { useCopilotKit } from "@copilotkit/react-core/v2";
117
-
118
- const { copilotkit } = useCopilotKit();
119
-
120
- await copilotkit.runTool({
121
- name: "searchDocs",
122
- parameters: { query: "zod" },
123
- followUp: "Summarize these results in 3 bullets", // inject as user message, run agent
124
- });
125
- ```
126
-
127
- ## Common Mistakes
128
-
129
- ### CRITICAL — Writing JSX from scratch for `render` when the app has a UI kit
130
-
131
- Wrong:
132
-
133
- ```tsx
134
- useFrontendTool({
135
- name: "show",
136
- parameters: z.object({ id: z.string() }),
137
- handler,
138
- render: ({ status }) => <div style={{ padding: 12 }}>…</div>,
139
- });
140
- ```
141
-
142
- Correct:
143
-
144
- ```tsx
145
- // First check package.json for shadcn / @mui/* / @chakra-ui/* / antd / @mantine/*, then:
146
- import { Card, CardContent } from "@/components/ui/card";
147
- import { Skeleton } from "@/components/ui/skeleton";
148
-
149
- useFrontendTool({
150
- name: "show",
151
- parameters: z.object({ id: z.string() }),
152
- handler,
153
- render: ({ status, result }) => (
154
- <Card>
155
- {status === "inProgress" ? (
156
- <Skeleton />
157
- ) : (
158
- <CardContent>{result}</CardContent>
159
- )}
160
- </Card>
161
- ),
162
- });
163
- ```
164
-
165
- Consumers almost always have a UI kit. Raw JSX produces unbranded output
166
- and skips the accessibility patterns their existing primitives encode.
167
-
168
- Source: maintainer interview (Phase 2c)
169
-
170
- ### HIGH — Stale closure inside `handler`
171
-
172
- Wrong:
173
-
174
- ```tsx
175
- useFrontendTool({
176
- name: "addItem",
177
- parameters: z.object({ id: z.string() }),
178
- handler: async ({ id }) => {
179
- addTo(cart, id); // `cart` is captured at registration — goes stale
180
- },
181
- });
182
- ```
183
-
184
- Correct:
185
-
186
- ```tsx
187
- useFrontendTool(
188
- {
189
- name: "addItem",
190
- parameters: z.object({ id: z.string() }),
191
- handler: async ({ id }) => {
192
- addTo(cart, id);
193
- },
194
- },
195
- [cart],
196
- );
197
- ```
198
-
199
- `useFrontendTool` only re-registers when `name`, `available`, or `deps`
200
- change. Without `deps`, closures over React state freeze at first mount.
201
-
202
- Source: `packages/react-core/src/v2/hooks/use-frontend-tool.tsx:45`
203
-
204
- ### HIGH — Ignoring `signal` in async handlers
205
-
206
- Wrong:
207
-
208
- ```tsx
209
- useFrontendTool({
210
- name: "search",
211
- parameters: z.object({ q: z.string() }),
212
- handler: async ({ q }) => (await fetch(`/search?q=${q}`)).text(),
213
- });
214
- ```
215
-
216
- Correct:
217
-
218
- ```tsx
219
- useFrontendTool({
220
- name: "search",
221
- parameters: z.object({ q: z.string() }),
222
- handler: async ({ q }, { signal }) =>
223
- (await fetch(`/search?q=${q}`, { signal })).text(),
224
- });
225
- ```
226
-
227
- `stopAgent` / `agent.abortRun` abort via `AbortSignal`. A handler that
228
- doesn't forward `signal` keeps fetching after cancel, racing the next turn.
229
-
230
- Source: `packages/core/src/types.ts:24-30`
231
-
232
- ### HIGH — Assuming `followUp` defaults to `false`
233
-
234
- Wrong:
235
-
236
- ```tsx
237
- useFrontendTool({
238
- name: "logAnalyticsEvent",
239
- parameters: z.object({ name: z.string() }),
240
- handler: async ({ name }) => {
241
- analytics.track(name);
242
- },
243
- // followUp omitted → defaults to TRUE. Agent re-runs after every analytics call.
244
- });
245
- ```
246
-
247
- Correct:
248
-
249
- ```tsx
250
- useFrontendTool({
251
- name: "logAnalyticsEvent",
252
- parameters: z.object({ name: z.string() }),
253
- handler: async ({ name }) => {
254
- analytics.track(name);
255
- },
256
- followUp: false, // side-effect tool — don't re-invoke the agent
257
- });
258
- ```
259
-
260
- For agent-invoked tools, run-handler checks `tool?.followUp !== false` — so
261
- `undefined` AND `true` both fire a follow-up `runAgent`. Only explicit
262
- `false` suppresses it. Pure side-effect tools must opt out or they loop.
263
-
264
- Source: `packages/core/src/core/run-handler.ts:607`
265
-
266
- ### HIGH — Missing `zod` peer dependency
267
-
268
- Wrong:
269
-
270
- ```bash
271
- pnpm install @copilotkit/react-core
272
- # zod missing — the CopilotKit provider fails to load
273
- ```
274
-
275
- Correct:
276
-
277
- ```bash
278
- pnpm install @copilotkit/react-core zod
279
- ```
280
-
281
- `zod` is a hard peer of `@copilotkit/react-core` and is imported at
282
- provider module scope. Without it the provider module throws on load.
283
-
284
- Source: `packages/react-core/package.json` (peerDependencies)
285
-
286
- ### MEDIUM — Duplicate tool name across hooks
287
-
288
- Wrong:
289
-
290
- ```tsx
291
- // ComponentA
292
- useFrontendTool({ name: "save", parameters, handler: saveA });
293
- // ComponentB mounted in same tree:
294
- useFrontendTool({ name: "save", parameters, handler: saveB });
295
- // console.warn: "Tool 'save' already exists … Overriding"
296
- ```
297
-
298
- Correct:
299
-
300
- ```tsx
301
- useFrontendTool({
302
- name: "save",
303
- agentId: "research",
304
- parameters,
305
- handler: saveA,
306
- });
307
- useFrontendTool({
308
- name: "save",
309
- agentId: "coding",
310
- parameters,
311
- handler: saveB,
312
- });
313
- ```
314
-
315
- Tool names must be globally unique per `agentId`. Second mount warns and
316
- replaces the first. Scope with `agentId` when multiple agents need their
317
- own "save" handler.
318
-
319
- Source: `packages/react-core/src/v2/hooks/use-frontend-tool.tsx:17-22`
320
-
321
- ### MEDIUM — Passing `"generate"` or a string to `useFrontendTool`'s `followUp`
322
-
323
- Wrong:
324
-
325
- ```tsx
326
- useFrontendTool({
327
- name: "searchDocs",
328
- parameters: z.object({ q: z.string() }),
329
- handler,
330
- followUp: "Summarize these results" as any, // silently truthy on registered tools
331
- });
332
- ```
333
-
334
- Correct:
335
-
336
- ```tsx
337
- // Registered tools — boolean only:
338
- useFrontendTool({
339
- name: "searchDocs",
340
- parameters: z.object({ q: z.string() }),
341
- handler,
342
- followUp: true,
343
- });
344
-
345
- // For string follow-ups, call runTool programmatically:
346
- const { copilotkit } = useCopilotKit();
347
- await copilotkit.runTool({
348
- name: "searchDocs",
349
- parameters: { q: "zod" },
350
- followUp: "Summarize these results", // injects user message, runs agent
351
- });
352
- ```
353
-
354
- `FrontendTool.followUp` is typed `boolean`. Strings are silently truthy
355
- (treated as `true`). The `"generate"` and custom-string modes only work
356
- on `copilotkit.runTool({ followUp })`.
357
-
358
- Source: `packages/core/src/types.ts:39`; `packages/core/src/core/run-handler.ts:47,763,848-863`