@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.
- package/dist/{copilotkit-BU3OvveB.cjs → copilotkit-BkVEkUS0.cjs} +369 -154
- package/dist/copilotkit-BkVEkUS0.cjs.map +1 -0
- package/dist/{copilotkit-Bs98akp9.d.mts → copilotkit-ChjzWqn6.d.mts} +33 -8
- package/dist/copilotkit-ChjzWqn6.d.mts.map +1 -0
- package/dist/{copilotkit-Ap_yisA5.mjs → copilotkit-D5BTo0YG.mjs} +368 -153
- package/dist/copilotkit-D5BTo0YG.mjs.map +1 -0
- package/dist/{copilotkit-X2eGbOwf.d.cts → copilotkit-DCIXZawe.d.cts} +33 -8
- package/dist/copilotkit-DCIXZawe.d.cts.map +1 -0
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +180 -139
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/context.cjs +4 -0
- package/dist/v2/context.cjs.map +1 -1
- package/dist/v2/context.d.cts +3 -1
- package/dist/v2/context.d.cts.map +1 -1
- package/dist/v2/context.d.mts +3 -1
- package/dist/v2/context.d.mts.map +1 -1
- package/dist/v2/context.mjs +3 -1
- package/dist/v2/context.mjs.map +1 -1
- package/dist/v2/headless.cjs +20 -5
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts +9 -4
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts +9 -4
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +21 -6
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +1 -1
- package/dist/v2/index.d.mts +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +495 -278
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +8 -9
- package/dist/copilotkit-Ap_yisA5.mjs.map +0 -1
- package/dist/copilotkit-BU3OvveB.cjs.map +0 -1
- package/dist/copilotkit-Bs98akp9.d.mts.map +0 -1
- package/dist/copilotkit-X2eGbOwf.d.cts.map +0 -1
- package/skills/react-core/SKILL.md +0 -110
- package/skills/react-core/references/agent-access.md +0 -355
- package/skills/react-core/references/attachments.md +0 -311
- package/skills/react-core/references/capabilities.md +0 -138
- package/skills/react-core/references/chat-components.md +0 -229
- package/skills/react-core/references/client-side-tools.md +0 -358
- package/skills/react-core/references/custom-message-renderers.md +0 -223
- package/skills/react-core/references/debug-mode.md +0 -140
- package/skills/react-core/references/human-in-the-loop.md +0 -312
- package/skills/react-core/references/provider-setup.md +0 -358
- package/skills/react-core/references/rendering-activity-messages.md +0 -201
- package/skills/react-core/references/rendering-tool-calls.md +0 -319
- package/skills/react-core/references/suggestions.md +0 -211
- package/skills/react-core/references/switching-agents-recipes.md +0 -161
- package/skills/react-core/references/switching-agents.md +0 -240
- package/skills/react-core/references/threads.md +0 -289
|
@@ -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)
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
# CopilotKit Rendering Activity Messages (React)
|
|
2
|
-
|
|
3
|
-
This skill builds on `copilotkit/provider-setup`. Activity-message
|
|
4
|
-
renderers are registered as entries in the `renderActivityMessages` array
|
|
5
|
-
prop on the `CopilotKit` provider and resolved at render time by
|
|
6
|
-
`useRenderActivityMessage` (consumed internally by chat components).
|
|
7
|
-
|
|
8
|
-
User renderers are placed first in the array so they override the built-in
|
|
9
|
-
`MCPAppsActivityType` and `OpenGenerativeUIActivityType` renderers for the
|
|
10
|
-
same `activityType`.
|
|
11
|
-
|
|
12
|
-
Resolver order:
|
|
13
|
-
|
|
14
|
-
1. `(activityType, agentId)` match
|
|
15
|
-
2. `(activityType, unscoped)` match
|
|
16
|
-
3. `'*'` wildcard
|
|
17
|
-
4. `null`
|
|
18
|
-
|
|
19
|
-
## Setup
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
"use client";
|
|
23
|
-
import { CopilotKit } from "@copilotkit/react-core/v2";
|
|
24
|
-
import type { ReactActivityMessageRenderer } from "@copilotkit/react-core/v2";
|
|
25
|
-
import { z } from "zod";
|
|
26
|
-
import { useMemo } from "react";
|
|
27
|
-
import { Card, CardContent } from "@/components/ui/card";
|
|
28
|
-
import { Progress } from "@/components/ui/progress";
|
|
29
|
-
|
|
30
|
-
const progressRenderer: ReactActivityMessageRenderer<{
|
|
31
|
-
percent: number;
|
|
32
|
-
label: string;
|
|
33
|
-
}> = {
|
|
34
|
-
activityType: "progress",
|
|
35
|
-
content: z.object({ percent: z.number().min(0).max(1), label: z.string() }),
|
|
36
|
-
render: ({ content }) => (
|
|
37
|
-
<Card>
|
|
38
|
-
<CardContent>
|
|
39
|
-
<div>{content.label}</div>
|
|
40
|
-
<Progress value={content.percent * 100} />
|
|
41
|
-
</CardContent>
|
|
42
|
-
</Card>
|
|
43
|
-
),
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export function Providers({ children }: { children: React.ReactNode }) {
|
|
47
|
-
const renderers = useMemo(() => [progressRenderer], []);
|
|
48
|
-
return (
|
|
49
|
-
<CopilotKit runtimeUrl="/api/copilotkit" renderActivityMessages={renderers}>
|
|
50
|
-
{children}
|
|
51
|
-
</CopilotKit>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Core Patterns
|
|
57
|
-
|
|
58
|
-
### Agent-scoped renderer
|
|
59
|
-
|
|
60
|
-
```tsx
|
|
61
|
-
const researchProgress: ReactActivityMessageRenderer<{ step: string }> = {
|
|
62
|
-
activityType: "research-step",
|
|
63
|
-
agentId: "research",
|
|
64
|
-
content: z.object({ step: z.string() }),
|
|
65
|
-
render: ({ content }) => <ResearchStepBadge step={content.step} />,
|
|
66
|
-
};
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Override a built-in (MCP Apps)
|
|
70
|
-
|
|
71
|
-
Place your renderer for the same `activityType` — user renderers are
|
|
72
|
-
evaluated before built-ins.
|
|
73
|
-
|
|
74
|
-
```tsx
|
|
75
|
-
import { MCPAppsActivityType } from "@copilotkit/react-core/v2";
|
|
76
|
-
|
|
77
|
-
const customMcpRenderer: ReactActivityMessageRenderer<unknown> = {
|
|
78
|
-
activityType: MCPAppsActivityType, // "mcp-apps" — must match the exported constant
|
|
79
|
-
content: z.unknown(),
|
|
80
|
-
render: ({ content, message }) => <CustomMCPCard payload={content} />,
|
|
81
|
-
};
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Using the hook directly (custom chat surface)
|
|
85
|
-
|
|
86
|
-
```tsx
|
|
87
|
-
import { useRenderActivityMessage } from "@copilotkit/react-core/v2";
|
|
88
|
-
import type { ActivityMessage } from "@ag-ui/core";
|
|
89
|
-
|
|
90
|
-
export function ActivityList({ messages }: { messages: ActivityMessage[] }) {
|
|
91
|
-
const { renderActivityMessage } = useRenderActivityMessage();
|
|
92
|
-
return (
|
|
93
|
-
<div>
|
|
94
|
-
{messages.map((m) => (
|
|
95
|
-
<div key={m.id}>{renderActivityMessage(m)}</div>
|
|
96
|
-
))}
|
|
97
|
-
</div>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Common Mistakes
|
|
103
|
-
|
|
104
|
-
### HIGH — Incompatible content schema
|
|
105
|
-
|
|
106
|
-
Wrong:
|
|
107
|
-
|
|
108
|
-
```tsx
|
|
109
|
-
// Renderer expects `pct`
|
|
110
|
-
const r: ReactActivityMessageRenderer<{ pct: number }> = {
|
|
111
|
-
activityType: "progress",
|
|
112
|
-
content: z.object({ pct: z.number() }),
|
|
113
|
-
render: ({ content }) => <Bar value={content.pct} />,
|
|
114
|
-
};
|
|
115
|
-
// But the server emits { percent: 0.5 } — mismatched field name
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Correct:
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
const r: ReactActivityMessageRenderer<{ percent: number }> = {
|
|
122
|
-
activityType: "progress",
|
|
123
|
-
content: z.object({ percent: z.number() }),
|
|
124
|
-
render: ({ content }) => <Bar value={content.percent} />,
|
|
125
|
-
};
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
`safeParse` is called on every incoming activity message. Mismatched
|
|
129
|
-
schemas return `null` with only a `console.warn("Failed to parse content
|
|
130
|
-
for activity message …")` — the UI renders nothing and the failure is
|
|
131
|
-
silent unless you read the console.
|
|
132
|
-
|
|
133
|
-
Source: `packages/react-core/src/v2/hooks/use-render-activity-message.tsx:44-50`
|
|
134
|
-
|
|
135
|
-
### MEDIUM — Side effects in `render`
|
|
136
|
-
|
|
137
|
-
Wrong:
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
render: ({ content }) => {
|
|
141
|
-
trackEvent(content); // fires on every re-render
|
|
142
|
-
return <Badge>{content.label}</Badge>;
|
|
143
|
-
};
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Wrong (Rules of Hooks violation):
|
|
147
|
-
|
|
148
|
-
```tsx
|
|
149
|
-
render: ({ content }) => {
|
|
150
|
-
// `render` is invoked as a plain function by the resolver — NOT as a
|
|
151
|
-
// React component — so calling hooks directly inside it is illegal.
|
|
152
|
-
useEffect(() => trackEvent(content), [content]);
|
|
153
|
-
return <Badge>{content.label}</Badge>;
|
|
154
|
-
};
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Correct:
|
|
158
|
-
|
|
159
|
-
```tsx
|
|
160
|
-
function TrackedBadge({ content }: { content: { label: string } }) {
|
|
161
|
-
useEffect(() => {
|
|
162
|
-
trackEvent(content);
|
|
163
|
-
}, [content]);
|
|
164
|
-
return <Badge>{content.label}</Badge>;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// In the renderer:
|
|
168
|
-
render: ({ content }) => <TrackedBadge content={content} />;
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Activity-message renderers re-render on every message-list tick. Side
|
|
172
|
-
effects in the render body fire repeatedly. Hooks cannot be called
|
|
173
|
-
directly inside `render` because the resolver invokes it as a plain
|
|
174
|
-
function; hoist the effect into a wrapper component that React mounts as
|
|
175
|
-
a real element.
|
|
176
|
-
|
|
177
|
-
Source: `packages/react-core/src/v2/hooks/use-render-activity-message.tsx`
|
|
178
|
-
|
|
179
|
-
### MEDIUM — Building the `renderActivityMessages` array inline
|
|
180
|
-
|
|
181
|
-
Wrong:
|
|
182
|
-
|
|
183
|
-
```tsx
|
|
184
|
-
<CopilotKit
|
|
185
|
-
runtimeUrl="/api/copilotkit"
|
|
186
|
-
renderActivityMessages={[progressRenderer, customMcpRenderer]}
|
|
187
|
-
/>
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Correct:
|
|
191
|
-
|
|
192
|
-
```tsx
|
|
193
|
-
const renderers = useMemo(() => [progressRenderer, customMcpRenderer], []);
|
|
194
|
-
<CopilotKit runtimeUrl="/api/copilotkit" renderActivityMessages={renderers} />;
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
The provider uses `useStableArrayProp` and console-errors when a new array
|
|
198
|
-
identity appears every render. Memoize or hoist the array to module
|
|
199
|
-
scope.
|
|
200
|
-
|
|
201
|
-
Source: `packages/react-core/src/v2/providers/CopilotKitProvider.tsx` (useStableArrayProp)
|