@copilotkit/react-ui 1.10.0-next.8 → 1.10.0

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 (62) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/dist/{chunk-U5ATIGWH.mjs → chunk-BJHJBS5M.mjs} +45 -5
  3. package/dist/chunk-BJHJBS5M.mjs.map +1 -0
  4. package/dist/{chunk-KLV4ERV6.mjs → chunk-GBP47ONN.mjs} +2 -2
  5. package/dist/{chunk-3DVMCBME.mjs → chunk-GJ4SX4JE.mjs} +97 -35
  6. package/dist/chunk-GJ4SX4JE.mjs.map +1 -0
  7. package/dist/{chunk-APLX7E54.mjs → chunk-J5ZZR6YB.mjs} +2 -2
  8. package/dist/chunk-MIVUCSGO.mjs +126 -0
  9. package/dist/chunk-MIVUCSGO.mjs.map +1 -0
  10. package/dist/{chunk-JHUTTP5C.mjs → chunk-T5QU6KSB.mjs} +5 -1
  11. package/dist/chunk-T5QU6KSB.mjs.map +1 -0
  12. package/dist/{chunk-BPU3FDT4.mjs → chunk-Y44VLEUH.mjs} +30 -11
  13. package/dist/chunk-Y44VLEUH.mjs.map +1 -0
  14. package/dist/components/chat/Chat.d.ts +32 -2
  15. package/dist/components/chat/Chat.js +1084 -865
  16. package/dist/components/chat/Chat.js.map +1 -1
  17. package/dist/components/chat/Chat.mjs +7 -6
  18. package/dist/components/chat/Messages.d.ts +1 -1
  19. package/dist/components/chat/Messages.js +984 -23
  20. package/dist/components/chat/Messages.js.map +1 -1
  21. package/dist/components/chat/Messages.mjs +9 -1
  22. package/dist/components/chat/Modal.js +1107 -875
  23. package/dist/components/chat/Modal.js.map +1 -1
  24. package/dist/components/chat/Modal.mjs +8 -7
  25. package/dist/components/chat/Popup.js +1109 -877
  26. package/dist/components/chat/Popup.js.map +1 -1
  27. package/dist/components/chat/Popup.mjs +9 -8
  28. package/dist/components/chat/Sidebar.js +1109 -877
  29. package/dist/components/chat/Sidebar.js.map +1 -1
  30. package/dist/components/chat/Sidebar.mjs +9 -8
  31. package/dist/components/chat/index.js +1111 -879
  32. package/dist/components/chat/index.js.map +1 -1
  33. package/dist/components/chat/index.mjs +16 -15
  34. package/dist/components/chat/messages/LegacyRenderMessage.d.ts +28 -0
  35. package/dist/components/chat/messages/LegacyRenderMessage.js +980 -0
  36. package/dist/components/chat/messages/LegacyRenderMessage.js.map +1 -0
  37. package/dist/components/chat/messages/LegacyRenderMessage.mjs +17 -0
  38. package/dist/components/chat/messages/LegacyRenderMessage.mjs.map +1 -0
  39. package/dist/components/chat/messages/RenderMessage.js +4 -0
  40. package/dist/components/chat/messages/RenderMessage.js.map +1 -1
  41. package/dist/components/chat/messages/RenderMessage.mjs +1 -1
  42. package/dist/components/chat/props.d.ts +55 -1
  43. package/dist/components/chat/props.js.map +1 -1
  44. package/dist/components/index.js +1111 -879
  45. package/dist/components/index.js.map +1 -1
  46. package/dist/components/index.mjs +16 -15
  47. package/dist/index.js +1113 -881
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs +16 -15
  50. package/package.json +4 -4
  51. package/src/components/chat/Chat.tsx +144 -21
  52. package/src/components/chat/Messages.tsx +56 -3
  53. package/src/components/chat/Modal.tsx +24 -3
  54. package/src/components/chat/messages/LegacyRenderMessage.tsx +143 -0
  55. package/src/components/chat/messages/RenderMessage.tsx +3 -0
  56. package/src/components/chat/props.ts +64 -1
  57. package/dist/chunk-3DVMCBME.mjs.map +0 -1
  58. package/dist/chunk-BPU3FDT4.mjs.map +0 -1
  59. package/dist/chunk-JHUTTP5C.mjs.map +0 -1
  60. package/dist/chunk-U5ATIGWH.mjs.map +0 -1
  61. /package/dist/{chunk-KLV4ERV6.mjs.map → chunk-GBP47ONN.mjs.map} +0 -0
  62. /package/dist/{chunk-APLX7E54.mjs.map → chunk-J5ZZR6YB.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -4,12 +4,12 @@ import "./chunk-MMVDU6DF.mjs";
4
4
  import "./chunk-SC6JRFAJ.mjs";
5
5
  import {
6
6
  CopilotSidebar
7
- } from "./chunk-KLV4ERV6.mjs";
7
+ } from "./chunk-GBP47ONN.mjs";
8
8
  import "./chunk-WB3YULQ4.mjs";
