@copilotkit/react-ui 1.9.3 → 1.10.0-next.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 (178) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/{chunk-KENCH7RN.mjs → chunk-B5IFB5YJ.mjs} +1 -1
  3. package/dist/chunk-B5IFB5YJ.mjs.map +1 -0
  4. package/dist/chunk-DBKRAOH7.mjs +34 -0
  5. package/dist/chunk-DBKRAOH7.mjs.map +1 -0
  6. package/dist/{chunk-4HUXYD3B.mjs → chunk-DTRPPNSA.mjs} +2 -2
  7. package/dist/{chunk-YTXEWDNC.mjs → chunk-E6MQUIZW.mjs} +15 -4
  8. package/dist/chunk-E6MQUIZW.mjs.map +1 -0
  9. package/dist/{chunk-L3GZ7TXC.mjs → chunk-GCKKSSBU.mjs} +21 -24
  10. package/dist/chunk-GCKKSSBU.mjs.map +1 -0
  11. package/dist/{chunk-KN2GCKBE.mjs → chunk-GJ3MFNBX.mjs} +6 -6
  12. package/dist/{chunk-32MUWKL3.mjs → chunk-JHUTTP5C.mjs} +21 -17
  13. package/dist/chunk-JHUTTP5C.mjs.map +1 -0
  14. package/dist/{chunk-HKTWKCPS.mjs → chunk-LXCD3K7B.mjs} +127 -92
  15. package/dist/chunk-LXCD3K7B.mjs.map +1 -0
  16. package/dist/{chunk-S5MBUNGN.mjs → chunk-O72ZB5V3.mjs} +4 -4
  17. package/dist/chunk-O72ZB5V3.mjs.map +1 -0
  18. package/dist/{chunk-QGSPTXOV.mjs → chunk-O7KTFUAN.mjs} +2 -2
  19. package/dist/chunk-O7KTFUAN.mjs.map +1 -0
  20. package/dist/chunk-Q2467VHZ.mjs +30 -0
  21. package/dist/chunk-Q2467VHZ.mjs.map +1 -0
  22. package/dist/{chunk-H3EM63WS.mjs → chunk-VLNT34X3.mjs} +2 -2
  23. package/dist/chunk-VVL6JFCJ.mjs +16 -0
  24. package/dist/chunk-VVL6JFCJ.mjs.map +1 -0
  25. package/dist/chunk-WHDNKXMP.mjs +135 -0
  26. package/dist/chunk-WHDNKXMP.mjs.map +1 -0
  27. package/dist/{chunk-ALIBUJML.mjs → chunk-WPVTPQ7X.mjs} +2 -2
  28. package/dist/components/chat/Button.d.ts +1 -1
  29. package/dist/components/chat/Chat.d.ts +119 -28
  30. package/dist/components/chat/Chat.js +298 -658
  31. package/dist/components/chat/Chat.js.map +1 -1
  32. package/dist/components/chat/Chat.mjs +12 -15
  33. package/dist/components/chat/CodeBlock.js.map +1 -1
  34. package/dist/components/chat/CodeBlock.mjs +1 -1
  35. package/dist/components/chat/Header.d.ts +1 -1
  36. package/dist/components/chat/Input.d.ts +1 -1
  37. package/dist/components/chat/Input.js +3 -3
  38. package/dist/components/chat/Input.js.map +1 -1
  39. package/dist/components/chat/Input.mjs +2 -2
  40. package/dist/components/chat/Markdown.js +13 -2
  41. package/dist/components/chat/Markdown.js.map +1 -1
  42. package/dist/components/chat/Markdown.mjs +2 -2
  43. package/dist/components/chat/Messages.d.ts +3 -3
  44. package/dist/components/chat/Messages.js +40 -116
  45. package/dist/components/chat/Messages.js.map +1 -1
  46. package/dist/components/chat/Messages.mjs +1 -1
  47. package/dist/components/chat/Modal.d.ts +7 -2
  48. package/dist/components/chat/Modal.js +308 -668
  49. package/dist/components/chat/Modal.js.map +1 -1
  50. package/dist/components/chat/Modal.mjs +13 -16
  51. package/dist/components/chat/Popup.d.ts +7 -2
  52. package/dist/components/chat/Popup.js +310 -670
  53. package/dist/components/chat/Popup.js.map +1 -1
  54. package/dist/components/chat/Popup.mjs +14 -17
  55. package/dist/components/chat/Sidebar.d.ts +7 -2
  56. package/dist/components/chat/Sidebar.js +312 -672
  57. package/dist/components/chat/Sidebar.js.map +1 -1
  58. package/dist/components/chat/Sidebar.mjs +14 -17
  59. package/dist/components/chat/Suggestion.d.ts +2 -9
  60. package/dist/components/chat/Suggestion.js +6 -96
  61. package/dist/components/chat/Suggestion.js.map +1 -1
  62. package/dist/components/chat/Suggestion.mjs +3 -5
  63. package/dist/components/chat/Suggestions.d.ts +1 -1
  64. package/dist/components/chat/Suggestions.js +4 -3
  65. package/dist/components/chat/Suggestions.js.map +1 -1
  66. package/dist/components/chat/Suggestions.mjs +2 -2
  67. package/dist/components/chat/Window.d.ts +1 -1
  68. package/dist/components/chat/index.d.ts +8 -3
  69. package/dist/components/chat/index.js +316 -676
  70. package/dist/components/chat/index.js.map +1 -1
  71. package/dist/components/chat/index.mjs +18 -21
  72. package/dist/components/chat/messages/AssistantMessage.d.ts +1 -1
  73. package/dist/components/chat/messages/AssistantMessage.js +32 -24
  74. package/dist/components/chat/messages/AssistantMessage.js.map +1 -1
  75. package/dist/components/chat/messages/AssistantMessage.mjs +3 -3
  76. package/dist/components/chat/messages/ImageRenderer.d.ts +12 -0
  77. package/dist/components/chat/messages/ImageRenderer.js +58 -0
  78. package/dist/components/chat/messages/ImageRenderer.js.map +1 -0
  79. package/dist/components/chat/messages/ImageRenderer.mjs +8 -0
  80. package/dist/components/chat/messages/RenderMessage.d.ts +9 -0
  81. package/dist/components/chat/messages/{RenderTextMessage.js → RenderMessage.js} +92 -47
  82. package/dist/components/chat/messages/RenderMessage.js.map +1 -0
  83. package/dist/components/chat/messages/RenderMessage.mjs +16 -0
  84. package/dist/components/chat/messages/UserMessage.d.ts +1 -1
  85. package/dist/components/chat/messages/UserMessage.js +7 -1
  86. package/dist/components/chat/messages/UserMessage.js.map +1 -1
  87. package/dist/components/chat/messages/UserMessage.mjs +1 -1
  88. package/dist/components/chat/props.d.ts +32 -27
  89. package/dist/components/chat/props.js.map +1 -1
  90. package/dist/components/index.d.ts +8 -3
  91. package/dist/components/index.js +316 -676
  92. package/dist/components/index.js.map +1 -1
  93. package/dist/components/index.mjs +18 -21
  94. package/dist/hooks/use-push-to-talk.d.ts +1 -1
  95. package/dist/hooks/use-push-to-talk.js +3 -3
  96. package/dist/hooks/use-push-to-talk.js.map +1 -1
  97. package/dist/hooks/use-push-to-talk.mjs +1 -1
  98. package/dist/index.css +59 -3
  99. package/dist/index.css.map +1 -1
  100. package/dist/index.d.ts +8 -3
  101. package/dist/index.js +322 -682
  102. package/dist/index.js.map +1 -1
  103. package/dist/index.mjs +18 -21
  104. package/dist/types/css.d.ts +3 -0
  105. package/dist/types/css.js.map +1 -1
  106. package/package.json +4 -4
  107. package/src/components/chat/Chat.tsx +193 -105
  108. package/src/components/chat/CodeBlock.tsx +1 -1
  109. package/src/components/chat/Markdown.tsx +12 -2
  110. package/src/components/chat/Messages.tsx +43 -122
  111. package/src/components/chat/Suggestion.tsx +5 -108
  112. package/src/components/chat/Suggestions.tsx +0 -1
  113. package/src/components/chat/index.tsx +1 -1
  114. package/src/components/chat/messages/AssistantMessage.tsx +15 -23
  115. package/src/components/chat/messages/ImageRenderer.tsx +37 -0
  116. package/src/components/chat/messages/{RenderTextMessage.tsx → RenderMessage.tsx} +10 -9
  117. package/src/components/chat/messages/UserMessage.tsx +16 -5
  118. package/src/components/chat/props.ts +36 -28
  119. package/src/css/colors.css +10 -0
  120. package/src/css/markdown.css +8 -0
  121. package/src/css/messages.css +54 -5
  122. package/src/css/suggestions.css +1 -1
  123. package/src/hooks/use-push-to-talk.tsx +6 -5
  124. package/src/styles.css +1 -1
  125. package/src/types/css.ts +3 -0
  126. package/dist/chunk-2II3Q27P.mjs +0 -112
  127. package/dist/chunk-2II3Q27P.mjs.map +0 -1
  128. package/dist/chunk-32MUWKL3.mjs.map +0 -1
  129. package/dist/chunk-53CVDVS5.mjs +0 -127
  130. package/dist/chunk-53CVDVS5.mjs.map +0 -1
  131. package/dist/chunk-B3D7U7TJ.mjs +0 -211
  132. package/dist/chunk-B3D7U7TJ.mjs.map +0 -1
  133. package/dist/chunk-C7OB63U5.mjs +0 -36
  134. package/dist/chunk-C7OB63U5.mjs.map +0 -1
  135. package/dist/chunk-HKTWKCPS.mjs.map +0 -1
  136. package/dist/chunk-HWMFMBJC.mjs +0 -10
  137. package/dist/chunk-HWMFMBJC.mjs.map +0 -1
  138. package/dist/chunk-IMBPSLL4.mjs +0 -104
  139. package/dist/chunk-IMBPSLL4.mjs.map +0 -1
  140. package/dist/chunk-KENCH7RN.mjs.map +0 -1
  141. package/dist/chunk-L3GZ7TXC.mjs.map +0 -1
  142. package/dist/chunk-QGSPTXOV.mjs.map +0 -1
  143. package/dist/chunk-S5MBUNGN.mjs.map +0 -1
  144. package/dist/chunk-ULDQXCED.mjs +0 -78
  145. package/dist/chunk-ULDQXCED.mjs.map +0 -1
  146. package/dist/chunk-YTXEWDNC.mjs.map +0 -1
  147. package/dist/components/chat/messages/RenderActionExecutionMessage.d.ts +0 -9
  148. package/dist/components/chat/messages/RenderActionExecutionMessage.js +0 -869
  149. package/dist/components/chat/messages/RenderActionExecutionMessage.js.map +0 -1
  150. package/dist/components/chat/messages/RenderActionExecutionMessage.mjs +0 -14
  151. package/dist/components/chat/messages/RenderAgentStateMessage.d.ts +0 -9
  152. package/dist/components/chat/messages/RenderAgentStateMessage.js +0 -854
  153. package/dist/components/chat/messages/RenderAgentStateMessage.js.map +0 -1
  154. package/dist/components/chat/messages/RenderAgentStateMessage.mjs +0 -14
  155. package/dist/components/chat/messages/RenderImageMessage.d.ts +0 -9
  156. package/dist/components/chat/messages/RenderImageMessage.js +0 -823
  157. package/dist/components/chat/messages/RenderImageMessage.js.map +0 -1
  158. package/dist/components/chat/messages/RenderImageMessage.mjs +0 -15
  159. package/dist/components/chat/messages/RenderImageMessage.mjs.map +0 -1
  160. package/dist/components/chat/messages/RenderResultMessage.d.ts +0 -9
  161. package/dist/components/chat/messages/RenderResultMessage.js +0 -778
  162. package/dist/components/chat/messages/RenderResultMessage.js.map +0 -1
  163. package/dist/components/chat/messages/RenderResultMessage.mjs +0 -14
  164. package/dist/components/chat/messages/RenderResultMessage.mjs.map +0 -1
  165. package/dist/components/chat/messages/RenderTextMessage.d.ts +0 -9
  166. package/dist/components/chat/messages/RenderTextMessage.js.map +0 -1
  167. package/dist/components/chat/messages/RenderTextMessage.mjs +0 -15
  168. package/dist/components/chat/messages/RenderTextMessage.mjs.map +0 -1
  169. package/src/components/chat/messages/RenderActionExecutionMessage.tsx +0 -127
  170. package/src/components/chat/messages/RenderAgentStateMessage.tsx +0 -116
  171. package/src/components/chat/messages/RenderImageMessage.tsx +0 -64
  172. package/src/components/chat/messages/RenderResultMessage.tsx +0 -26
  173. /package/dist/{chunk-4HUXYD3B.mjs.map → chunk-DTRPPNSA.mjs.map} +0 -0
  174. /package/dist/{chunk-KN2GCKBE.mjs.map → chunk-GJ3MFNBX.mjs.map} +0 -0
  175. /package/dist/{chunk-H3EM63WS.mjs.map → chunk-VLNT34X3.mjs.map} +0 -0
  176. /package/dist/{chunk-ALIBUJML.mjs.map → chunk-WPVTPQ7X.mjs.map} +0 -0
  177. /package/dist/components/chat/messages/{RenderActionExecutionMessage.mjs.map → ImageRenderer.mjs.map} +0 -0
  178. /package/dist/components/chat/messages/{RenderAgentStateMessage.mjs.map → RenderMessage.mjs.map} +0 -0
