@copilotkit/react-ui 1.10.0-next.1 → 1.10.0-next.11

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 (108) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/dist/{chunk-O7KTFUAN.mjs → chunk-226ZMOE3.mjs} +2 -2
  3. package/dist/{chunk-WHDNKXMP.mjs → chunk-BJHJBS5M.mjs} +46 -6
  4. package/dist/chunk-BJHJBS5M.mjs.map +1 -0
  5. package/dist/{chunk-FOSKS7AI.mjs → chunk-FFJHOZX6.mjs} +5 -5
  6. package/dist/{chunk-QELAC6XJ.mjs → chunk-GBP47ONN.mjs} +2 -2
  7. package/dist/chunk-GBP47ONN.mjs.map +1 -0
  8. package/dist/{chunk-7CAK2CNK.mjs → chunk-GDSZGYCE.mjs} +2 -2
  9. package/dist/{chunk-O7PYQO73.mjs → chunk-GJ4SX4JE.mjs} +153 -37
  10. package/dist/chunk-GJ4SX4JE.mjs.map +1 -0
  11. package/dist/{chunk-TCIZDWPC.mjs → chunk-J5ZZR6YB.mjs} +2 -2
  12. package/dist/chunk-J5ZZR6YB.mjs.map +1 -0
  13. package/dist/{chunk-QN7T3GWI.mjs → chunk-JY2CSDKN.mjs} +4 -6
  14. package/dist/chunk-JY2CSDKN.mjs.map +1 -0
  15. package/dist/chunk-MIVUCSGO.mjs +126 -0
  16. package/dist/chunk-MIVUCSGO.mjs.map +1 -0
  17. package/dist/{chunk-OQM7D3Z3.mjs → chunk-T5QU6KSB.mjs} +8 -4
  18. package/dist/chunk-T5QU6KSB.mjs.map +1 -0
  19. package/dist/{chunk-Q2467VHZ.mjs → chunk-W26XFBEG.mjs} +2 -2
  20. package/dist/chunk-W26XFBEG.mjs.map +1 -0
  21. package/dist/chunk-Y44VLEUH.mjs +222 -0
  22. package/dist/chunk-Y44VLEUH.mjs.map +1 -0
  23. package/dist/components/chat/Chat.d.ts +52 -15
  24. package/dist/components/chat/Chat.js +1136 -869
  25. package/dist/components/chat/Chat.js.map +1 -1
  26. package/dist/components/chat/Chat.mjs +9 -8
  27. package/dist/components/chat/Header.js +6 -8
  28. package/dist/components/chat/Header.js.map +1 -1
  29. package/dist/components/chat/Header.mjs +4 -4
  30. package/dist/components/chat/Messages.d.ts +1 -1
  31. package/dist/components/chat/Messages.js +984 -23
  32. package/dist/components/chat/Messages.js.map +1 -1
  33. package/dist/components/chat/Messages.mjs +9 -1
  34. package/dist/components/chat/Modal.d.ts +2 -2
  35. package/dist/components/chat/Modal.js +1267 -931
  36. package/dist/components/chat/Modal.js.map +1 -1
  37. package/dist/components/chat/Modal.mjs +14 -13
  38. package/dist/components/chat/Popup.d.ts +1 -1
  39. package/dist/components/chat/Popup.js +1269 -933
  40. package/dist/components/chat/Popup.js.map +1 -1
  41. package/dist/components/chat/Popup.mjs +15 -14
  42. package/dist/components/chat/Sidebar.d.ts +1 -1
  43. package/dist/components/chat/Sidebar.js +1269 -933
  44. package/dist/components/chat/Sidebar.js.map +1 -1
  45. package/dist/components/chat/Sidebar.mjs +15 -14
  46. package/dist/components/chat/Suggestion.js +1 -1
  47. package/dist/components/chat/Suggestion.js.map +1 -1
  48. package/dist/components/chat/Suggestion.mjs +1 -1
  49. package/dist/components/chat/Suggestions.js +1 -1
  50. package/dist/components/chat/Suggestions.js.map +1 -1
  51. package/dist/components/chat/Suggestions.mjs +2 -2
  52. package/dist/components/chat/index.d.ts +2 -2
  53. package/dist/components/chat/index.js +1271 -935
  54. package/dist/components/chat/index.js.map +1 -1
  55. package/dist/components/chat/index.mjs +22 -21
  56. package/dist/components/chat/messages/LegacyRenderMessage.d.ts +28 -0
  57. package/dist/components/chat/messages/LegacyRenderMessage.js +980 -0
  58. package/dist/components/chat/messages/LegacyRenderMessage.js.map +1 -0
  59. package/dist/components/chat/messages/LegacyRenderMessage.mjs +17 -0
  60. package/dist/components/chat/messages/LegacyRenderMessage.mjs.map +1 -0
  61. package/dist/components/chat/messages/RenderMessage.js +4 -0
  62. package/dist/components/chat/messages/RenderMessage.js.map +1 -1
  63. package/dist/components/chat/messages/RenderMessage.mjs +2 -2
  64. package/dist/components/chat/props.d.ts +94 -2
  65. package/dist/components/chat/props.js.map +1 -1
  66. package/dist/components/dev-console/console.d.ts +1 -0
  67. package/dist/components/dev-console/console.js +6 -8
  68. package/dist/components/dev-console/console.js.map +1 -1
  69. package/dist/components/dev-console/console.mjs +3 -3
  70. package/dist/components/dev-console/index.d.ts +1 -3
  71. package/dist/components/dev-console/index.js +7 -9
  72. package/dist/components/dev-console/index.js.map +1 -1
  73. package/dist/components/dev-console/index.mjs +5 -5
  74. package/dist/components/dev-console/utils.d.ts +2 -2
  75. package/dist/components/dev-console/utils.js +2 -4
  76. package/dist/components/dev-console/utils.js.map +1 -1
  77. package/dist/components/dev-console/utils.mjs +1 -1
  78. package/dist/components/index.d.ts +3 -5
  79. package/dist/components/index.js +1272 -936
  80. package/dist/components/index.js.map +1 -1
  81. package/dist/components/index.mjs +24 -23
  82. package/dist/index.d.ts +3 -5
  83. package/dist/index.js +1303 -967
  84. package/dist/index.js.map +1 -1
  85. package/dist/index.mjs +24 -23
  86. package/package.json +6 -6
  87. package/src/components/chat/Chat.tsx +241 -23
  88. package/src/components/chat/Messages.tsx +58 -5
  89. package/src/components/chat/Modal.tsx +128 -41
  90. package/src/components/chat/Popup.tsx +20 -0
  91. package/src/components/chat/Sidebar.tsx +22 -0
  92. package/src/components/chat/Suggestion.tsx +1 -1
  93. package/src/components/chat/messages/LegacyRenderMessage.tsx +143 -0
  94. package/src/components/chat/messages/RenderMessage.tsx +3 -0
  95. package/src/components/chat/props.ts +110 -1
  96. package/src/components/dev-console/utils.ts +1 -6
  97. package/dist/chunk-7RNOT3GM.mjs +0 -144
  98. package/dist/chunk-7RNOT3GM.mjs.map +0 -1
  99. package/dist/chunk-O7PYQO73.mjs.map +0 -1
  100. package/dist/chunk-OQM7D3Z3.mjs.map +0 -1
  101. package/dist/chunk-Q2467VHZ.mjs.map +0 -1
  102. package/dist/chunk-QELAC6XJ.mjs.map +0 -1
  103. package/dist/chunk-QN7T3GWI.mjs.map +0 -1
  104. package/dist/chunk-TCIZDWPC.mjs.map +0 -1
  105. package/dist/chunk-WHDNKXMP.mjs.map +0 -1
  106. /package/dist/{chunk-O7KTFUAN.mjs.map → chunk-226ZMOE3.mjs.map} +0 -0
  107. /package/dist/{chunk-FOSKS7AI.mjs.map → chunk-FFJHOZX6.mjs.map} +0 -0
  108. /package/dist/{chunk-7CAK2CNK.mjs.map → chunk-GDSZGYCE.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -4,53 +4,54 @@ import "./chunk-MMVDU6DF.mjs";
4
4
  import "./chunk-SC6JRFAJ.mjs";
5
5
  import {
6
6
  CopilotSidebar
7
- } from "./chunk-QELAC6XJ.mjs";
7
+ } from "./chunk-GBP47ONN.mjs";
8
8
  import "./chunk-WB3YULQ4.mjs";
