@copilotkit/runtime 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 (39) hide show
  1. package/dist/agent/index.cjs +5 -1
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +1 -1
  4. package/dist/agent/index.d.cts.map +1 -1
  5. package/dist/agent/index.d.mts +1 -1
  6. package/dist/agent/index.d.mts.map +1 -1
  7. package/dist/agent/index.mjs +5 -1
  8. package/dist/agent/index.mjs.map +1 -1
  9. package/dist/package.cjs +3 -3
  10. package/dist/package.mjs +3 -3
  11. package/package.json +5 -6
  12. package/skills/runtime/SKILL.md +0 -98
  13. package/skills/runtime/references/agent-runners-custom.md +0 -161
  14. package/skills/runtime/references/agent-runners-in-memory.md +0 -79
  15. package/skills/runtime/references/agent-runners-sqlite.md +0 -90
  16. package/skills/runtime/references/agent-runners.md +0 -336
  17. package/skills/runtime/references/built-in-agent-factory-modes.md +0 -232
  18. package/skills/runtime/references/built-in-agent-helper-utilities.md +0 -123
  19. package/skills/runtime/references/built-in-agent-model-identifiers.md +0 -58
  20. package/skills/runtime/references/built-in-agent.md +0 -523
  21. package/skills/runtime/references/intelligence-mode.md +0 -364
  22. package/skills/runtime/references/middleware.md +0 -376
  23. package/skills/runtime/references/server-side-tools.md +0 -414
  24. package/skills/runtime/references/setup-endpoint.md +0 -503
  25. package/skills/runtime/references/transcription.md +0 -287
  26. package/skills/runtime/references/wiring-a2a.md +0 -40
  27. package/skills/runtime/references/wiring-adk.md +0 -45
  28. package/skills/runtime/references/wiring-ag2.md +0 -41
  29. package/skills/runtime/references/wiring-agno.md +0 -40
  30. package/skills/runtime/references/wiring-aws-strands.md +0 -59
  31. package/skills/runtime/references/wiring-crewai-crews.md +0 -51
  32. package/skills/runtime/references/wiring-crewai-flows.md +0 -45
  33. package/skills/runtime/references/wiring-external-agents.md +0 -348
  34. package/skills/runtime/references/wiring-langgraph.md +0 -49
  35. package/skills/runtime/references/wiring-llamaindex.md +0 -39
  36. package/skills/runtime/references/wiring-mastra.md +0 -70
  37. package/skills/runtime/references/wiring-mcp-apps-middleware.md +0 -73
  38. package/skills/runtime/references/wiring-ms-agent-framework.md +0 -41
  39. package/skills/runtime/references/wiring-pydantic-ai.md +0 -45