@@ -1,18 +1,13 @@
1
1
  import { useEffect, useMemo, useRef } from "react";
2
2
  import { MessagesProps } from "./props";
3
3
  import { useChatContext } from "./ChatContext";
4
- import { Message, ResultMessage, TextMessage, Role } from "@copilotkit/runtime-client-gql";
5
- import { useLangGraphInterruptRender } from "@copilotkit/react-core";
4
+ import { Message, Role } from "@copilotkit/shared";
5
+ import { useCopilotChat } from "@copilotkit/react-core";
6
6
 
7
7
  export const Messages = ({
8
- messages,
9
8
  inProgress,
10
9
  children,
11
- RenderTextMessage,
12
- RenderActionExecutionMessage,
13
- RenderAgentStateMessage,
14
- RenderResultMessage,
15
- RenderImageMessage,
10
+ RenderMessage,
16
11
  AssistantMessage,
17
12
  UserMessage,
18
13
  onRegenerate,
@@ -21,110 +16,33 @@ export const Messages = ({
21
16
  onThumbsDown,
22
17
  markdownTagRenderers,
23
18
  }: MessagesProps) => {
24
- const context = useChatContext();
25
- const initialMessages = useMemo(
26
- () => makeInitialMessages(context.labels.initial),
27
- [context.labels.initial],
28
- );
29
-
30
- messages = [...initialMessages, ...messages];
31
-
32
- const actionResults: Record<string, string> = {};
33
-
34
- for (let i = 0; i < messages.length; i++) {
35
- if (messages[i].isActionExecutionMessage()) {
36
- const id = messages[i].id;
37
- const resultMessage: ResultMessage | undefined = messages.find(
38
- (message) => message.isResultMessage() && message.actionExecutionId === id,
39
- ) as ResultMessage | undefined;
40
-
41
- if (resultMessage) {
42
- actionResults[id] = ResultMessage.decodeResult(resultMessage.result || "");
43
- }
44
- }
45
- }
46
-
19
+ const { labels } = useChatContext();
20
+ const { visibleMessages, interrupt } = useCopilotChat();
21
+ const initialMessages = useMemo(() => makeInitialMessages(labels.initial), [labels.initial]);
22
+ const messages = [...initialMessages, ...visibleMessages];
47
23
  const { messagesContainerRef, messagesEndRef } = useScrollToBottom(messages);
48
24
 
49
- const interrupt = useLangGraphInterruptRender();
50
-
51
25
  return (
52
26
  <div className="copilotKitMessages" ref={messagesContainerRef}>
53
27
  <div className="copilotKitMessagesContainer">
54
28
  {messages.map((message, index) => {
55
29
  const isCurrentMessage = index === messages.length - 1;
56
-
57
- if (message.isTextMessage()) {
58
- return (
59
- <RenderTextMessage
60
- key={index}
61
- message={message}
62
- inProgress={inProgress}
63
- index={index}
64
- isCurrentMessage={isCurrentMessage}
65
- AssistantMessage={AssistantMessage}
66
- UserMessage={UserMessage}
67
- onRegenerate={onRegenerate}
68
- onCopy={onCopy}
69
- onThumbsUp={onThumbsUp}
70
- onThumbsDown={onThumbsDown}
71
- markdownTagRenderers={markdownTagRenderers}
72
- />
73
- );
74
- } else if (message.isActionExecutionMessage()) {
75
- return (
76
- <RenderActionExecutionMessage
77
- key={index}
78
- message={message}
79
- inProgress={inProgress}
80
- index={index}
81
- isCurrentMessage={isCurrentMessage}
82
- actionResult={actionResults[message.id]}
83
- AssistantMessage={AssistantMessage}
84
- UserMessage={UserMessage}
85
- />
86
- );
87
- } else if (message.isAgentStateMessage()) {
88
- return (
89
- <RenderAgentStateMessage
90
- key={index}
91
- message={message}
92
- inProgress={inProgress}
93
- index={index}
94
- isCurrentMessage={isCurrentMessage}
95
- AssistantMessage={AssistantMessage}
96
- UserMessage={UserMessage}
97
- />
98
- );
99
- } else if (message.isResultMessage()) {
100
- return (
101
- <RenderResultMessage
102
- key={index}
103
- message={message}
104
- inProgress={inProgress}
105
- index={index}
106
- isCurrentMessage={isCurrentMessage}
107
- AssistantMessage={AssistantMessage}
108
- UserMessage={UserMessage}
109
- />
110
- );
111
- } else if (message.isImageMessage && message.isImageMessage()) {
112
- return (
113
- <RenderImageMessage
114
- key={index}
115
- message={message}
116
- inProgress={inProgress}
117
- index={index}
118
- isCurrentMessage={isCurrentMessage}
119
- AssistantMessage={AssistantMessage}
120
- UserMessage={UserMessage}
121
- onRegenerate={onRegenerate}
122
- onCopy={onCopy}
123
- onThumbsUp={onThumbsUp}
124
- onThumbsDown={onThumbsDown}
125
- />
126
- );
127
- }
30
+ return (
31
+ <RenderMessage
32
+ key={index}
33
+ message={message}
34
+ inProgress={inProgress}
35
+ index={index}
36
+ isCurrentMessage={isCurrentMessage}
37
+ AssistantMessage={AssistantMessage}
38
+ UserMessage={UserMessage}
39
+ onRegenerate={onRegenerate}
40
+ onCopy={onCopy}
41
+ onThumbsUp={onThumbsUp}
42
+ onThumbsDown={onThumbsDown}
43
+ markdownTagRenderers={markdownTagRenderers}
44
+ />
45
+ );
128
46
  })}
129
47
  {interrupt}
130
48
  </div>
@@ -135,26 +53,29 @@ export const Messages = ({
135
53
  );
136
54
  };
137
55
 
138
- function makeInitialMessages(initial?: string | string[]): Message[] {
139
- let initialArray: string[] = [];
140
- if (initial) {
141
- if (Array.isArray(initial)) {
142
- initialArray.push(...initial);
143
- } else {
144
- initialArray.push(initial);
145
- }
146
- }
56
+ function makeInitialMessages(initial: string | string[] | undefined): Message[] {
57
+ if (!initial) return [];
147
58
 
148
- return initialArray.map(
149
- (message) =>
150
- new TextMessage({
151
- role: Role.Assistant,
59
+ if (Array.isArray(initial)) {
60
+ return initial.map((message) => {
61
+ return {
62
+ id: message,
63
+ role: "assistant",
152
64
  content: message,
153
- }),
154
- );
65
+ };
66
+ });
67
+ }
68
+
69
+ return [
70
+ {
71
+ id: initial,
72
+ role: "system",
73
+ content: initial,
74
+ },
75
+ ];
155
76
  }
156
77
 
157
- export function useScrollToBottom(messages: any[]) {
78
+ export function useScrollToBottom(messages: Message[]) {
158
79
  const messagesEndRef = useRef<HTMLDivElement>(null);
159
80
  const messagesContainerRef = useRef<HTMLDivElement | null>(null);
160
81
  const isProgrammaticScrollRef = useRef(false);
@@ -217,7 +138,7 @@ export function useScrollToBottom(messages: any[]) {
217
138
  useEffect(() => {
218
139
  isUserScrollUpRef.current = false;
219
140
  scrollToBottom();
220
- }, [messages.filter((m) => m.isTextMessage() && m.role === Role.User).length]);
141
+ }, [messages.filter((m) => m.role === "user").length]);
221
142
 
222
143
  return { messagesEndRef, messagesContainerRef };
223
144
  }
@@ -1,13 +1,5 @@
1
- import {
2
- CopilotContextParams,
3
- extract,
4
- CopilotChatSuggestionConfiguration,
5
- CopilotMessagesContextParams,
6
- } from "@copilotkit/react-core";
1
+ import { useCopilotChat } from "@copilotkit/react-core";
7
2
  import { SmallSpinnerIcon } from "./Icons";
8
- import { CopilotChatSuggestion } from "../../types/suggestions";
9
- import { actionParametersToJsonSchema } from "@copilotkit/shared";
10
- import { CopilotRequestType } from "@copilotkit/runtime-client-gql";
11
3
 
12
4
  interface SuggestionsProps {
13
5
  title: string;
@@ -18,9 +10,12 @@ interface SuggestionsProps {
18
10
  }
19
11
 
20
12
  export function Suggestion({ title, onClick, partial, className }: SuggestionsProps) {
13
+ if (!title) return null;
14
+ const { isLoading } = useCopilotChat();
15
+
21
16
  return (
22
17
  <button
23
- disabled={partial}
18
+ disabled={partial || isLoading}
24
19
  onClick={(e) => {
25
20
  e.preventDefault();
26
21
  onClick();
@@ -32,101 +27,3 @@ export function Suggestion({ title, onClick, partial, className }: SuggestionsPr
32
27
  </button>
33
28
  );
34
29
  }
35
-
36
- export const reloadSuggestions = async (
37
- context: CopilotContextParams & CopilotMessagesContextParams,
38
- chatSuggestionConfiguration: { [key: string]: CopilotChatSuggestionConfiguration },
39
- setCurrentSuggestions: (suggestions: { title: string; message: string }[]) => void,
40
- abortControllerRef: React.MutableRefObject<AbortController | null>,
41
- ) => {
42
- const abortController = abortControllerRef.current;
43
-
44
- const tools = JSON.stringify(
45
- Object.values(context.actions).map((action) => ({
46
- name: action.name,
47
- description: action.description,
48
- jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters)),
49
- })),
50
- );
51
-
52
- const allSuggestions: CopilotChatSuggestion[] = [];
53
-
54
- for (const config of Object.values(chatSuggestionConfiguration)) {
55
- try {
56
- const numOfSuggestionsInstructions =
57
- config.minSuggestions === 0
58
- ? `Produce up to ${config.maxSuggestions} suggestions. ` +
59
- `If there are no highly relevant suggestions you can think of, provide an empty array.`
60
- : `Produce between ${config.minSuggestions} and ${config.maxSuggestions} suggestions.`;
61
-
62
- const result = await extract({
63
- context,
64
- instructions:
65
- "Suggest what the user could say next. Provide clear, highly relevant suggestions. Do not literally suggest function calls. ",
66
- data:
67
- config.instructions +
68
- "\n\n" +
69
- numOfSuggestionsInstructions +
70
- "\n\n" +
71
- "Available tools: " +
72
- tools +
73
- "\n\n",
74
- requestType: CopilotRequestType.Task,
75
- parameters: [
76
- {
77
- name: "suggestions",
78
- type: "object[]",
79
- attributes: [
80
- {
81
- name: "title",
82
- description:
83
- "The title of the suggestion. This is shown as a button and should be short.",
84
- type: "string",
85
- },
86
- {
87
- name: "message",
88
- description:
89
- "The message to send when the suggestion is clicked. This should be a clear, complete sentence and will be sent as an instruction to the AI.",
90
- type: "string",
91
- },
92
- ],
93
- },
94
- ],
95
- include: {
96
- messages: true,
97
- readable: true,
98
- },
99
- abortSignal: abortController?.signal,
100
- stream: ({ status, args }) => {
101
- const suggestions = args.suggestions || [];
102
- const newSuggestions: CopilotChatSuggestion[] = [];
103
- for (let i = 0; i < suggestions.length; i++) {
104
- // if GPT provides too many suggestions, limit the number of suggestions
105
- if (config.maxSuggestions !== undefined && i >= config.maxSuggestions) {
106
- break;
107
- }
108
- const { title, message } = suggestions[i];
109
-
110
- // If this is the last suggestion and the status is not complete, mark it as partial
111
- const partial = i == suggestions.length - 1 && status !== "complete";
112
-
113
- newSuggestions.push({
114
- title,
115
- message,
116
- partial,
117
- className: config.className,
118
- });
119
- }
120
- setCurrentSuggestions([...allSuggestions, ...newSuggestions]);
121
- },
122
- });
123
- allSuggestions.push(...result.suggestions);
124
- } catch (error) {
125
- console.error("Error loading suggestions", error);
126
- }
127
- }
128
-
129
- if (abortControllerRef.current === abortController) {
130
- abortControllerRef.current = null;
131
- }
132
- };
@@ -1,5 +1,4 @@
1
1
  import { Suggestion } from "./Suggestion";
2
- import React from "react";
3
2
  import { RenderSuggestionsListProps } from "./props";
4
3
 
5
4
  export function Suggestions({ suggestions, onSuggestionClick }: RenderSuggestionsListProps) {
@@ -5,7 +5,7 @@ export { CopilotChat } from "./Chat";
5
5
  export { Markdown } from "./Markdown";
6
6
  export { AssistantMessage } from "./messages/AssistantMessage";
7
7
  export { UserMessage } from "./messages/UserMessage";
8
+ export { ImageRenderer } from "./messages/ImageRenderer";
8
9
  export { useChatContext } from "./ChatContext";
9
- export { RenderImageMessage } from "./messages/RenderImageMessage";
10
10
  export { Suggestions as RenderSuggestionsList } from "./Suggestions";
11
11
  export { Suggestion as RenderSuggestion } from "./Suggestion";
@@ -2,67 +2,58 @@ import { AssistantMessageProps } from "../props";
2
2
  import { useChatContext } from "../ChatContext";
3
3
  import { Markdown } from "../Markdown";
4
4
  import { useState } from "react";
5
- import { TextMessage } from "@copilotkit/runtime-client-gql";
6
5
 
7
6
  export const AssistantMessage = (props: AssistantMessageProps) => {
8
7
  const { icons, labels } = useChatContext();
9
8
  const {
10
9
  message,
11
10
  isLoading,
12
- subComponent,
13
11
  onRegenerate,
14
12
  onCopy,
15
13
  onThumbsUp,
16
14
  onThumbsDown,
17
15
  isCurrentMessage,
18
- rawData,
19
16
  markdownTagRenderers,
20
17
  } = props;
21
18
  const [copied, setCopied] = useState(false);
22
19
 
23
20
  const handleCopy = () => {
24
- if (message && onCopy) {
25
- navigator.clipboard.writeText(message);
21
+ const content = message?.content || "";
22
+ if (content && onCopy) {
23
+ navigator.clipboard.writeText(content);
26
24
  setCopied(true);
27
- onCopy(message);
25
+ onCopy(content);
28
26
  setTimeout(() => setCopied(false), 2000);
29
- } else if (message) {
30
- navigator.clipboard.writeText(message);
27
+ } else if (content) {
28
+ navigator.clipboard.writeText(content);
31
29
  setCopied(true);
32
30
  setTimeout(() => setCopied(false), 2000);
33
31
  }
34
32
  };
35
33
 
36
34
  const handleRegenerate = () => {
37
- if (onRegenerate) {
38
- onRegenerate();
39
- }
35
+ if (onRegenerate) onRegenerate();
40
36
  };
41
37
 
42
38
  const handleThumbsUp = () => {
43
- const fullMessage = rawData as TextMessage;
44
- if (onThumbsUp && fullMessage) {
45
- onThumbsUp(fullMessage);
46
- }
39
+ if (onThumbsUp && message) onThumbsUp(message);
47
40
  };
48
41
 
49
42
  const handleThumbsDown = () => {
50
- const fullMessage = rawData as TextMessage;
51
- if (onThumbsDown && fullMessage) {
52
- onThumbsDown(fullMessage);
53
- }
43
+ if (onThumbsDown && message) onThumbsDown(message);
54
44
  };
55
45
 
56
46
  const LoadingIcon = () => <span>{icons.activityIcon}</span>;
47
+ const content = message?.content || "";
48
+ const subComponent = message?.generativeUI?.();
57
49
 
58
50
  return (
59
51
  <>
60
- {(message || isLoading) && (
52
+ {content && (
61
53
  <div className="copilotKitMessage copilotKitAssistantMessage">
62
- {message && <Markdown content={message || ""} components={markdownTagRenderers} />}
63
- {isLoading && <LoadingIcon />}
54
+ {content && <Markdown content={content} components={markdownTagRenderers} />}
64
55
 
65
- {message && !isLoading && (
56
+ {content && !isLoading && (
66
57
  <div
67
58
  className={`copilotKitMessageControls ${isCurrentMessage ? "currentMessage" : ""}`}
68
59
  >
@@ -111,6 +102,7 @@ export const AssistantMessage = (props: AssistantMessageProps) => {
111
102
  </div>
112
103
  )}
113
104
  <div style={{ marginBottom: "0.5rem" }}>{subComponent}</div>
105
+ {isLoading && <LoadingIcon />}
114
106
  </>
115
107
  );
116
108
  };
@@ -0,0 +1,37 @@
1
+ import React, { useState } from "react";
2
+ import { ImageRendererProps } from "../props";
3
+
4
+ /**
5
+ * Default image rendering component that can be customized by users.
6
+ * Uses CSS classes for styling so users can override styles.
7
+ */
8
+ export const ImageRenderer: React.FC<ImageRendererProps> = ({ image, content, className = "" }) => {
9
+ const [imageError, setImageError] = useState(false);
10
+ const imageSrc = `data:image/${image.format};base64,${image.bytes}`;
11
+ const altText = content || "User uploaded image";
12
+
13
+ const handleImageError = () => {
14
+ setImageError(true);
15
+ };
16
+
17
+ if (imageError) {
18
+ return (
19
+ <div className={`copilotKitImageRendering copilotKitImageRenderingError ${className}`}>
20
+ <div className="copilotKitImageRenderingErrorMessage">Failed to load image</div>
21
+ {content && <div className="copilotKitImageRenderingContent">{content}</div>}
22
+ </div>
23
+ );
24
+ }
25
+
26
+ return (
27
+ <div className={`copilotKitImageRendering ${className}`}>
28
+ <img
29
+ src={imageSrc}
30
+ alt={altText}
31
+ className="copilotKitImageRenderingImage"
32
+ onError={handleImageError}
33
+ />
34
+ {content && <div className="copilotKitImageRenderingContent">{content}</div>}
35
+ </div>
36
+ );
37
+ };
@@ -1,10 +1,12 @@
1
1
  import { RenderMessageProps } from "../props";
2
2
  import { UserMessage as DefaultUserMessage } from "./UserMessage";
3
3
  import { AssistantMessage as DefaultAssistantMessage } from "./AssistantMessage";
4
+ import { ImageRenderer as DefaultImageRenderer } from "./ImageRenderer";
4
5
 
5
- export function RenderTextMessage({
6
+ export function RenderMessage({
6
7
  UserMessage = DefaultUserMessage,
7
8
  AssistantMessage = DefaultAssistantMessage,
9
+ ImageRenderer = DefaultImageRenderer,
8
10
  ...props
9
11
  }: RenderMessageProps) {
10
12
  const {
@@ -19,23 +21,22 @@ export function RenderTextMessage({
19
21
  markdownTagRenderers,
20
22
  } = props;
21
23
 
22
- if (message.isTextMessage()) {
23
- if (message.role === "user") {
24
+ switch (message.role) {
25
+ case "user":
24
26
  return (
25
27
  <UserMessage
26
28
  key={index}
27
29
  data-message-role="user"
28
- message={message.content}
29
- rawData={message}
30
+ message={message}
31
+ ImageRenderer={ImageRenderer}
30
32
  />
31
33
  );
32
- } else if (message.role == "assistant") {
34
+ case "assistant":
33
35
  return (
34
36
  <AssistantMessage
35
37
  key={index}
36
38
  data-message-role="assistant"
37
- message={message.content}
38
- rawData={message}
39
+ message={message}
39
40
  isLoading={inProgress && isCurrentMessage && !message.content}
40
41
  isGenerating={inProgress && isCurrentMessage && !!message.content}
41
42
  isCurrentMessage={isCurrentMessage}
@@ -44,8 +45,8 @@ export function RenderTextMessage({
44
45
  onThumbsUp={onThumbsUp}
45
46
  onThumbsDown={onThumbsDown}
46
47
  markdownTagRenderers={markdownTagRenderers}
48
+ ImageRenderer={ImageRenderer}
47
49
  />
48
50
  );
49
- }
50
51
  }
51
52
  }
@@ -1,9 +1,20 @@
1
1
  import { UserMessageProps } from "../props";
2
2
 
3
3
  export const UserMessage = (props: UserMessageProps) => {
4
- return (
5
- <div className="copilotKitMessage copilotKitUserMessage">
6
- {props.subComponent || props.message}
7
- </div>
8
- );
4
+ const { message, ImageRenderer } = props;
5
+ const isImageMessage = message && "image" in message && message.image;
6
+
7
+ // Image message
8
+ if (isImageMessage) {
9
+ const imageMessage = message;
10
+
11
+ return (
12
+ <div className="copilotKitMessage copilotKitUserMessage">
13
+ <ImageRenderer image={imageMessage.image!} content={imageMessage.content} />
14
+ </div>
15
+ );
16
+ }
17
+
18
+ // Regular text message
19
+ return <div className="copilotKitMessage copilotKitUserMessage">{message?.content}</div>;
9
20
  };