9
9
  import {
10
10
  CopilotPopup
11
- } from "./chunk-TCIZDWPC.mjs";
12
- import "./chunk-7RNOT3GM.mjs";
11
+ } from "./chunk-J5ZZR6YB.mjs";
12
+ import "./chunk-Y44VLEUH.mjs";
13
13
  import "./chunk-C3GSYRC3.mjs";
14
- import "./chunk-7CAK2CNK.mjs";
14
+ import "./chunk-GDSZGYCE.mjs";
15
15
  import "./chunk-V7W6IM2V.mjs";
16
16
  import {
17
17
  CopilotDevConsole
18
- } from "./chunk-FOSKS7AI.mjs";
19
- import "./chunk-KXE2JCUH.mjs";
20
- import "./chunk-NRA3CFEE.mjs";
21
- import "./chunk-BH6PCAAL.mjs";
18
+ } from "./chunk-FFJHOZX6.mjs";
22
19
  import "./chunk-Q5V6S67N.mjs";
23
20
  import {
24
21
  shouldShowDevConsole
25
- } from "./chunk-QN7T3GWI.mjs";
22
+ } from "./chunk-JY2CSDKN.mjs";
23
+ import "./chunk-KXE2JCUH.mjs";
24
+ import "./chunk-NRA3CFEE.mjs";
25
+ import "./chunk-BH6PCAAL.mjs";
26
26
  import "./chunk-UFN2VWSR.mjs";
