@copilotkitnext/react 0.0.3 → 0.0.4

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 (48) hide show
  1. package/package.json +3 -3
  2. package/.turbo/turbo-build$colon$css.log +0 -9
  3. package/.turbo/turbo-build.log +0 -30
  4. package/.turbo/turbo-check-types.log +0 -7
  5. package/.turbo/turbo-lint.log +0 -78
  6. package/.turbo/turbo-test.log +0 -79
  7. package/postcss.config.js +0 -7
  8. package/src/__tests__/setup.ts +0 -2
  9. package/src/components/chat/CopilotChat.tsx +0 -90
  10. package/src/components/chat/CopilotChatAssistantMessage.tsx +0 -478
  11. package/src/components/chat/CopilotChatAudioRecorder.tsx +0 -157
  12. package/src/components/chat/CopilotChatInput.tsx +0 -596
  13. package/src/components/chat/CopilotChatMessageView.tsx +0 -85
  14. package/src/components/chat/CopilotChatToolCallsView.tsx +0 -43
  15. package/src/components/chat/CopilotChatUserMessage.tsx +0 -337
  16. package/src/components/chat/CopilotChatView.tsx +0 -385
  17. package/src/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +0 -684
  18. package/src/components/chat/__tests__/CopilotChatInput.test.tsx +0 -531
  19. package/src/components/chat/__tests__/setup.ts +0 -1
  20. package/src/components/chat/index.ts +0 -35
  21. package/src/components/index.ts +0 -4
  22. package/src/components/ui/button.tsx +0 -123
  23. package/src/components/ui/dropdown-menu.tsx +0 -257
  24. package/src/components/ui/tooltip.tsx +0 -59
  25. package/src/hooks/index.ts +0 -6
  26. package/src/hooks/use-agent-context.tsx +0 -17
  27. package/src/hooks/use-agent.tsx +0 -48
  28. package/src/hooks/use-frontend-tool.tsx +0 -46
  29. package/src/hooks/use-human-in-the-loop.tsx +0 -76
  30. package/src/hooks/use-render-tool-call.tsx +0 -81
  31. package/src/index.ts +0 -4
  32. package/src/lib/__tests__/completePartialMarkdown.test.ts +0 -495
  33. package/src/lib/__tests__/renderSlot.test.tsx +0 -610
  34. package/src/lib/slots.tsx +0 -55
  35. package/src/lib/utils.ts +0 -6
  36. package/src/providers/CopilotChatConfigurationProvider.tsx +0 -81
  37. package/src/providers/CopilotKitProvider.tsx +0 -269
  38. package/src/providers/__tests__/CopilotKitProvider.test.tsx +0 -487
  39. package/src/providers/__tests__/CopilotKitProvider.wildcard.test.tsx +0 -261
  40. package/src/providers/index.ts +0 -14
  41. package/src/styles/globals.css +0 -302
  42. package/src/types/frontend-tool.ts +0 -8
  43. package/src/types/human-in-the-loop.ts +0 -33
  44. package/src/types/index.ts +0 -3
  45. package/src/types/react-tool-call-render.ts +0 -29
  46. package/tailwind.config.js +0 -9
  47. package/tsconfig.json +0 -23
  48. package/tsup.config.ts +0 -19