9
9
  import {
10
10
  CopilotPopup
11
- } from "./chunk-APLX7E54.mjs";
12
- import "./chunk-BPU3FDT4.mjs";
11
+ } from "./chunk-J5ZZR6YB.mjs";
12
+ import "./chunk-Y44VLEUH.mjs";
13
13
  import "./chunk-C3GSYRC3.mjs";
14
14
  import "./chunk-GDSZGYCE.mjs";
15
15
  import "./chunk-V7W6IM2V.mjs";
@@ -26,17 +26,7 @@ import "./chunk-BH6PCAAL.mjs";
26
26
  import "./chunk-UFN2VWSR.mjs";
27
27
  import {
28
28
  CopilotChat
29
- } from "./chunk-3DVMCBME.mjs";
30
- import "./chunk-JHUTTP5C.mjs";
31
- import {
32
- AssistantMessage
33
- } from "./chunk-GCKKSSBU.mjs";
34
- import {
35
- ImageRenderer
36
- } from "./chunk-DBKRAOH7.mjs";
37
- import {
38
- UserMessage
39
- } from "./chunk-VVL6JFCJ.mjs";
29
+ } from "./chunk-GJ4SX4JE.mjs";
40
30
  import {
41
31
  Suggestions
42
32
  } from "./chunk-226ZMOE3.mjs";
@@ -47,10 +37,21 @@ 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-U5ATIGWH.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.8",
12
+ "version": "1.10.0",
13
13
  "sideEffects": [
14
14
  "**/*.css"
15
15
  ],
@@ -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.8",
55
- "@copilotkit/runtime-client-gql": "1.10.0-next.8",
56
- "@copilotkit/shared": "1.10.0-next.8"
54
+ "@copilotkit/react-core": "1.10.0",
55
+ "@copilotkit/runtime-client-gql": "1.10.0",
56
+ "@copilotkit/shared": "1.10.0"
57
57
  },