27
27
  import {
28
28
  CopilotChat
29
- } from "./chunk-O7PYQO73.mjs";
30
- import "./chunk-OQM7D3Z3.mjs";
31
- import {
32
- UserMessage
33
- } from "./chunk-VVL6JFCJ.mjs";
34
- import {
35
- AssistantMessage
36
- } from "./chunk-GCKKSSBU.mjs";
37
- import {
38
- ImageRenderer
39
- } from "./chunk-DBKRAOH7.mjs";
29
+ } from "./chunk-GJ4SX4JE.mjs";
40
30
  import {
41
31
  Suggestions
42
- } from "./chunk-O7KTFUAN.mjs";
32
+ } from "./chunk-226ZMOE3.mjs";
43
33
  import {
44
34
  Suggestion
45
- } from "./chunk-Q2467VHZ.mjs";
35
+ } from "./chunk-W26XFBEG.mjs";
46
36
  import "./chunk-PLHTVHUW.mjs";
47
37
  import "./chunk-DTRPPNSA.mjs";
48
38
  import "./chunk-CGEAG65D.mjs";
49
39
  import "./chunk-QIOJXTIQ.mjs";
40
+ import "./chunk-BJHJBS5M.mjs";
41
+ import "./chunk-MIVUCSGO.mjs";
42
+ import "./chunk-T5QU6KSB.mjs";
43
+ import {
44
+ AssistantMessage
45
+ } from "./chunk-GCKKSSBU.mjs";
46
+ import {
47
+ ImageRenderer
48
+ } from "./chunk-DBKRAOH7.mjs";
49
+ import {
50
+ UserMessage
51
+ } from "./chunk-VVL6JFCJ.mjs";
50
52
  import {
51
53
  Markdown
52
54
  } from "./chunk-E6MQUIZW.mjs";
53
- import "./chunk-WHDNKXMP.mjs";
54
55
  import {
55
56
  useChatContext
56
57
  } from "./chunk-IEMQ2SQW.mjs";
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.10.0-next.1",
12
+ "version": "1.10.0-next.11",
13
13
  "sideEffects": [
14
14
  "**/*.css"
15
15
  ],
@@ -40,9 +40,9 @@
40
40
  "ts-jest": "^29.1.1",
41
41
  "tsup": "^6.7.0",
42
42
  "typescript": "^5.2.3",
43
- "eslint-config-custom": "1.4.6",
44
43
  "tailwind-config": "1.4.6",
45
- "tsconfig": "1.4.6"
44
+ "tsconfig": "1.4.6",
45
+ "eslint-config-custom": "1.4.6"
46
46
  },
47
47
  "dependencies": {
48
48
  "@headlessui/react": "^2.1.3",
@@ -51,9 +51,9 @@
51
51
  "rehype-raw": "^7.0.0",
52
52
  "remark-gfm": "^4.0.1",
53
53
  "remark-math": "^6.0.0",
54
- "@copilotkit/react-core": "1.10.0-next.1",
55
- "@copilotkit/runtime-client-gql": "1.10.0-next.1",
56
- "@copilotkit/shared": "1.10.0-next.1"
54
+ "@copilotkit/react-core": "1.10.0-next.11",
55
+ "@copilotkit/runtime-client-gql": "1.10.0-next.11",
56
+ "@copilotkit/shared": "1.10.0-next.11"
57
57
  },
