@copilotkit/react-core 1.71.0 → 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 (35) hide show
  1. package/dist/{copilotkit-B4Jb1QEy.cjs → copilotkit-BkVEkUS0.cjs} +5 -2
  2. package/dist/copilotkit-BkVEkUS0.cjs.map +1 -0
  3. package/dist/{copilotkit-snbJkMqQ.mjs → copilotkit-D5BTo0YG.mjs} +5 -2
  4. package/dist/copilotkit-D5BTo0YG.mjs.map +1 -0
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.mjs +1 -1
  7. package/dist/index.umd.js +4 -1
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/v2/headless.cjs +4 -1
  10. package/dist/v2/headless.cjs.map +1 -1
  11. package/dist/v2/headless.mjs +4 -1
  12. package/dist/v2/headless.mjs.map +1 -1
  13. package/dist/v2/index.cjs +1 -1
  14. package/dist/v2/index.mjs +1 -1
  15. package/dist/v2/index.umd.js +4 -1
  16. package/dist/v2/index.umd.js.map +1 -1
  17. package/package.json +8 -9
  18. package/dist/copilotkit-B4Jb1QEy.cjs.map +0 -1
  19. package/dist/copilotkit-snbJkMqQ.mjs.map +0 -1
  20. package/skills/react-core/SKILL.md +0 -110
  21. package/skills/react-core/references/agent-access.md +0 -398
  22. package/skills/react-core/references/attachments.md +0 -311
  23. package/skills/react-core/references/capabilities.md +0 -138
  24. package/skills/react-core/references/chat-components.md +0 -246
  25. package/skills/react-core/references/client-side-tools.md +0 -358
  26. package/skills/react-core/references/custom-message-renderers.md +0 -223
  27. package/skills/react-core/references/debug-mode.md +0 -140
  28. package/skills/react-core/references/human-in-the-loop.md +0 -312
  29. package/skills/react-core/references/provider-setup.md +0 -358
  30. package/skills/react-core/references/rendering-activity-messages.md +0 -201
  31. package/skills/react-core/references/rendering-tool-calls.md +0 -319
  32. package/skills/react-core/references/suggestions.md +0 -211
  33. package/skills/react-core/references/switching-agents-recipes.md +0 -161
  34. package/skills/react-core/references/switching-agents.md +0 -240
  35. package/skills/react-core/references/threads.md +0 -289