58
58
  "keywords": [
59
59
  "copilotkit",
@@ -85,6 +85,7 @@ import type { SuggestionItem } from "@copilotkit/react-core";
85
85
  import {
86
86
  CopilotKitError,
87
87
  CopilotKitErrorCode,
88
+ CopilotErrorEvent,
88
89
  Message,
89
90
  Severity,
90
91
  ErrorVisibility,
@@ -239,6 +240,31 @@ export interface CopilotChatProps {
239
240
  */
240
241
  Messages?: React.ComponentType<MessagesProps>;
241
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
+
242
268
  /**
243
269
  * A custom RenderMessage component to use instead of the default.
244
270
  *
@@ -281,6 +307,18 @@ export interface CopilotChatProps {
281
307
  * These hooks only work when publicApiKey is provided.
282
308
  */
283
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;
284
322
  }
285
323
 
286
324
  interface OnStopGenerationArguments {
@@ -368,19 +406,35 @@ export function CopilotChat({
368
406
  inputFileAccept = "image/*",
369
407
  hideStopButton,
370
408
  observabilityHooks,
409
+ renderError,
410
+
411
+ // Legacy props - deprecated
412
+ RenderTextMessage,
413
+ RenderActionExecutionMessage,
414
+ RenderAgentStateMessage,
415
+ RenderResultMessage,
416
+ RenderImageMessage,
371
417
  }: CopilotChatProps) {
372
418
  const { additionalInstructions, setChatInstructions, copilotApiConfig, setBannerError } =
373
419
  useCopilotContext();
420
+
421
+ // Destructure stable values to avoid object reference changes
422
+ const { publicApiKey, chatApiEndpoint } = copilotApiConfig;
374
423
  const [selectedImages, setSelectedImages] = useState<Array<ImageUpload>>([]);
424
+ const [chatError, setChatError] = useState<{
425
+ message: string;
426
+ operation?: string;
427
+ timestamp: number;
428
+ } | null>(null);
375
429
  const fileInputRef = useRef<HTMLInputElement>(null);
376
430
 
377
431
  // Helper function to trigger event hooks only if publicApiKey is provided
378
432
  const triggerObservabilityHook = useCallback(
379
433
  (hookName: keyof CopilotObservabilityHooks, ...args: any[]) => {
380
- if (copilotApiConfig.publicApiKey && observabilityHooks?.[hookName]) {
434
+ if (publicApiKey && observabilityHooks?.[hookName]) {
381
435
  (observabilityHooks[hookName] as any)(...args);
382
436
  }
383
- if (observabilityHooks?.[hookName] && !copilotApiConfig.publicApiKey) {
437
+ if (observabilityHooks?.[hookName] && !publicApiKey) {
384
438
  setBannerError(
385
439
  new CopilotKitError({
386
440
  message: "observabilityHooks requires a publicApiKey to function.",
@@ -392,7 +446,58 @@ export function CopilotChat({
392
446
  styledConsole.publicApiKeyRequired("observabilityHooks");
393
447
  }
394
448
  },
395
- [copilotApiConfig.publicApiKey, observabilityHooks],
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],
396
501
  );
397
502
 
398
503
  // Clipboard paste handler
@@ -436,14 +541,15 @@ export function CopilotChat({
436
541
  const loadedImages = (await Promise.all(imagePromises)).filter((img) => img !== null);
437
542
  setSelectedImages((prev) => [...prev, ...loadedImages]);
438
543
  } catch (error) {
439
- // TODO: Show an error message to the user
544
+ // Trigger chat-level error handler
545
+ triggerChatError(error, "processClipboardImages", error);
440
546
  console.error("Error processing pasted images:", error);
441
547
  }
442
548
  };
443
549
 
444
550
  document.addEventListener("paste", handlePaste);
445
551
  return () => document.removeEventListener("paste", handlePaste);
446
- }, [imageUploadsEnabled]);
552
+ }, [imageUploadsEnabled, triggerChatError]);
447
553
 
448
554
  useEffect(() => {
449
555
  if (!additionalInstructions?.length) {
@@ -469,7 +575,7 @@ export function CopilotChat({
469
575
  }, [instructions, additionalInstructions]);
470
576
 
471
577
  const {
472
- visibleMessages,
578
+ messages,
473
579
  isLoading,
474
580
  sendMessage,
475
581
  stopGeneration,
@@ -563,7 +669,8 @@ export function CopilotChat({
563
669
  const loadedImages = await Promise.all(fileReadPromises);
564
670
  setSelectedImages((prev) => [...prev, ...loadedImages]);
565
671
  } catch (error) {
566
- // TODO: Show an error message to the user
672
+ // Trigger chat-level error handler
673
+ triggerChatError(error, "processUploadedImages", error);
567
674
  console.error("Error reading files:", error);
568
675
  }
569
676
  };
@@ -592,11 +699,24 @@ export function CopilotChat({
592
699
 
593
700
  return (
594
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
+
595
715
  <Messages
596
716
  AssistantMessage={AssistantMessage}
597
717
  UserMessage={UserMessage}
598
718
  RenderMessage={RenderMessage}
599
- messages={visibleMessages}
719
+ messages={messages}
600
720
  inProgress={isLoading}
601
721
  onRegenerate={handleRegenerate}
602
722
  onCopy={handleCopy}
@@ -604,6 +724,12 @@ export function CopilotChat({
604
724
  onThumbsDown={handleThumbsDown}
605
725
  markdownTagRenderers={markdownTagRenderers}
606
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}
607
733
  >
608
734
  {currentSuggestions.length > 0 && (
609
735
  <RenderSuggestionsList
@@ -669,8 +795,8 @@ export const useCopilotChatLogic = (
669
795
  onReloadMessages?: OnReloadMessages,
670
796
  ) => {
671
797
  const {
672
- visibleMessages,
673
- appendMessage,
798
+ messages,
799
+ sendMessage,
674
800
  setMessages,
675
801
  reloadMessages: defaultReloadMessages,
676
802
  stopGeneration: defaultStopGeneration,
@@ -734,14 +860,14 @@ export const useCopilotChatLogic = (
734
860
  }
735
861
 
736
862
  // Generate initial suggestions when chat is empty
737
- if (visibleMessages.length === 0 && !hasGeneratedInitialSuggestions.current) {
863
+ if (messages.length === 0 && !hasGeneratedInitialSuggestions.current) {
738
864
  hasGeneratedInitialSuggestions.current = true;
739
865
  generateSuggestionsWithErrorHandling("initial");
740
866
  return;
741
867
  }
742
868
 
743
869
  // Generate post-message suggestions after assistant responds
744
- if (visibleMessages.length > 0 && suggestions.length === 0) {
870
+ if (messages.length > 0 && suggestions.length === 0) {
745
871
  generateSuggestionsWithErrorHandling("post-message");
746
872
  return;
747
873
  }
@@ -749,7 +875,7 @@ export const useCopilotChatLogic = (
749
875
  chatSuggestions,
750
876
  isLoadingSuggestions,
751
877
  suggestionsFailed,
752
- visibleMessages.length,
878
+ messages.length,
753
879
  isLoading,
754
880
  suggestions.length,
755
881
  Object.keys(generalContext.chatSuggestionConfiguration).join(","), // Use stable string instead of object reference
@@ -789,7 +915,7 @@ export const useCopilotChatLogic = (
789
915
  onInProgress?.(isLoading);
790
916
  }, [onInProgress, isLoading]);
791
917
 
792
- const sendMessage = async (
918
+ const safelySendMessage = async (
793
919
  messageContent: string,
794
920
  imagesToUse?: Array<{ contentType: string; bytes: string }>,
795
921
  ) => {
@@ -821,7 +947,7 @@ export const useCopilotChatLogic = (
821
947
  }
822
948
 
823
949
  // Send the message and clear suggestions for auto/manual modes
824
- await appendMessage(textMessage, {
950
+ await sendMessage(textMessage, {
825
951
  followUp: images.length === 0,
826
952
  clearSuggestions: chatSuggestions === "auto" || chatSuggestions === "manual",
827
953
  });
@@ -842,7 +968,7 @@ export const useCopilotChatLogic = (
842
968
  bytes: images[i].bytes,
843
969
  },
844
970
  } as unknown as Message;
845
- await appendMessage(imageMessage, { followUp: i === images.length - 1 });
971
+ await sendMessage(imageMessage, { followUp: i === images.length - 1 });
846
972
  if (!firstMessage) {
847
973
  firstMessage = imageMessage;
848
974
  }
@@ -859,7 +985,6 @@ export const useCopilotChatLogic = (
859
985
  return firstMessage;
860
986
  };
861
987
 
862
- const messages = visibleMessages;
863
988
  const currentAgentName = generalContext.agentSession?.agentName;
864
989
  const restartCurrentAgent = async (hint?: HintFunction) => {
865
990
  if (generalContext.agentSession) {
@@ -887,9 +1012,8 @@ export const useCopilotChatLogic = (
887
1012
  generalContext.agentSession.agentName,
888
1013
  stableContext,
889
1014
  messagesContext.messages,
890
- appendMessage,
1015
+ sendMessage,
891
1016
  runChatCompletion,
892
- hint,
893
1017
  );
894
1018
  }
895
1019
  };
@@ -950,10 +1074,9 @@ export const useCopilotChatLogic = (
950
1074
 
951
1075
  return {
952
1076
  messages,
953
- visibleMessages,
954
1077
  isLoading,
955
1078
  suggestions,
956
- sendMessage,
1079
+ sendMessage: safelySendMessage,
957
1080
  stopGeneration,
958
1081
  reloadMessages,
959
1082
  resetSuggestions,
@@ -3,6 +3,7 @@ import { MessagesProps } from "./props";
3
3
  import { useChatContext } from "./ChatContext";
4
4
  import { Message } from "@copilotkit/shared";
5
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
  ];
@@ -10,6 +10,13 @@ import { CopilotChat, CopilotChatProps } from "./Chat";
10
10
  import { AssistantMessage as DefaultAssistantMessage } from "./messages/AssistantMessage";
11
11
  import { UserMessage as DefaultUserMessage } from "./messages/UserMessage";
12
12
  import { useCopilotContext } from "@copilotkit/react-core";
13
+ import {
14
+ CopilotKitError,
15
+ CopilotKitErrorCode,
16
+ Severity,
17
+ ErrorVisibility,
18
+ styledConsole,
19
+ } from "@copilotkit/shared";
13
20
 
14
21
  export interface CopilotModalProps extends CopilotChatProps {
15
22
  /**
@@ -79,16 +86,30 @@ const CopilotModalInner = ({
79
86
  hitEscapeToClose: boolean;
80
87
  shortcut: string;
81
88
  }) => {
82
- const { copilotApiConfig } = useCopilotContext();
89
+ const { copilotApiConfig, setBannerError } = useCopilotContext();
90
+
91
+ // Destructure stable values to avoid object reference changes
92
+ const { publicApiKey } = copilotApiConfig;
83
93
 
84
94
  // Helper function to trigger event hooks only if publicApiKey is provided
85
95
  const triggerObservabilityHook = useCallback(
86
96
  (hookName: keyof CopilotObservabilityHooks, ...args: any[]) => {
87
- if (copilotApiConfig.publicApiKey && observabilityHooks?.[hookName]) {
97
+ if (publicApiKey && observabilityHooks?.[hookName]) {
88
98
  (observabilityHooks[hookName] as any)(...args);
89
99
  }
100
+ if (observabilityHooks?.[hookName] && !publicApiKey) {
101
+ setBannerError(
102
+ new CopilotKitError({
103
+ message: "observabilityHooks requires a publicApiKey to function.",
104
+ code: CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
105
+ severity: Severity.CRITICAL,
106
+ visibility: ErrorVisibility.BANNER,
107
+ }),
108
+ );
109
+ styledConsole.publicApiKeyRequired("observabilityHooks");
110
+ }
90
111
  },
91
- [copilotApiConfig.publicApiKey, observabilityHooks],
112
+ [publicApiKey, observabilityHooks, setBannerError],
92
113
  );
93
114
 
94
115
  const { open } = useChatContext();
@@ -0,0 +1,143 @@
1
+ import React from "react";
2
+ import { RenderMessageProps } from "../props";
3
+ import { RenderMessage as DefaultRenderMessage } from "./RenderMessage";
4
+ import { aguiToGQL } from "@copilotkit/runtime-client-gql";
5
+
6
+ /**
7
+ * Legacy message render props interface for backwards compatibility
8
+ */
9
+ export interface LegacyRenderProps {
10
+ RenderTextMessage?: React.ComponentType<RenderMessageProps>;
11
+ RenderActionExecutionMessage?: React.ComponentType<RenderMessageProps>;
12
+ RenderAgentStateMessage?: React.ComponentType<RenderMessageProps>;
13
+ RenderResultMessage?: React.ComponentType<RenderMessageProps>;
14
+ RenderImageMessage?: React.ComponentType<RenderMessageProps>;
15
+ }
16
+
17
+ /**
18
+ * Props for the LegacyRenderMessage component
19
+ */
20
+ export interface LegacyRenderMessageProps extends RenderMessageProps {
21
+ legacyProps: LegacyRenderProps;
22
+ }
23
+
24
+ /**
25
+ * Legacy message adapter component that maps old render props to new message types.
26
+ * This component provides backwards compatibility for the deprecated render props.
27
+ */
28
+ export const LegacyRenderMessage: React.FC<LegacyRenderMessageProps> = ({
29
+ message,
30
+ inProgress,
31
+ index,
32
+ isCurrentMessage,
33
+ actionResult,
34
+ AssistantMessage,
35
+ UserMessage,
36
+ ImageRenderer,
37
+ onRegenerate,
38
+ onCopy,
39
+ onThumbsUp,
40
+ onThumbsDown,
41
+ markdownTagRenderers,
42
+ legacyProps,
43
+ }) => {
44
+ const {
45
+ RenderTextMessage,
46
+ RenderActionExecutionMessage,
47
+ RenderAgentStateMessage,
48
+ RenderResultMessage,
49
+ RenderImageMessage,
50
+ } = legacyProps;
51
+
52
+ const deprecatedMessage = aguiToGQL(message)[0] ?? undefined;
53
+
54
+ // Route to appropriate legacy renderer based on message type
55
+ if (deprecatedMessage.isTextMessage() && RenderTextMessage) {
56
+ return (
57
+ <RenderTextMessage
58
+ message={message}
59
+ inProgress={inProgress}
60
+ index={index}
61
+ isCurrentMessage={isCurrentMessage}
62
+ AssistantMessage={AssistantMessage}
63
+ UserMessage={UserMessage}
64
+ onRegenerate={onRegenerate}
65
+ onCopy={onCopy}
66
+ onThumbsUp={onThumbsUp}
67
+ onThumbsDown={onThumbsDown}
68
+ markdownTagRenderers={markdownTagRenderers}
69
+ />
70
+ );
71
+ }
72
+
73
+ if (deprecatedMessage.isActionExecutionMessage() && RenderActionExecutionMessage) {
74
+ return (
75
+ <RenderActionExecutionMessage
76
+ message={message}
77
+ inProgress={inProgress}
78
+ index={index}
79
+ isCurrentMessage={isCurrentMessage}
80
+ actionResult={actionResult}
81
+ AssistantMessage={AssistantMessage}
82
+ UserMessage={UserMessage}
83
+ />
84
+ );
85
+ }
86
+
87
+ if (deprecatedMessage.isAgentStateMessage() && RenderAgentStateMessage) {
88
+ return (
89
+ <RenderAgentStateMessage
90
+ message={message}
91
+ inProgress={inProgress}
92
+ index={index}
93
+ isCurrentMessage={isCurrentMessage}
94
+ AssistantMessage={AssistantMessage}
95
+ UserMessage={UserMessage}
96
+ />
97
+ );
98
+ }
99
+
100
+ if (deprecatedMessage.isResultMessage() && RenderResultMessage) {
101
+ return (
102
+ <RenderResultMessage
103
+ message={message}
104
+ inProgress={inProgress}
105
+ index={index}
106
+ isCurrentMessage={isCurrentMessage}
107
+ AssistantMessage={AssistantMessage}
108
+ UserMessage={UserMessage}
109
+ />
110
+ );
111
+ }
112
+
113
+ if (deprecatedMessage.isImageMessage() && RenderImageMessage) {
114
+ return (
115
+ <RenderImageMessage
116
+ message={message}
117
+ inProgress={inProgress}
118
+ index={index}
119
+ isCurrentMessage={isCurrentMessage}
120
+ AssistantMessage={AssistantMessage}
121
+ UserMessage={UserMessage}
122
+ />
123
+ );
124
+ }
125
+
126
+ // Fallback to default RenderMessage for any unhandled cases
127
+ return (
128
+ <DefaultRenderMessage
129
+ message={message}
130
+ inProgress={inProgress}
131
+ index={index}
132
+ isCurrentMessage={isCurrentMessage}
133
+ AssistantMessage={AssistantMessage}
134
+ UserMessage={UserMessage}
135
+ ImageRenderer={ImageRenderer}
136
+ onRegenerate={onRegenerate}
137
+ onCopy={onCopy}
138
+ onThumbsUp={onThumbsUp}
139
+ onThumbsDown={onThumbsDown}
140
+ markdownTagRenderers={markdownTagRenderers}
141
+ />
142
+ );
143
+ };