58
58
  "keywords": [
59
59
  "copilotkit",
@@ -27,6 +27,23 @@
27
27
  * />
28
28
  * ```
29
29
  *
30
+ * ### With Observability Hooks
31
+ *
32
+ * To monitor user interactions, provide the `observabilityHooks` prop.
33
+ * **Note:** This requires a `publicApiKey` in the `<CopilotKit>` provider.
34
+ *
35
+ * ```tsx
36
+ * <CopilotKit publicApiKey="YOUR_PUBLIC_API_KEY">
37
+ * <CopilotChat
38
+ * observabilityHooks={{
39
+ * onMessageSent: (message) => {
40
+ * console.log("Message sent:", message);
41
+ * },
42
+ * }}
43
+ * />
44
+ * </CopilotKit>
45
+ * ```
46
+ *
30
47
  * ### Look & Feel
31
48
  *
32
49
  * By default, CopilotKit components do not have any styles. You can import CopilotKit's stylesheet at the root of your project:
@@ -60,16 +77,25 @@ import { ImageRenderer as DefaultImageRenderer } from "./messages/ImageRenderer"
60
77
  import React, { useEffect, useRef, useState, useCallback, useMemo } from "react";
61
78
  import {
62
79
  SystemMessageFunction,
63
- useCopilotChat,
80
+ useCopilotChatInternal as useCopilotChat,
64
81
  useCopilotContext,
65
82
  useCopilotMessagesContext,
66
83
  } from "@copilotkit/react-core";
67
84
  import type { SuggestionItem } from "@copilotkit/react-core";
68
- import { Message } from "@copilotkit/shared";
85
+ import {
86
+ CopilotKitError,
87
+ CopilotKitErrorCode,
88
+ CopilotErrorEvent,
89
+ Message,
90
+ Severity,
91
+ ErrorVisibility,
92
+ styledConsole,
93
+ } from "@copilotkit/shared";
69
94
  import { randomId } from "@copilotkit/shared";
70
95
  import {
71
96
  AssistantMessageProps,
72
97
  ComponentsMap,
98
+ CopilotObservabilityHooks,
73
99
  ImageRendererProps,
74
100
  InputProps,
75
101
  MessagesProps,
@@ -214,6 +240,31 @@ export interface CopilotChatProps {
214
240
  */
215
241
  Messages?: React.ComponentType<MessagesProps>;
216
242
 
243
+ /**
244
+ * @deprecated - use RenderMessage instead
245
+ */
246
+ RenderTextMessage?: React.ComponentType<RenderMessageProps>;
247
+
248
+ /**
249
+ * @deprecated - use RenderMessage instead
250
+ */
251
+ RenderActionExecutionMessage?: React.ComponentType<RenderMessageProps>;
252
+
253
+ /**
254
+ * @deprecated - use RenderMessage instead
255
+ */
256
+ RenderAgentStateMessage?: React.ComponentType<RenderMessageProps>;
257
+
258
+ /**
259
+ * @deprecated - use RenderMessage instead
260
+ */
261
+ RenderResultMessage?: React.ComponentType<RenderMessageProps>;
262
+
263
+ /**
264
+ * @deprecated - use RenderMessage instead
265
+ */
266
+ RenderImageMessage?: React.ComponentType<RenderMessageProps>;
267
+
217
268
  /**
218
269
  * A custom RenderMessage component to use instead of the default.
219
270
  *
@@ -250,6 +301,24 @@ export interface CopilotChatProps {
250
301
  children?: React.ReactNode;
251
302
 
252
303
  hideStopButton?: boolean;
304
+
305
+ /**
306
+ * Event hooks for CopilotKit chat events.
307
+ * These hooks only work when publicApiKey is provided.
308
+ */
309
+ observabilityHooks?: CopilotObservabilityHooks;
310
+
311
+ /**
312
+ * Custom error renderer for chat-specific errors.
313
+ * When provided, errors will be displayed inline within the chat interface.
314
+ */
315
+ renderError?: (error: {
316
+ message: string;
317
+ operation?: string;
318
+ timestamp: number;
319
+ onDismiss: () => void;
320
+ onRetry?: () => void;
321
+ }) => React.ReactNode;
253
322
  }
254
323
 
255
324
  interface OnStopGenerationArguments {
@@ -336,11 +405,101 @@ export function CopilotChat({
336
405
  imageUploadsEnabled,
337
406
  inputFileAccept = "image/*",
338
407
  hideStopButton,
408
+ observabilityHooks,
409
+ renderError,
410
+
411
+ // Legacy props - deprecated
412
+ RenderTextMessage,
413
+ RenderActionExecutionMessage,
414
+ RenderAgentStateMessage,
415
+ RenderResultMessage,
416
+ RenderImageMessage,
339
417
  }: CopilotChatProps) {
340
- const { additionalInstructions, setChatInstructions } = useCopilotContext();
418
+ const { additionalInstructions, setChatInstructions, copilotApiConfig, setBannerError } =
419
+ useCopilotContext();
420
+
421
+ // Destructure stable values to avoid object reference changes
422
+ const { publicApiKey, chatApiEndpoint } = copilotApiConfig;
341
423
  const [selectedImages, setSelectedImages] = useState<Array<ImageUpload>>([]);
424
+ const [chatError, setChatError] = useState<{
425
+ message: string;
426
+ operation?: string;
427
+ timestamp: number;
428
+ } | null>(null);
342
429
  const fileInputRef = useRef<HTMLInputElement>(null);
343
430
 
431
+ // Helper function to trigger event hooks only if publicApiKey is provided
432
+ const triggerObservabilityHook = useCallback(
433
+ (hookName: keyof CopilotObservabilityHooks, ...args: any[]) => {
434
+ if (publicApiKey && observabilityHooks?.[hookName]) {
435
+ (observabilityHooks[hookName] as any)(...args);
436
+ }
437
+ if (observabilityHooks?.[hookName] && !publicApiKey) {
438
+ setBannerError(
439
+ new CopilotKitError({
440
+ message: "observabilityHooks requires a publicApiKey to function.",
441
+ code: CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
442
+ severity: Severity.CRITICAL,
443
+ visibility: ErrorVisibility.BANNER,
444
+ }),
445
+ );
446
+ styledConsole.publicApiKeyRequired("observabilityHooks");
447
+ }
448
+ },
449
+ [publicApiKey, observabilityHooks, setBannerError],
450
+ );
451
+
452
+ // Helper function to trigger chat error and render error UI
453
+ const triggerChatError = useCallback(
454
+ (error: any, operation: string, originalError?: any) => {
455
+ const errorMessage = error?.message || error?.toString() || "An error occurred";
456
+
457
+ // Set chat error state for rendering
458
+ setChatError({
459
+ message: errorMessage,
460
+ operation,
461
+ timestamp: Date.now(),
462
+ });
463
+
464
+ // Also trigger observability hook if available
465
+ if (publicApiKey && observabilityHooks?.onError) {
466
+ const errorEvent: CopilotErrorEvent = {
467
+ type: "error",
468
+ timestamp: Date.now(),
469
+ context: {
470
+ source: "ui",
471
+ request: {
472
+ operation,
473
+ url: chatApiEndpoint,
474
+ startTime: Date.now(),
475
+ },
476
+ technical: {
477
+ environment: "browser",
478
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : undefined,
479
+ stackTrace: originalError instanceof Error ? originalError.stack : undefined,
480
+ },
481
+ },
482
+ error,
483
+ };
484
+ observabilityHooks.onError(errorEvent);
485
+ }
486
+
487
+ // Show banner error if onError hook is used without publicApiKey
488
+ if (observabilityHooks?.onError && !publicApiKey) {
489
+ setBannerError(
490
+ new CopilotKitError({
491
+ message: "observabilityHooks.onError requires a publicApiKey to function.",
492
+ code: CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
493
+ severity: Severity.CRITICAL,
494
+ visibility: ErrorVisibility.BANNER,
495
+ }),
496
+ );
497
+ styledConsole.publicApiKeyRequired("observabilityHooks.onError");
498
+ }
499
+ },
500
+ [publicApiKey, chatApiEndpoint, observabilityHooks, setBannerError],
501
+ );
502
+
344
503
  // Clipboard paste handler
345
504
  useEffect(() => {
346
505
  if (!imageUploadsEnabled) return;
@@ -382,14 +541,15 @@ export function CopilotChat({
382
541
  const loadedImages = (await Promise.all(imagePromises)).filter((img) => img !== null);
383
542
  setSelectedImages((prev) => [...prev, ...loadedImages]);
384
543
  } catch (error) {
385
- // TODO: Show an error message to the user
544
+ // Trigger chat-level error handler
545
+ triggerChatError(error, "processClipboardImages", error);
386
546
  console.error("Error processing pasted images:", error);
387
547
  }
388
548
  };
389
549
 
390
550
  document.addEventListener("paste", handlePaste);
391
551
  return () => document.removeEventListener("paste", handlePaste);
392
- }, [imageUploadsEnabled]);
552
+ }, [imageUploadsEnabled, triggerChatError]);
393
553
 
394
554
  useEffect(() => {
395
555
  if (!additionalInstructions?.length) {
@@ -415,7 +575,7 @@ export function CopilotChat({
415
575
  }, [instructions, additionalInstructions]);
416
576
 
417
577
  const {
418
- visibleMessages,
578
+ messages,
419
579
  isLoading,
420
580
  sendMessage,
421
581
  stopGeneration,
@@ -430,6 +590,19 @@ export function CopilotChat({
430
590
  onReloadMessages,
431
591
  );
432
592
 
593
+ // Track loading state changes for chat start/stop events
594
+ const prevIsLoading = useRef(isLoading);
595
+ useEffect(() => {
596
+ if (prevIsLoading.current !== isLoading) {
597
+ if (isLoading) {
598
+ triggerObservabilityHook("onChatStarted");
599
+ } else {
600
+ triggerObservabilityHook("onChatStopped");
601
+ }
602
+ prevIsLoading.current = isLoading;
603
+ }
604
+ }, [isLoading, triggerObservabilityHook]);
605
+
433
606
  // Wrapper for sendMessage to clear selected images
434
607
  const handleSendMessage = (text: string) => {
435
608
  const images = selectedImages;
@@ -438,6 +611,9 @@ export function CopilotChat({
438
611
  fileInputRef.current.value = "";
439
612
  }
440
613
 
614
+ // Trigger message sent event
615
+ triggerObservabilityHook("onMessageSent", text);
616
+
441
617
  return sendMessage(text, images);
442
618
  };
443
619
 
@@ -449,6 +625,9 @@ export function CopilotChat({
449
625
  onRegenerate(messageId);
450
626
  }
451
627
 
628
+ // Trigger message regenerated event
629
+ triggerObservabilityHook("onMessageRegenerated", messageId);
630
+
452
631
  reloadMessages(messageId);
453
632
  };
454
633
 
@@ -456,6 +635,9 @@ export function CopilotChat({
456
635
  if (onCopy) {
457
636
  onCopy(message);
458
637
  }
638
+
639
+ // Trigger message copied event
640
+ triggerObservabilityHook("onMessageCopied", message);
459
641
  };
460
642
 
461
643
  const handleImageUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
@@ -487,7 +669,8 @@ export function CopilotChat({
487
669
  const loadedImages = await Promise.all(fileReadPromises);
488
670
  setSelectedImages((prev) => [...prev, ...loadedImages]);
489
671
  } catch (error) {
490
- // TODO: Show an error message to the user
672
+ // Trigger chat-level error handler
673
+ triggerChatError(error, "processUploadedImages", error);
491
674
  console.error("Error reading files:", error);
492
675
  }
493
676
  };
@@ -496,20 +679,57 @@ export function CopilotChat({
496
679
  setSelectedImages((prev) => prev.filter((_, i) => i !== index));
497
680
  };
498
681
 
682
+ const handleThumbsUp = (message: Message) => {
683
+ if (onThumbsUp) {
684
+ onThumbsUp(message);
685
+ }
686
+
687
+ // Trigger feedback given event
688
+ triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsUp");
689
+ };
690
+
691
+ const handleThumbsDown = (message: Message) => {
692
+ if (onThumbsDown) {
693
+ onThumbsDown(message);
694
+ }
695
+
696
+ // Trigger feedback given event
697
+ triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsDown");
698
+ };
699
+
499
700
  return (
500
701
  <WrappedCopilotChat icons={icons} labels={labels} className={className}>
702
+ {/* Render error above messages if present */}
703
+ {chatError &&
704
+ renderError &&
705
+ renderError({
706
+ ...chatError,
707
+ onDismiss: () => setChatError(null),
708
+ onRetry: () => {
709
+ // Clear error and potentially retry based on operation
710
+ setChatError(null);
711
+ // TODO: Implement specific retry logic based on operation type
712
+ },
713
+ })}
714
+
501
715
  <Messages
502
716
  AssistantMessage={AssistantMessage}
503
717
  UserMessage={UserMessage}
504
718
  RenderMessage={RenderMessage}
505
- messages={visibleMessages}
719
+ messages={messages}
506
720
  inProgress={isLoading}
507
721
  onRegenerate={handleRegenerate}
508
722
  onCopy={handleCopy}
509
- onThumbsUp={onThumbsUp}
510
- onThumbsDown={onThumbsDown}
723
+ onThumbsUp={handleThumbsUp}
724
+ onThumbsDown={handleThumbsDown}
511
725
  markdownTagRenderers={markdownTagRenderers}
512
726
  ImageRenderer={ImageRenderer}
727
+ // Legacy props - passed through to Messages component
728
+ RenderTextMessage={RenderTextMessage}
729
+ RenderActionExecutionMessage={RenderActionExecutionMessage}
730
+ RenderAgentStateMessage={RenderAgentStateMessage}
731
+ RenderResultMessage={RenderResultMessage}
732
+ RenderImageMessage={RenderImageMessage}
513
733
  >
514
734
  {currentSuggestions.length > 0 && (
515
735
  <RenderSuggestionsList
@@ -575,8 +795,8 @@ export const useCopilotChatLogic = (
575
795
  onReloadMessages?: OnReloadMessages,
576
796
  ) => {
577
797
  const {
578
- visibleMessages,
579
- appendMessage,
798
+ messages,
799
+ sendMessage,
580
800
  setMessages,
581
801
  reloadMessages: defaultReloadMessages,
582
802
  stopGeneration: defaultStopGeneration,
@@ -640,14 +860,14 @@ export const useCopilotChatLogic = (
640
860
  }
641
861
 
642
862
  // Generate initial suggestions when chat is empty
643
- if (visibleMessages.length === 0 && !hasGeneratedInitialSuggestions.current) {
863
+ if (messages.length === 0 && !hasGeneratedInitialSuggestions.current) {
644
864
  hasGeneratedInitialSuggestions.current = true;
645
865
  generateSuggestionsWithErrorHandling("initial");
646
866
  return;
647
867
  }
648
868
 
649
869
  // Generate post-message suggestions after assistant responds
650
- if (visibleMessages.length > 0 && suggestions.length === 0) {
870
+ if (messages.length > 0 && suggestions.length === 0) {
651
871
  generateSuggestionsWithErrorHandling("post-message");
652
872
  return;
653
873
  }
@@ -655,7 +875,7 @@ export const useCopilotChatLogic = (
655
875
  chatSuggestions,
656
876
  isLoadingSuggestions,
657
877
  suggestionsFailed,
658
- visibleMessages.length,
878
+ messages.length,
659
879
  isLoading,
660
880
  suggestions.length,
661
881
  Object.keys(generalContext.chatSuggestionConfiguration).join(","), // Use stable string instead of object reference
@@ -695,7 +915,7 @@ export const useCopilotChatLogic = (
695
915
  onInProgress?.(isLoading);
696
916
  }, [onInProgress, isLoading]);
697
917
 
698
- const sendMessage = async (
918
+ const safelySendMessage = async (
699
919
  messageContent: string,
700
920
  imagesToUse?: Array<{ contentType: string; bytes: string }>,
701
921
  ) => {
@@ -727,7 +947,7 @@ export const useCopilotChatLogic = (
727
947
  }
728
948
 
729
949
  // Send the message and clear suggestions for auto/manual modes
730
- await appendMessage(textMessage, {
950
+ await sendMessage(textMessage, {
731
951
  followUp: images.length === 0,
732
952
  clearSuggestions: chatSuggestions === "auto" || chatSuggestions === "manual",
733
953
  });
@@ -748,7 +968,7 @@ export const useCopilotChatLogic = (
748
968
  bytes: images[i].bytes,
749
969
  },
750
970
  } as unknown as Message;
751
- await appendMessage(imageMessage, { followUp: i === images.length - 1 });
971
+ await sendMessage(imageMessage, { followUp: i === images.length - 1 });
752
972
  if (!firstMessage) {
753
973
  firstMessage = imageMessage;
754
974
  }
@@ -765,7 +985,6 @@ export const useCopilotChatLogic = (
765
985
  return firstMessage;
766
986
  };
767
987
 
768
- const messages = visibleMessages;
769
988
  const currentAgentName = generalContext.agentSession?.agentName;
770
989
  const restartCurrentAgent = async (hint?: HintFunction) => {
771
990
  if (generalContext.agentSession) {
@@ -792,9 +1011,9 @@ export const useCopilotChatLogic = (
792
1011
  await runAgent(
793
1012
  generalContext.agentSession.agentName,
794
1013
  stableContext,
795
- appendMessage,
1014
+ messagesContext.messages,
1015
+ sendMessage,
796
1016
  runChatCompletion,
797
- hint,
798
1017
  );
799
1018
  }
800
1019
  };
@@ -855,10 +1074,9 @@ export const useCopilotChatLogic = (
855
1074
 
856
1075
  return {
857
1076
  messages,
858
- visibleMessages,
859
1077
  isLoading,
860
1078
  suggestions,
861
- sendMessage,
1079
+ sendMessage: safelySendMessage,
862
1080
  stopGeneration,
863
1081
  reloadMessages,
864
1082
  resetSuggestions,
@@ -1,8 +1,9 @@
1
1
  import { useEffect, useMemo, useRef } from "react";
2
2
  import { MessagesProps } from "./props";
3
3
  import { useChatContext } from "./ChatContext";
4
- import { Message, Role } from "@copilotkit/shared";
5
- import { useCopilotChat } from "@copilotkit/react-core";
4
+ import { Message } from "@copilotkit/shared";
5
+ import { useCopilotChatInternal as useCopilotChat } from "@copilotkit/react-core";
6
+ import { LegacyRenderMessage, LegacyRenderProps } from "./messages/LegacyRenderMessage";
6
7
 
7
8
  export const Messages = ({
8
9
  inProgress,
@@ -10,25 +11,76 @@ export const Messages = ({
10
11
  RenderMessage,
11
12
  AssistantMessage,
12
13
  UserMessage,
14
+ ImageRenderer,
13
15
  onRegenerate,
14
16
  onCopy,
15
17
  onThumbsUp,
16
18
  onThumbsDown,
17
19
  markdownTagRenderers,
20
+
21
+ // Legacy props
22
+ RenderTextMessage,
23
+ RenderActionExecutionMessage,
24
+ RenderAgentStateMessage,
25
+ RenderResultMessage,
26
+ RenderImageMessage,
18
27
  }: MessagesProps) => {
19
28
  const { labels } = useChatContext();
20
- const { visibleMessages, interrupt } = useCopilotChat();
29
+ const { messages: visibleMessages, interrupt } = useCopilotChat();
21
30
  const initialMessages = useMemo(() => makeInitialMessages(labels.initial), [labels.initial]);
22
31
  const messages = [...initialMessages, ...visibleMessages];
23
32
  const { messagesContainerRef, messagesEndRef } = useScrollToBottom(messages);
24
33
 
34
+ // Check if any legacy props are provided
35
+ const hasLegacyProps = !!(
36
+ RenderTextMessage ||
37
+ RenderActionExecutionMessage ||
38
+ RenderAgentStateMessage ||
39
+ RenderResultMessage ||
40
+ RenderImageMessage
41
+ );
42
+
43
+ // Show deprecation warning if legacy props are used
44
+ useEffect(() => {
45
+ if (hasLegacyProps) {
46
+ console.warn(
47
+ "[CopilotKit] Legacy message render props (RenderTextMessage, RenderActionExecutionMessage, etc.) are deprecated. " +
48
+ "Please use the unified 'RenderMessage' prop instead. " +
49
+ "See migration guide: https://docs.copilotkit.ai/migration/render-message",
50
+ );
51
+ }
52
+ }, [hasLegacyProps]);
53
+
54
+ // Create legacy props object for the adapter
55
+ const legacyProps: LegacyRenderProps = useMemo(
56
+ () => ({
57
+ RenderTextMessage,
58
+ RenderActionExecutionMessage,
59
+ RenderAgentStateMessage,
60
+ RenderResultMessage,
61
+ RenderImageMessage,
62
+ }),
63
+ [
64
+ RenderTextMessage,
65
+ RenderActionExecutionMessage,
66
+ RenderAgentStateMessage,
67
+ RenderResultMessage,
68
+ RenderImageMessage,
69
+ ],
70
+ );
71
+
72
+ // Determine which render component to use
73
+ const MessageRenderer = hasLegacyProps
74
+ ? (props: any) => <LegacyRenderMessage {...props} legacyProps={legacyProps} />
75
+ : RenderMessage;
76
+
25
77
  return (
26
78
  <div className="copilotKitMessages" ref={messagesContainerRef}>
27
79
  <div className="copilotKitMessagesContainer">
28
80
  {messages.map((message, index) => {
29
81
  const isCurrentMessage = index === messages.length - 1;
30
82
  return (
31
- <RenderMessage
83
+ <MessageRenderer
32
84
  key={index}
33
85
  message={message}
34
86
  inProgress={inProgress}
@@ -36,6 +88,7 @@ export const Messages = ({
36
88
  isCurrentMessage={isCurrentMessage}
37
89
  AssistantMessage={AssistantMessage}
38
90
  UserMessage={UserMessage}
91
+ ImageRenderer={ImageRenderer}
39
92
  onRegenerate={onRegenerate}
40
93
  onCopy={onCopy}
41
94
  onThumbsUp={onThumbsUp}
@@ -69,7 +122,7 @@ function makeInitialMessages(initial: string | string[] | undefined): Message[]
69
122
  return [
70
123
  {
71
124
  id: initial,
72
- role: "system",
125
+ role: "assistant",
73
126
  content: initial,
74
127
  },
75
128
  ];