@@ -1,312 +0,0 @@
1
- # CopilotKit Human-in-the-Loop (React)
2
-
3
- This skill builds on `copilotkit/provider-setup`, `copilotkit/client-side-tools`,
4
- and `copilotkit/rendering-tool-calls`.
5
-
6
- `useHumanInTheLoop` is `useFrontendTool` minus the `handler` plus a
7
- `render` that receives a `respond` function. The hook synthesizes a
8
- Promise-based handler — the Promise resolves when `respond(result)` is
9
- called. No `respond` call → infinite hang.
10
-
11
- Status is camelCase: `"inProgress" | "executing" | "complete"`. `respond`
12
- is `undefined` except during `"executing"`.
13
-
14
- ## UI-kit detection rule
15
-
16
- Before writing the approval UI, check the consumer's `package.json` for a
17
- UI kit (shadcn `AlertDialog`, MUI `Dialog`, Chakra `Modal`, Ant `Modal`,
18
- Mantine `Modal`) and reuse it. Don't hand-roll an overlay.
19
-
20
- ## Setup
21
-
22
- ```tsx
23
- "use client";
24
- import { useHumanInTheLoop } from "@copilotkit/react-core/v2";
25
- import { z } from "zod";
26
- import {
27
- AlertDialog,
28
- AlertDialogAction,
29
- AlertDialogCancel,
30
- AlertDialogContent,
31
- AlertDialogDescription,
32
- AlertDialogFooter,
33
- AlertDialogHeader,
34
- AlertDialogTitle,
35
- } from "@/components/ui/alert-dialog";
36
-
37
- export function DeleteConfirmHITL() {
38
- useHumanInTheLoop({
39
- name: "confirmDelete",
40
- description: "Confirm a destructive delete with the user",
41
- parameters: z.object({ id: z.string(), label: z.string() }),
42
- render: ({ status, args, respond }) => (
43
- <AlertDialog open>
44
- <AlertDialogContent>
45
- <AlertDialogHeader>
46
- <AlertDialogTitle>Delete {args.label}?</AlertDialogTitle>
47
- <AlertDialogDescription>
48
- This action cannot be undone.
49
- </AlertDialogDescription>
50
- </AlertDialogHeader>
51
- <AlertDialogFooter>
52
- <AlertDialogCancel
53
- disabled={status !== "executing"}
54
- onClick={() => respond?.("denied")}
55
- >
56
- Cancel
57
- </AlertDialogCancel>
58
- <AlertDialogAction
59
- disabled={status !== "executing"}
60
- onClick={() => respond?.("approved")}
61
- >
62
- Delete
63
- </AlertDialogAction>
64
- </AlertDialogFooter>
65
- </AlertDialogContent>
66
- </AlertDialog>
67
- ),
68
- });
69
- return null;
70
- }
71
- ```
72
-
73
- ## Core Patterns
74
-
75
- ### Always call `respond` in every branch
76
-
77
- ```tsx
78
- render: ({ status, args, respond }) => {
79
- if (status !== "executing" || !respond) {
80
- return <div>Awaiting decision…</div>;
81
- }
82
- return (
83
- <div>
84
- <button onClick={() => respond("approved")}>Approve</button>
85
- <button onClick={() => respond("denied")}>Reject</button>
86
- <button onClick={() => respond({ action: "skip", reason: "timeout" })}>
87
- Skip
88
- </button>
89
- </div>
90
- );
91
- };
92
- ```
93
-
94
- ### Abort the run on unmount so threads unlock
95
-
96
- ```tsx
97
- import { useAgent, UseAgentUpdate } from "@copilotkit/react-core/v2";
98
- import { useEffect, useRef } from "react";
99
-
100
- function HITLHost() {
101
- const { agent } = useAgent({
102
- agentId: "default",
103
- updates: [UseAgentUpdate.OnRunStatusChanged],
104
- });
105
- // Track isRunning in a ref so the unmount cleanup reads the latest value
106
- // without re-firing on every transition.
107
- const runningRef = useRef(false);
108
- useEffect(() => {
109
- runningRef.current = agent.isRunning;
110
- }, [agent.isRunning]);
111
-
112
- useEffect(() => {
113
- return () => {
114
- if (runningRef.current) agent.abortRun();
115
- };
116
- }, [agent]);
117
-
118
- return <DeleteConfirmHITL />;
119
- }
120
- ```
121
-
122
- `useAgent` returns `{ agent }` only — run status lives on `agent.isRunning`.
123
- Depending the cleanup effect directly on `agent.isRunning` would fire the
124
- cleanup on every status flip (not just unmount), aborting active runs.
125
- The ref pattern captures the latest value while the cleanup runs only
126
- when the host component truly unmounts.
127
-
128
- ### Collect structured user input mid-run
129
-
130
- ```tsx
131
- useHumanInTheLoop({
132
- name: "askUserForPriority",
133
- parameters: z.object({ taskId: z.string() }),
134
- render: ({ status, args, respond }) => {
135
- if (status !== "executing" || !respond) return <div>Waiting…</div>;
136
- return (
137
- <div>
138
- {["low", "medium", "high"].map((p) => (
139
- <button
140
- key={p}
141
- onClick={() => respond({ taskId: args.taskId, priority: p })}
142
- >
143
- {p}
144
- </button>
145
- ))}
146
- </div>
147
- );
148
- },
149
- });
150
- ```
151
-
152
- ## Common Mistakes
153
-
154
- ### CRITICAL — Never calling `respond()`
155
-
156
- Wrong:
157
-
158
- ```tsx
159
- useHumanInTheLoop({
160
- name: "confirmDelete",
161
- parameters: z.object({ id: z.string() }),
162
- render: ({ args, status, respond }) => (
163
- <div>
164
- <p>Delete {args.id}?</p>
165
- <button>OK</button>
166
- </div>
167
- ),
168
- });
169
- ```
170
-
171
- Correct:
172
-
173
- ```tsx
174
- useHumanInTheLoop({
175
- name: "confirmDelete",
176
- parameters: z.object({ id: z.string() }),
177
- render: ({ args, status, respond }) => (
178
- <div>
179
- <p>Delete {args.id}?</p>
180
- <button onClick={() => respond?.("approved")}>OK</button>
181
- <button onClick={() => respond?.("denied")}>Cancel</button>
182
- </div>
183
- ),
184
- });
185
- ```
186
-
187
- The synthesized handler returns a Promise that resolves only when `respond`
188
- is called. Never calling it (including reject / cancel paths) hangs the
189
- run indefinitely and leaves the thread locked on the server.
190
-
191
- Source: `packages/react-core/src/v2/hooks/use-human-in-the-loop.tsx:13-26`
192
-
193
- ### CRITICAL — Writing a custom overlay when the app has a Dialog primitive
194
-
195
- Wrong:
196
-
197
- ```tsx
198
- render: ({ respond }) => (
199
- <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)" }}>
200
-
201
- </div>
202
- );
203
- ```
204
-
205
- Correct:
206
-
207
- ```tsx
208
- import {
209
- AlertDialog,
210
- AlertDialogContent,
211
- AlertDialogAction,
212
- } from "@/components/ui/alert-dialog";
213
-
214
- render: ({ respond }) => (
215
- <AlertDialog open>
216
- <AlertDialogContent>
217
-
218
- <AlertDialogAction onClick={() => respond?.("approved")}>
219
- OK
220
- </AlertDialogAction>
221
- </AlertDialogContent>
222
- </AlertDialog>
223
- );
224
- ```
225
-
226
- Check `package.json` for shadcn / MUI / Chakra / Ant / Mantine before
227
- writing an overlay. Their dialog primitives handle focus trapping,
228
- escape-to-close, and accessibility — raw JSX skips all of that.
229
-
230
- Source: maintainer interview (Phase 2c)
231
-
232
- ### HIGH — Calling `respond` during `inProgress` or `complete`
233
-
234
- Wrong:
235
-
236
- ```tsx
237
- render: ({ status, respond }) => (
238
- <button onClick={() => (respond as any)("yes")}>Yes</button>
239
- );
240
- ```
241
-
242
- Correct:
243
-
244
- ```tsx
245
- render: ({ status, respond }) =>
246
- status === "executing" && respond ? (
247
- <button onClick={() => respond("yes")}>Yes</button>
248
- ) : (
249
- <p>Waiting…</p>
250
- );
251
- ```
252
-
253
- `respond` is `undefined` outside `status === "executing"`. Widening it to
254
- `any` silently no-ops — the button click appears to work, but nothing
255
- resolves the Promise.
256
-
257
- Source: `packages/react-core/src/v2/types/human-in-the-loop.ts:8-32`
258
-
259
- ### HIGH — Unmounting the render mid-executing
260
-
261
- Wrong:
262
-
263
- ```tsx
264
- // User clicks away to a different route while the agent is waiting on respond()
265
- ```
266
-
267
- Correct:
268
-
269
- ```tsx
270
- // Keep the HITL prompt at a layout level that persists across route changes, OR abort on unmount:
271
- const { agent } = useAgent({
272
- agentId: "default",
273
- updates: [UseAgentUpdate.OnRunStatusChanged],
274
- });
275
- const runningRef = useRef(false);
276
- useEffect(() => {
277
- runningRef.current = agent.isRunning;
278
- }, [agent.isRunning]);
279
- useEffect(
280
- () => () => {
281
- if (runningRef.current) agent.abortRun();
282
- },
283
- [agent],
284
- );
285
- ```
286
-
287
- `useHumanInTheLoop` removes its renderer on unmount (unlike
288
- `useFrontendTool`, which keeps renderers for history). If the renderer
289
- unmounts mid-`executing`, the pending Promise is abandoned and the run
290
- hangs. Either lift the HITL UI to a layout-level component, or abort the
291
- run on unmount.
292
-
293
- Source: `packages/react-core/src/v2/hooks/use-human-in-the-loop.tsx:76-80`
294
-
295
- ### MEDIUM — Using hyphenated `"in-progress"` status
296
-
297
- Wrong:
298
-
299
- ```tsx
300
- render: ({ status }) => (status === "in-progress" ? <Spinner /> : <Form />);
301
- ```
302
-
303
- Correct:
304
-
305
- ```tsx
306
- render: ({ status }) => (status === "inProgress" ? <Spinner /> : <Form />);
307
- ```
308
-
309
- Same camelCase rule as `rendering-tool-calls`: the discriminated union
310
- only matches `"inProgress" | "executing" | "complete"`.
311
-
312
- Source: `packages/react-core/src/v2/types/human-in-the-loop.ts:8-32`
@@ -1,358 +0,0 @@
1
- # CopilotKit Provider Setup (React)
2
-
3
- Mount the `CopilotKit` provider (from `@copilotkit/react-core/v2`) once
4
- near the root of the React tree. Every CopilotKit hook (`useAgent`,
5
- `useFrontendTool`, `useRenderTool`, etc.) and every chat component
6
- (`CopilotChat`, `CopilotPopup`, `CopilotSidebar`) must be rendered inside
7
- this provider.
8
-
9
- > **Which provider component?** Use `CopilotKit` imported from `@copilotkit/react-core/v2`. It is the compatibility bridge across v1 and v2 and a superset of `CopilotKitProvider`, which is also exported from `/v2` and is a perfectly good choice if you do not need the v1 bridge. Do **not** use `CopilotKit` from the package root (`@copilotkit/react-core`) — that is the legacy v1 entry point and will not work with v2 hooks or components.
10
-
11
- ## Transport
12
-
13
- You do not normally configure the transport. Both providers leave
14
- `useSingleEndpoint` unset by default, and the client then negotiates: it probes
15
- `GET {runtimeUrl}/info` and falls back to the single-route `POST` envelope. That
16
- works against a multi-route handler (the default for every `createCopilot*`
17
- handler) and a single-route one alike.
18
-
19
- Set the prop only to pin one mode deliberately:
20
-
21
- | `useSingleEndpoint` | Transport | Requires |
22
- | ------------------------- | ---------------------------- | --------------------------------------------- |
23
- | omitted (**recommended**) | negotiated | either handler mode |
24
- | `{true}` | single-route `POST` envelope | a handler mounted with `mode: "single-route"` |
25
- | `{false}` | multi-route REST routes | a handler in the default multi-route mode |
26
-
27
- Pinning the wrong one is the classic first-run failure: a single-route envelope
28
- sent to a multi-route runtime matches no route, so the runtime 404s while
29
- `GET /info` still returns 200 and the app looks connected. If you see that, drop
30
- the prop rather than guessing the other value.
31
-
32
- All v2 imports use the `@copilotkit/react-core/v2` subpath. Imports from the
33
- package root are v1 and will not work with v2 hooks or components.
34
-
35
- ## Setup
36
-
37
- ### Next.js App Router (and any RSC-based framework)
38
-
39
- `@copilotkit/react-core/v2` is marked `"use client"`. You must mount the
40
- provider from a client component, not a server component. The cleanest
41
- pattern is a dedicated client-only `providers.tsx`.
42
-
43
- ```tsx
44
- // app/providers.tsx
45
- "use client";
46
-
47
- import { CopilotKit } from "@copilotkit/react-core/v2";
48
- import "@copilotkit/react-core/v2/styles.css";
49
-
50
- export function Providers({ children }: { children: React.ReactNode }) {
51
- return (
52
- <CopilotKit
53
- runtimeUrl="/api/copilotkit"
54
- credentials="include"
55
- onError={({ code, error, context }) => {
56
- console.error("[copilotkit]", code, error, context);
57
- }}
58
- >
59
- {children}
60
- </CopilotKit>
61
- );
62
- }
63
- ```
64
-
65
- For auth headers that change over the session (rotating bearer tokens,
66
- refreshed cookies), see the "Stable headers for rotating auth tokens"
67
- pattern below. Avoid putting a `useMemo(() => ({ Authorization: ... }),
68
- [])` on the provider — an empty deps array captures the token at mount
69
- and never refreshes.
70
-
71
- ```tsx
72
- // app/layout.tsx — server component
73
- import { Providers } from "./providers";
74
-
75
- export default function RootLayout({
76
- children,
77
- }: {
78
- children: React.ReactNode;
79
- }) {
80
- return (
81
- <html lang="en">
82
- <body>
83
- <Providers>{children}</Providers>
84
- </body>
85
- </html>
86
- );
87
- }
88
- ```
89
-
90
- ### Vite / React Router v7 / SPA
91
-
92
- ```tsx
93
- import { CopilotKit } from "@copilotkit/react-core/v2";
94
- import "@copilotkit/react-core/v2/styles.css";
95
-
96
- export function App({ children }: { children: React.ReactNode }) {
97
- return <CopilotKit runtimeUrl="/api/copilotkit">{children}</CopilotKit>;
98
- }
99
- ```
100
-
101
- ### SPA with CopilotKit Intelligence (no self-hosted runtime)
102
-
103
- ```tsx
104
- <CopilotKit publicLicenseKey="ck_pub_..." />
105
- ```
106
-
107
- `publicLicenseKey` is the canonical prop for running CopilotKit from a
108
- pure client bundle. `publicApiKey` is a deprecated alias that resolves to
109
- the same value — accept it in old code, but always write
110
- `publicLicenseKey` in new code.
111
-
112
- ## Core Patterns
113
-
114
- ### Stable headers for rotating auth tokens
115
-
116
- For tokens that change during the session, use the imperative setter instead
117
- of re-rendering the provider with a new `headers` prop.
118
-
119
- ```tsx
120
- "use client";
121
- import { useCopilotKit } from "@copilotkit/react-core/v2";
122
- import { useEffect } from "react";
123
-
124
- export function AuthTokenSync({ token }: { token: string | null }) {
125
- const { copilotkit } = useCopilotKit();
126
- useEffect(() => {
127
- // setHeaders is an overwrite, not a merge — spread the current headers so
128
- // entries set elsewhere (e.g. the public license key) survive. A `null`
129
- // value clears that header, so logging out removes `Authorization` instead
130
- // of sending an empty one.
131
- copilotkit.setHeaders({
132
- ...copilotkit.headers,
133
- Authorization: token ? `Bearer ${token}` : null,
134
- });
135
- }, [copilotkit, token]);
136
- return null;
137
- }
138
- ```
139
-
140
- `setHeaders` accepts `null`/`undefined` values and drops those keys, so passing
141
- `Authorization: null` is the supported way to clear a header. Setting it to an
142
- empty string would keep the header present with a blank value.
143
-
144
- Do not set the same header through both the `headers` prop and imperative
145
- `setHeaders`. Whenever any provider prop changes, the provider calls
146
- `setHeaders` with its prop-derived headers — a full overwrite that drops every
147
- imperatively-set header, not just keys the prop also defines. Keep rotating
148
- values like the auth token out of the `headers` prop and manage them only
149
- through `setHeaders` (as above).
150
-
151
- ### Global error handler
152
-
153
- `onError` fires for every `CopilotKitCoreErrorCode` emitted by core. Keeps
154
- UI from getting stuck in "connecting..." when the runtime URL is wrong or
155
- CORS is misconfigured.
156
-
157
- ```tsx
158
- <CopilotKit
159
- runtimeUrl="/api/copilotkit"
160
- onError={({ code, error, context }) => {
161
- telemetry.capture({ code, message: error.message, context });
162
- }}
163
- />
164
- ```
165
-
166
- ### Sharing app properties with every run
167
-
168
- `properties` flows to the runtime on each agent run — useful for tenant IDs,
169
- feature flags, or anything the server needs.
170
-
171
- ```tsx
172
- const properties = useMemo(
173
- () => ({ tenantId: user.tenantId, locale: user.locale }),
174
- [user.tenantId, user.locale],
175
- );
176
-
177
- <CopilotKit runtimeUrl="/api/copilotkit" properties={properties} />;
178
- ```
179
-
180
- ## Common Mistakes
181
-
182
- ### CRITICAL — Mounting the provider from a Server Component
183
-
184
- Wrong:
185
-
186
- ```tsx
187
- // app/page.tsx (server component — no "use client")
188
- import { CopilotKit } from "@copilotkit/react-core/v2";
189
-
190
- export default function Page() {
191
- return <CopilotKit runtimeUrl="/api/copilotkit">...</CopilotKit>;
192
- }
193
- ```
194
-
195
- Correct:
196
-
197
- ```tsx
198
- // app/providers.tsx
199
- "use client";
200
- import { CopilotKit } from "@copilotkit/react-core/v2";
201
-
202
- export function Providers({ children }: { children: React.ReactNode }) {
203
- return <CopilotKit runtimeUrl="/api/copilotkit">{children}</CopilotKit>;
204
- }
205
-
206
- // app/layout.tsx imports <Providers>.
207
- ```
208
-
209
- `@copilotkit/react-core/v2` begins with `"use client"`. Importing it from a
210
- server component silently strips interactivity — the provider renders but
211
- none of the hooks wire up.
212
-
213
- Source: `packages/react-core/src/v2/index.ts:1`
214
-
215
- ### CRITICAL — Using `agents__unsafe_dev_only` or `selfManagedAgents` in production
216
-
217
- Wrong:
218
-
219
- ```tsx
220
- <CopilotKit
221
- agents__unsafe_dev_only={{
222
- default: new BuiltInAgent({ apiKey: process.env.OPENAI_KEY! }),
223
- }}
224
- />
225
- // or the alias (same thing):
226
- <CopilotKit
227
- selfManagedAgents={{ default: new BuiltInAgent({ apiKey: "..." }) }}
228
- />
229
- ```
230
-
231
- Correct:
232
-
233
- ```tsx
234
- // Route through a runtime that keeps secrets server-side:
235
- <CopilotKit runtimeUrl="/api/copilotkit" />
236
-
237
- // Or for a pure SPA, use CopilotKit Intelligence:
238
- <CopilotKit publicLicenseKey="ck_pub_..." />
239
- ```
240
-
241
- Both props are aliases for the same dev-only mechanism and ship any embedded
242
- credentials to the browser bundle. Never use either for production agents.
243
-
244
- Source: `packages/react-core/src/v2/providers/CopilotKitProvider.tsx:136-138,393`
245
-
246
- ### HIGH — Inline object props rebuilt every render
247
-
248
- Wrong:
249
-
250
- ```tsx
251
- <CopilotKit
252
- runtimeUrl="/api/copilotkit"
253
- headers={{ Authorization: `Bearer ${token}` }}
254
- properties={{ tenantId: user.tenantId }}
255
- />
256
- ```
257
-
258
- Correct:
259
-
260
- ```tsx
261
- const headers = useMemo(() => ({ Authorization: `Bearer ${token}` }), [token]);
262
- const properties = useMemo(
263
- () => ({ tenantId: user.tenantId }),
264
- [user.tenantId],
265
- );
266
-
267
- <CopilotKit
268
- runtimeUrl="/api/copilotkit"
269
- headers={headers}
270
- properties={properties}
271
- />;
272
- ```
273
-
274
- New object identity on every render causes the provider to diff-churn
275
- internal state and may thrash tool/renderer registration. `useStableArrayProp`
276
- also logs a `console.error` when array-prop shape changes without
277
- memoization.
278
-
279
- Source: `packages/react-core/src/v2/providers/CopilotKitProvider.tsx:324-340,399-410`
280
-
281
- ### HIGH — Missing `onError` leaves users stuck in "connecting..."
282
-
283
- Wrong:
284
-
285
- ```tsx
286
- <CopilotKit runtimeUrl="/api/copilotkit" />
287
- ```
288
-
289
- Correct:
290
-
291
- ```tsx
292
- <CopilotKit
293
- runtimeUrl="/api/copilotkit"
294
- onError={({ code, error, context }) => {
295
- telemetry.capture({ code, error, context });
296
- }}
297
- />
298
- ```
299
-
300
- Without `onError`, connection failures (bad runtime URL, CORS, network) keep
301
- the provider in a provisional state with `ProxiedCopilotRuntimeAgent`
302
- instances that never resolve. The chat UI keeps showing "connecting..."
303
- forever and users never see the actual error.
304
-
305
- Source: `packages/react-core/src/v2/providers/CopilotKitProvider.tsx:638-660`
306
-
307
- ### HIGH — Writing `publicApiKey` in new code
308
-
309
- Wrong:
310
-
311
- ```tsx
312
- <CopilotKit publicApiKey="ck_pub_..." />
313
- ```
314
-
315
- Correct:
316
-
317
- ```tsx
318
- <CopilotKit publicLicenseKey="ck_pub_..." />
319
- ```
320
-
321
- `publicApiKey` still works as a deprecated alias, but `publicLicenseKey`
322
- is the canonical name. The `CopilotKit` provider resolves
323
- `publicLicenseKey || publicApiKey`. Always write the canonical form in
324
- new code.
325
-
326
- Source: `packages/react-core/src/v1-deprecated/components/copilot-provider/copilotkit.tsx:172`
327
-
328
- ### MEDIUM — Putting the provider below a layout that uses CopilotKit
329
-
330
- Wrong:
331
-
332
- ```tsx
333
- <html>
334
- <body>
335
- <Header>{/* Header uses useFrontendTool internally */}</Header>
336
- <CopilotKit>{children}</CopilotKit>
337
- </body>
338
- </html>
339
- ```
340
-
341
- Correct:
342
-
343
- ```tsx
344
- <html>
345
- <body>
346
- <CopilotKit>
347
- <Header />
348
- {children}
349
- </CopilotKit>
350
- </body>
351
- </html>
352
- ```
353
-
354
- Any component that calls `useCopilotKit`, `useFrontendTool`, `useAgent`, or
355
- any other CopilotKit hook must be a descendant of the `CopilotKit`
356
- provider. Placing the provider beside or below a consumer throws at mount.
357
-
358
- Source: `packages/react-core/src/v2/providers/CopilotKitProvider.tsx` (context)