@@ -1,376 +0,0 @@
1
- # CopilotKit Runtime Middleware
2
-
3
- Two coexisting middleware surfaces:
4
-
5
- - **`hooks`** (preferred, newer) — pass to `createCopilotRuntimeHandler({ hooks })`.
6
- Route-aware via `onBeforeHandler({ route })`. Throw a `Response` to short-circuit.
7
- - **`beforeRequestMiddleware` / `afterRequestMiddleware`** (legacy) — pass to
8
- `new CopilotRuntime({ ... })`. Runs **after `hooks.onRequest` but before routing** (see
9
- `fetch-handler.ts:136-147` for exact order). Pre-routing only.
10
-
11
- Use **hooks** for new code.
12
-
13
- ## Setup
14
-
15
- ```typescript
16
- import {
17
- CopilotRuntime,
18
- createCopilotRuntimeHandler,
19
- } from "@copilotkit/runtime/v2";
20
-
21
- const runtime = new CopilotRuntime({
22
- agents: {
23
- /* ... */
24
- } as any,
25
- });
26
-
27
- const handler = createCopilotRuntimeHandler({
28
- runtime,
29
- basePath: "/api/copilotkit",
30
- hooks: {
31
- onRequest: async ({ request }) => {
32
- const token = request.headers.get("authorization");
33
- if (!token) throw new Response("Unauthorized", { status: 401 });
34
- },
35
- onBeforeHandler: async ({ route, request }) => {
36
- if (route.method === "agent/run" && route.agentId === "admin") {
37
- const user = await verifyAdminToken(
38
- request.headers.get("authorization"),
39
- );
40
- if (!user) throw new Response("Forbidden", { status: 403 });
41
- }
42
- },
43
- onResponse: async ({ response }) => {
44
- const headers = new Headers(response.headers);
45
- headers.set("x-copilot-version", "2.0");
46
- return new Response(response.body, {
47
- status: response.status,
48
- statusText: response.statusText,
49
- headers,
50
- });
51
- },
52
- onError: async ({ error, route }) => {
53
- console.error("[copilotkit]", route?.method, error);
54
- },
55
- },
56
- });
57
-
58
- async function verifyAdminToken(
59
- header: string | null,
60
- ): Promise<{ id: string } | null> {
61
- if (!header) return null;
62
- // delegate to your auth lib
63
- return { id: "admin" };
64
- }
65
-
66
- export default { fetch: handler };
67
- ```
68
-
69
- ## Core Patterns
70
-
71
- ### Reject unauthenticated requests at the runtime boundary
72
-
73
- ```typescript
74
- createCopilotRuntimeHandler({
75
- runtime,
76
- basePath: "/api/copilotkit",
77
- hooks: {
78
- onRequest: ({ request }) => {
79
- const token = request.headers.get("authorization");
80
- if (!token?.startsWith("Bearer ")) {
81
- throw new Response(JSON.stringify({ error: "unauthorized" }), {
82
- status: 401,
83
- headers: { "content-type": "application/json" },
84
- });
85
- }
86
- },
87
- },
88
- });
89
- ```
90
-
91
- ### Route-aware authorization
92
-
93
- Use `onBeforeHandler` — the `route` object carries `method`, `agentId`, and (for thread/stop
94
- methods) `threadId`.
95
-
96
- ```typescript
97
- createCopilotRuntimeHandler({
98
- runtime,
99
- basePath: "/api/copilotkit",
100
- hooks: {
101
- onBeforeHandler: async ({ route, request }) => {
102
- if (route.method === "agent/run" && route.agentId === "billing") {
103
- const ok = await canAccessBilling(request);
104
- if (!ok) throw new Response("Forbidden", { status: 403 });
105
- }
106
- },
107
- },
108
- });
109
-
110
- async function canAccessBilling(request: Request): Promise<boolean> {
111
- // delegate to your policy engine
112
- return true;
113
- }
114
- ```
115
-
116
- ### Rate-limit by calling an external limiter from the hook
117
-
118
- Delegate to a dedicated lib — do not implement a rate limiter inline.
119
-
120
- ```typescript
121
- import { Ratelimit } from "@upstash/ratelimit";
122
- import { Redis } from "@upstash/redis";
123
-
124
- const ratelimit = new Ratelimit({
125
- redis: Redis.fromEnv(),
126
- limiter: Ratelimit.slidingWindow(60, "1 m"),
127
- });
128
-
129
- createCopilotRuntimeHandler({
130
- runtime,
131
- basePath: "/api/copilotkit",
132
- hooks: {
133
- onRequest: async ({ request }) => {
134
- const userId = request.headers.get("x-user-id") ?? "anon";
135
- const { success } = await ratelimit.limit(userId);
136
- if (!success) throw new Response("Too Many Requests", { status: 429 });
137
- },
138
- },
139
- });
140
- ```
141
-
142
- ### Non-blocking telemetry on response
143
-
144
- `afterRequestMiddleware` runs non-blocking (errors inside only log). Do not await heavy
145
- work that the user's response waits on.
146
-
147
- ```typescript
148
- import { CopilotRuntime } from "@copilotkit/runtime/v2";
149
-
150
- const runtime = new CopilotRuntime({
151
- agents: {
152
- /* ... */
153
- } as any,
154
- afterRequestMiddleware: async ({ threadId, messages }) => {
155
- // fire-and-forget; do not await heavy work that blocks response
156
- void queue.enqueue({ type: "chat", threadId, messages });
157
- },
158
- });
159
- ```
160
-
161
- ## Common Mistakes
162
-
163
- ### HIGH Returning a Response instead of throwing
164
-
165
- Wrong:
166
-
167
- ```typescript
168
- new CopilotRuntime({
169
- agents,
170
- beforeRequestMiddleware: async () =>
171
- new Response("Unauthorized", { status: 401 }),
172
- });
173
- ```
174
-
175
- Correct:
176
-
177
- ```typescript
178
- new CopilotRuntime({
179
- agents,
180
- beforeRequestMiddleware: async ({ request }) => {
181
- if (!request.headers.get("authorization")) {
182
- throw new Response("Unauthorized", { status: 401 });
183
- }
184
- },
185
- });
186
- ```
187
-
188
- The middleware contract returns `Request | void`. Returning a Response corrupts the
189
- request object — `fetch-handler.ts:140-147` assigns any truthy return value back to
190
- `request`, so the router then tries to read `request.method` / `request.headers.get(...)`
191
- from the Response and downstream handling blows up. Always `throw` a Response to
192
- short-circuit; never return one.
193
-
194
- Source: `packages/runtime/src/v2/runtime/core/fetch-handler.ts:140-156`.
195
-
196
- ### MEDIUM Defaulting to beforeRequestMiddleware when hooks are preferred
197
-
198
- Wrong:
199
-
200
- ```typescript
201
- new CopilotRuntime({
202
- agents,
203
- beforeRequestMiddleware: async ({ request, path }) => {
204
- if (path.includes("/agent/admin/")) {
205
- /* check admin auth */
206
- }
207
- },
208
- });
209
- ```
210
-
211
- Correct:
212
-
213
- ```typescript
214
- const runtime = new CopilotRuntime({ agents });
215
- const handler = createCopilotRuntimeHandler({
216
- runtime,
217
- basePath: "/api/copilotkit",
218
- hooks: {
219
- onBeforeHandler: ({ route, request }) => {
220
- if (route.method === "agent/run" && route.agentId === "admin") {
221
- /* ... */
222
- }
223
- },
224
- },
225
- });
226
- ```
227
-
228
- Both surfaces coexist. For new code the hook API on `createCopilotRuntimeHandler` is
229
- preferred — `onBeforeHandler` receives typed `route` info, so you don't string-match paths.
230
-
231
- Source: `packages/runtime/src/v2/runtime/core/hooks.ts:84-117`; maintainer Phase 4c.
232
-
233
- ### MEDIUM Route-specific auth in global beforeRequestMiddleware
234
-
235
- Wrong:
236
-
237
- ```typescript
238
- new CopilotRuntime({
239
- agents,
240
- beforeRequestMiddleware: async ({ path, request }) => {
241
- if (path.includes("/agent/admin/")) {
242
- /* ... */
243
- }
244
- },
245
- });
246
- ```
247
-
248
- Correct:
249
-
250
- ```typescript
251
- createCopilotRuntimeHandler({
252
- runtime,
253
- basePath: "/api/copilotkit",
254
- hooks: {
255
- onBeforeHandler: ({ route, request }) => {
256
- if (route.method === "agent/run" && route.agentId === "admin") {
257
- /* ... */
258
- }
259
- },
260
- },
261
- });
262
- ```
263
-
264
- `beforeRequestMiddleware` fires before routing, so no route info exists yet — string-matching
265
- paths is fragile. `onBeforeHandler` fires after routing with typed `route.method`, `route.agentId`.
266
-
267
- Source: `packages/runtime/src/v2/runtime/core/hooks.ts:94-103`.
268
-
269
- ### MEDIUM Blocking on afterRequestMiddleware
270
-
271
- Wrong:
272
-
273
- ```typescript
274
- new CopilotRuntime({
275
- agents,
276
- afterRequestMiddleware: async ({ response, threadId, messages }) => {
277
- await heavyAnalytics(response, threadId, messages);
278
- },
279
- });
280
- ```
281
-
282
- Correct:
283
-
284
- ```typescript
285
- new CopilotRuntime({
286
- agents,
287
- afterRequestMiddleware: async ({ response, threadId, messages }) => {
288
- void queue.enqueue({ type: "chat", threadId, messages, response });
289
- },
290
- });
291
- ```
292
-
293
- The `afterRequestMiddleware` callback receives
294
- `{ runtime, response, path, messages?, threadId?, runId? }` — all these fields are always
295
- available (`messages`/`threadId`/`runId` are populated from the SSE stream when present,
296
- undefined otherwise). The hook runs non-blocking via `.catch()` so errors only log and any
297
- heavy awaited work can be lost on process exit — fire-and-forget is the intended shape.
298
-
299
- Source: `packages/runtime/src/v2/runtime/core/fetch-handler.ts:225-234`.
300
-
301
- ### MEDIUM Passing a webhook URL string as middleware
302
-
303
- Wrong:
304
-
305
- ```typescript
306
- new CopilotRuntime({
307
- agents,
308
- beforeRequestMiddleware: "https://hooks.example/auth" as any,
309
- });
310
- ```
311
-
312
- Correct:
313
-
314
- ```typescript
315
- new CopilotRuntime({
316
- agents,
317
- beforeRequestMiddleware: async ({ request }) => {
318
- await fetch("https://hooks.example/auth", {
319
- method: "POST",
320
- body: request.headers.get("authorization") ?? "",
321
- });
322
- },
323
- });
324
- ```
325
-
326
- Webhook-URL middleware is dead code in v2 — the runtime logs
327
- `"Unsupported beforeRequestMiddleware value – skipped"` and does nothing. Only function
328
- middleware is wired.
329
-
330
- Source: `packages/runtime/src/v2/runtime/core/middleware.ts:72-87`.
331
-
332
- ### HIGH Implementing auth / rate-limit inside CopilotKit middleware
333
-
334
- Wrong:
335
-
336
- ```typescript
337
- new CopilotRuntime({
338
- agents,
339
- beforeRequestMiddleware: async ({ request }) => {
340
- // hand-rolling a token-bucket rate limiter inline with Redis calls...
341
- },
342
- });
343
- ```
344
-
345
- Correct:
346
-
347
- ```typescript
348
- import { Ratelimit } from "@upstash/ratelimit";
349
- import { Redis } from "@upstash/redis";
350
-
351
- const ratelimit = new Ratelimit({
352
- redis: Redis.fromEnv(),
353
- limiter: Ratelimit.slidingWindow(60, "1 m"),
354
- });
355
-
356
- new CopilotRuntime({
357
- agents,
358
- beforeRequestMiddleware: async ({ request }) => {
359
- const { success } = await ratelimit.limit(
360
- request.headers.get("x-user-id") ?? "anon",
361
- );
362
- if (!success) throw new Response("Too Many Requests", { status: 429 });
363
- },
364
- });
365
- ```
366
-
367
- Auth, rate-limiting, and observability are server-framework concerns. CopilotKit middleware
368
- is the hook to invoke them, not a replacement.
369
-
370
- Source: maintainer interview (Phase 2c).
371
-
372
- ## See also
373
-
374
- - `copilotkit/setup-endpoint` — `hooks` are passed to `createCopilotRuntimeHandler`
375
- - `copilotkit/go-to-production` — production checklist lists auth/rate-limit wiring
376
- - `copilotkit/debug-and-troubleshoot` — `onError` telemetry pattern