@@ -1,487 +0,0 @@
1
- import React from "react";
2
- import { render, renderHook, waitFor } from "@testing-library/react";
3
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
4
- import { CopilotKitProvider, useCopilotKit } from "../CopilotKitProvider";
5
- import { ReactFrontendTool } from "../../types/frontend-tool";
6
- import { ReactHumanInTheLoop } from "../../types/human-in-the-loop";
7
- import { z } from "zod";
8
-
9
- // Mock console methods
10
- const originalConsoleError = console.error;
11
- const originalConsoleWarn = console.warn;
12
-
13
- describe("CopilotKitProvider", () => {
14
- let consoleErrorSpy: ReturnType<typeof vi.spyOn>;
15
- let consoleWarnSpy: ReturnType<typeof vi.spyOn>;
16
-
17
- beforeEach(() => {
18
- consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
19
- consoleWarnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
20
- });
21
-
22
- afterEach(() => {
23
- consoleErrorSpy.mockRestore();
24
- consoleWarnSpy.mockRestore();
25
- });
26
-
27
- describe("Basic functionality", () => {
28
- it("provides context to children", () => {
29
- const { result } = renderHook(() => useCopilotKit(), {
30
- wrapper: ({ children }) => (
31
- <CopilotKitProvider>{children}</CopilotKitProvider>
32
- ),
33
- });
34
-
35
- expect(result.current).toBeDefined();
36
- expect(result.current.copilotkit).toBeDefined();
37
- expect(result.current.renderToolCalls).toBeDefined();
38
- expect(result.current.currentRenderToolCalls).toBeDefined();
39
- expect(result.current.setCurrentRenderToolCalls).toBeDefined();
40
- });
41
-
42
- it("throws error when used outside provider", () => {
43
- // Temporarily restore console.error for this test
44
- consoleErrorSpy.mockRestore();
45
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
46
-
47
- expect(() => {
48
- renderHook(() => useCopilotKit());
49
- }).toThrow();
50
-
51
- errorSpy.mockRestore();
52
- consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
53
- });
54
- });
55
-
56
- describe("frontendTools prop", () => {
57
- it("registers frontend tools with CopilotKitCore", () => {
58
- const mockHandler = vi.fn();
59
- const frontendTools: ReactFrontendTool[] = [
60
- {
61
- name: "testTool",
62
- description: "A test tool",
63
- parameters: z.object({
64
- input: z.string(),
65
- }),
66
- handler: mockHandler,
67
- },
68
- ];
69
-
70
- const { result } = renderHook(() => useCopilotKit(), {
71
- wrapper: ({ children }) => (
72
- <CopilotKitProvider frontendTools={frontendTools}>
73
- {children}
74
- </CopilotKitProvider>
75
- ),
76
- });
77
-
78
- expect(result.current.copilotkit.tools["testTool"]).toBeDefined();
79
- expect(result.current.copilotkit.tools["testTool"]?.name).toBe("testTool");
80
- expect(result.current.copilotkit.tools["testTool"]?.handler).toBe(mockHandler);
81
- });
82
-
83
- it("includes render components from frontend tools", () => {
84
- const TestComponent: React.FC<any> = () => <div>Test</div>;
85
- const frontendTools: ReactFrontendTool[] = [
86
- {
87
- name: "renderTool",
88
- description: "A tool with render",
89
- parameters: z.object({
90
- input: z.string(),
91
- }),
92
- render: TestComponent,
93
- },
94
- ];
95
-
96
- const { result } = renderHook(() => useCopilotKit(), {
97
- wrapper: ({ children }) => (
98
- <CopilotKitProvider frontendTools={frontendTools}>
99
- {children}
100
- </CopilotKitProvider>
101
- ),
102
- });
103
-
104
- const renderTool = result.current.renderToolCalls.find(rc => rc.name === "renderTool");
105
- expect(renderTool).toBeDefined();
106
- expect(renderTool?.render).toBe(TestComponent);
107
- });
108
-
109
- it("warns when frontendTools prop changes", async () => {
110
- const initialTools: ReactFrontendTool[] = [
111
- {
112
- name: "tool1",
113
- description: "Tool 1",
114
- },
115
- ];
116
-
117
- const { rerender } = render(
118
- <CopilotKitProvider frontendTools={initialTools}>
119
- <div>Test</div>
120
- </CopilotKitProvider>
121
- );
122
-
123
- const newTools: ReactFrontendTool[] = [
124
- {
125
- name: "tool2",
126
- description: "Tool 2",
127
- },
128
- ];
129
-
130
- rerender(
131
- <CopilotKitProvider frontendTools={newTools}>
132
- <div>Test</div>
133
- </CopilotKitProvider>
134
- );
135
-
136
- await waitFor(() => {
137
- expect(consoleErrorSpy).toHaveBeenCalledWith(
138
- expect.stringContaining("frontendTools must be a stable array")
139
- );
140
- });
141
- });
142
- });
143
-
144
- describe("humanInTheLoop prop", () => {
145
- it("processes humanInTheLoop tools and creates handlers", () => {
146
- const TestComponent: React.FC<any> = () => <div>Test</div>;
147
- const humanInTheLoopTools: ReactHumanInTheLoop[] = [
148
- {
149
- name: "approvalTool",
150
- description: "Requires human approval",
151
- parameters: z.object({
152
- question: z.string(),
153
- }),
154
- render: TestComponent,
155
- },
156
- ];
157
-
158
- const { result } = renderHook(() => useCopilotKit(), {
159
- wrapper: ({ children }) => (
160
- <CopilotKitProvider humanInTheLoop={humanInTheLoopTools}>
161
- {children}
162
- </CopilotKitProvider>
163
- ),
164
- });
165
-
166
- // Check that the tool is registered
167
- expect(result.current.copilotkit.tools["approvalTool"]).toBeDefined();
168
- expect(result.current.copilotkit.tools["approvalTool"]?.name).toBe("approvalTool");
169
- expect(result.current.copilotkit.tools["approvalTool"]?.handler).toBeDefined();
170
-
171
- // Check that render component is registered
172
- const approvalTool = result.current.renderToolCalls.find(rc => rc.name === "approvalTool");
173
- expect(approvalTool).toBeDefined();
174
- expect(approvalTool?.render).toBe(TestComponent);
175
- });
176
-
177
- it("creates placeholder handlers for humanInTheLoop tools", async () => {
178
- const TestComponent: React.FC<any> = () => <div>Test</div>;
179
- const humanInTheLoopTools: ReactHumanInTheLoop[] = [
180
- {
181
- name: "interactiveTool",
182
- description: "Interactive tool",
183
- parameters: z.object({
184
- data: z.string(),
185
- }),
186
- render: TestComponent,
187
- },
188
- ];
189
-
190
- const { result } = renderHook(() => useCopilotKit(), {
191
- wrapper: ({ children }) => (
192
- <CopilotKitProvider humanInTheLoop={humanInTheLoopTools}>
193
- {children}
194
- </CopilotKitProvider>
195
- ),
196
- });
197
-
198
- const handler = result.current.copilotkit.tools["interactiveTool"]?.handler;
199
- expect(handler).toBeDefined();
200
-
201
- // Call the handler and check for warning
202
- const handlerPromise = handler!({ data: "test" });
203
-
204
- await waitFor(() => {
205
- expect(consoleWarnSpy).toHaveBeenCalledWith(
206
- expect.stringContaining("Human-in-the-loop tool 'interactiveTool' called")
207
- );
208
- });
209
-
210
- const result2 = await handlerPromise;
211
- expect(result2).toBeUndefined();
212
- });
213
-
214
- it("warns when humanInTheLoop prop changes", async () => {
215
- const TestComponent: React.FC<any> = () => <div>Test</div>;
216
- const initialTools: ReactHumanInTheLoop[] = [
217
- {
218
- name: "tool1",
219
- description: "Tool 1",
220
- render: TestComponent,
221
- },
222
- ];
223
-
224
- const { rerender } = render(
225
- <CopilotKitProvider humanInTheLoop={initialTools}>
226
- <div>Test</div>
227
- </CopilotKitProvider>
228
- );
229
-
230
- const newTools: ReactHumanInTheLoop[] = [
231
- {
232
- name: "tool2",
233
- description: "Tool 2",
234
- render: TestComponent,
235
- },
236
- ];
237
-
238
- rerender(
239
- <CopilotKitProvider humanInTheLoop={newTools}>
240
- <div>Test</div>
241
- </CopilotKitProvider>
242
- );
243
-
244
- await waitFor(() => {
245
- expect(consoleErrorSpy).toHaveBeenCalledWith(
246
- expect.stringContaining("humanInTheLoop must be a stable array")
247
- );
248
- });
249
- });
250
- });
251
-
252
- describe("Combined tools functionality", () => {
253
- it("registers both frontendTools and humanInTheLoop tools", () => {
254
- const TestComponent: React.FC<any> = () => <div>Test</div>;
255
- const frontendTools: ReactFrontendTool[] = [
256
- {
257
- name: "frontendTool",
258
- description: "Frontend tool",
259
- handler: vi.fn(),
260
- },
261
- ];
262
- const humanInTheLoopTools: ReactHumanInTheLoop[] = [
263
- {
264
- name: "humanTool",
265
- description: "Human tool",
266
- render: TestComponent,
267
- },
268
- ];
269
-
270
- const { result } = renderHook(() => useCopilotKit(), {
271
- wrapper: ({ children }) => (
272
- <CopilotKitProvider
273
- frontendTools={frontendTools}
274
- humanInTheLoop={humanInTheLoopTools}
275
- >
276
- {children}
277
- </CopilotKitProvider>
278
- ),
279
- });
280
-
281
- expect(result.current.copilotkit.tools["frontendTool"]).toBeDefined();
282
- expect(result.current.copilotkit.tools["humanTool"]).toBeDefined();
283
- });
284
-
285
- it("should handle agentId in frontend tools", () => {
286
- const handler1 = vi.fn();
287
- const handler2 = vi.fn();
288
-
289
- const frontendTools: ReactFrontendTool[] = [
290
- {
291
- name: "globalTool",
292
- description: "Global tool",
293
- handler: handler1,
294
- },
295
- {
296
- name: "agentSpecificTool",
297
- description: "Agent specific tool",
298
- handler: handler2,
299
- agentId: "specificAgent",
300
- },
301
- ];
302
-
303
- const { result } = renderHook(() => useCopilotKit(), {
304
- wrapper: ({ children }) => (
305
- <CopilotKitProvider frontendTools={frontendTools}>
306
- {children}
307
- </CopilotKitProvider>
308
- ),
309
- });
310
-
311
- expect(result.current.copilotkit.tools["globalTool"]).toBeDefined();
312
- expect(result.current.copilotkit.tools["globalTool"]?.agentId).toBeUndefined();
313
- expect(result.current.copilotkit.tools["agentSpecificTool"]).toBeDefined();
314
- expect(result.current.copilotkit.tools["agentSpecificTool"]?.agentId).toBe("specificAgent");
315
- });
316
-
317
- it("combines render components from all sources", () => {
318
- const TestComponent1: React.FC<any> = () => <div>Test1</div>;
319
- const TestComponent2: React.FC<any> = () => <div>Test2</div>;
320
- const TestComponent3: React.FC<any> = () => <div>Test3</div>;
321
-
322
- const frontendTools: ReactFrontendTool[] = [
323
- {
324
- name: "frontendRenderTool",
325
- description: "Frontend render tool",
326
- parameters: z.object({ a: z.string() }),
327
- render: TestComponent1,
328
- },
329
- ];
330
-
331
- const humanInTheLoopTools: ReactHumanInTheLoop[] = [
332
- {
333
- name: "humanRenderTool",
334
- description: "Human render tool",
335
- parameters: z.object({ b: z.string() }),
336
- render: TestComponent2,
337
- },
338
- ];
339
-
340
- const renderToolCalls = [
341
- {
342
- name: "directRenderTool",
343
- args: z.object({ c: z.string() }),
344
- render: TestComponent3,
345
- },
346
- ];
347
-
348
- const { result } = renderHook(() => useCopilotKit(), {
349
- wrapper: ({ children }) => (
350
- <CopilotKitProvider
351
- frontendTools={frontendTools}
352
- humanInTheLoop={humanInTheLoopTools}
353
- renderToolCalls={renderToolCalls}
354
- >
355
- {children}
356
- </CopilotKitProvider>
357
- ),
358
- });
359
-
360
- const frontendRenderTool = result.current.renderToolCalls.find(rc => rc.name === "frontendRenderTool");
361
- const humanRenderTool = result.current.renderToolCalls.find(rc => rc.name === "humanRenderTool");
362
- const directRenderTool = result.current.renderToolCalls.find(rc => rc.name === "directRenderTool");
363
-
364
- expect(frontendRenderTool).toBeDefined();
365
- expect(humanRenderTool).toBeDefined();
366
- expect(directRenderTool).toBeDefined();
367
-
368
- expect(frontendRenderTool?.render).toBe(TestComponent1);
369
- expect(humanRenderTool?.render).toBe(TestComponent2);
370
- expect(directRenderTool?.render).toBe(TestComponent3);
371
- });
372
- });
373
-
374
- describe("currentRenderToolCalls state", () => {
375
- it("initializes currentRenderToolCalls with all render tools", async () => {
376
- const TestComponent: React.FC<any> = () => <div>Test</div>;
377
- const frontendTools: ReactFrontendTool[] = [
378
- {
379
- name: "tool1",
380
- description: "Tool 1",
381
- parameters: z.object({ a: z.string() }),
382
- render: TestComponent,
383
- },
384
- ];
385
-
386
- const { result } = renderHook(() => useCopilotKit(), {
387
- wrapper: ({ children }) => (
388
- <CopilotKitProvider frontendTools={frontendTools}>
389
- {children}
390
- </CopilotKitProvider>
391
- ),
392
- });
393
-
394
- await waitFor(() => {
395
- const tool1 = result.current.currentRenderToolCalls.find(rc => rc.name === "tool1");
396
- expect(tool1).toBeDefined();
397
- });
398
- });
399
-
400
- it("allows updating currentRenderToolCalls", async () => {
401
- const TestComponent: React.FC<any> = () => <div>Test</div>;
402
- const NewComponent: React.FC<any> = () => <div>New</div>;
403
-
404
- const { result } = renderHook(() => useCopilotKit(), {
405
- wrapper: ({ children }) => (
406
- <CopilotKitProvider>{children}</CopilotKitProvider>
407
- ),
408
- });
409
-
410
- const newRenderToolCall = [
411
- {
412
- name: "dynamicTool",
413
- args: z.object({ x: z.string() }),
414
- render: NewComponent,
415
- },
416
- ];
417
-
418
- result.current.setCurrentRenderToolCalls(newRenderToolCall);
419
-
420
- await waitFor(() => {
421
- const dynamicTool = result.current.currentRenderToolCalls.find(rc => rc.name === "dynamicTool");
422
- expect(dynamicTool).toBeDefined();
423
- expect(dynamicTool?.render).toBe(NewComponent);
424
- });
425
- });
426
- });
427
-
428
- describe("Edge cases", () => {
429
- it("handles empty arrays for tools", () => {
430
- const { result } = renderHook(() => useCopilotKit(), {
431
- wrapper: ({ children }) => (
432
- <CopilotKitProvider frontendTools={[]} humanInTheLoop={[]}>
433
- {children}
434
- </CopilotKitProvider>
435
- ),
436
- });
437
-
438
- expect(Object.keys(result.current.copilotkit.tools)).toHaveLength(0);
439
- expect(Object.keys(result.current.renderToolCalls)).toHaveLength(0);
440
- });
441
-
442
- it("handles tools without render components", () => {
443
- const frontendTools: ReactFrontendTool[] = [
444
- {
445
- name: "noRenderTool",
446
- description: "Tool without render",
447
- handler: vi.fn(),
448
- },
449
- ];
450
-
451
- const { result } = renderHook(() => useCopilotKit(), {
452
- wrapper: ({ children }) => (
453
- <CopilotKitProvider frontendTools={frontendTools}>
454
- {children}
455
- </CopilotKitProvider>
456
- ),
457
- });
458
-
459
- expect(result.current.copilotkit.tools["noRenderTool"]).toBeDefined();
460
- const noRenderTool = result.current.renderToolCalls.find(rc => rc.name === "noRenderTool");
461
- expect(noRenderTool).toBeUndefined();
462
- });
463
-
464
- it("handles humanInTheLoop tools with followUp flag", () => {
465
- const TestComponent: React.FC<any> = () => <div>Test</div>;
466
- const humanInTheLoopTools: ReactHumanInTheLoop[] = [
467
- {
468
- name: "followUpTool",
469
- description: "Tool with followUp",
470
- parameters: z.object({ a: z.string() }),
471
- followUp: false,
472
- render: TestComponent,
473
- },
474
- ];
475
-
476
- const { result } = renderHook(() => useCopilotKit(), {
477
- wrapper: ({ children }) => (
478
- <CopilotKitProvider humanInTheLoop={humanInTheLoopTools}>
479
- {children}
480
- </CopilotKitProvider>
481
- ),
482
- });
483
-
484
- expect(result.current.copilotkit.tools["followUpTool"]?.followUp).toBe(false);
485
- });
486
- });
487
- });