@copilotkit/react-ui 1.7.2-next.1 → 1.8.0-next.3

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 (201) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/{chunk-QXTRFMPM.mjs → chunk-2LRE4W6A.mjs} +13 -11
  3. package/dist/chunk-2LRE4W6A.mjs.map +1 -0
  4. package/dist/{chunk-2C3ANQCY.mjs → chunk-5GNYGURH.mjs} +53 -42
  5. package/dist/chunk-5GNYGURH.mjs.map +1 -0
  6. package/dist/{chunk-CBBFRI3Q.mjs → chunk-5JY5QJ2W.mjs} +9 -5
  7. package/dist/chunk-5JY5QJ2W.mjs.map +1 -0
  8. package/dist/{chunk-OFYI4UU4.mjs → chunk-7RIBDD4K.mjs} +19 -3
  9. package/dist/chunk-7RIBDD4K.mjs.map +1 -0
  10. package/dist/{chunk-YAGE7RCE.mjs → chunk-CGVOCLHN.mjs} +2 -2
  11. package/dist/chunk-EJG6RRSX.mjs +138 -0
  12. package/dist/chunk-EJG6RRSX.mjs.map +1 -0
  13. package/dist/chunk-FBYETUFL.mjs +118 -0
  14. package/dist/chunk-FBYETUFL.mjs.map +1 -0
  15. package/dist/chunk-GDJAAFIK.mjs +24 -0
  16. package/dist/chunk-GDJAAFIK.mjs.map +1 -0
  17. package/dist/{chunk-6FTRYYR5.mjs → chunk-GJME6MK4.mjs} +72 -62
  18. package/dist/chunk-GJME6MK4.mjs.map +1 -0
  19. package/dist/{chunk-AZU4QOV5.mjs → chunk-KG6DW6R2.mjs} +12 -12
  20. package/dist/{chunk-3PJA5MFR.mjs → chunk-LKCAF2HG.mjs} +2 -2
  21. package/dist/{chunk-ADTTDBLB.mjs → chunk-LXCH2BIB.mjs} +2 -2
  22. package/dist/chunk-MCO235PS.mjs +164 -0
  23. package/dist/chunk-MCO235PS.mjs.map +1 -0
  24. package/dist/chunk-MWC5OV7Z.mjs +1 -0
  25. package/dist/chunk-N7LTE54T.mjs +1 -0
  26. package/dist/chunk-N7LTE54T.mjs.map +1 -0
  27. package/dist/chunk-ORSMX3SE.mjs +244 -0
  28. package/dist/chunk-ORSMX3SE.mjs.map +1 -0
  29. package/dist/{chunk-UPTB2MVO.mjs → chunk-PCTCOQK2.mjs} +4 -10
  30. package/dist/chunk-PCTCOQK2.mjs.map +1 -0
  31. package/dist/{chunk-22K5DDPF.mjs → chunk-QGK5GOSC.mjs} +31 -60
  32. package/dist/chunk-QGK5GOSC.mjs.map +1 -0
  33. package/dist/{chunk-WGAZXTUA.mjs → chunk-TOQ7P4DO.mjs} +6 -9
  34. package/dist/chunk-TOQ7P4DO.mjs.map +1 -0
  35. package/dist/chunk-UCVCAGU7.mjs +1 -0
  36. package/dist/chunk-UCVCAGU7.mjs.map +1 -0
  37. package/dist/{chunk-3XAXY2Z3.mjs → chunk-UZTZXMYS.mjs} +2 -2
  38. package/dist/{chunk-RQNJNK2W.mjs → chunk-VC4NO5QZ.mjs} +2 -2
  39. package/dist/{chunk-YQ3D5IQV.mjs → chunk-XNQO5AZZ.mjs} +2 -5
  40. package/dist/chunk-XNQO5AZZ.mjs.map +1 -0
  41. package/dist/chunk-YC4NBUGE.mjs +97 -0
  42. package/dist/chunk-YC4NBUGE.mjs.map +1 -0
  43. package/dist/components/chat/Button.js.map +1 -1
  44. package/dist/components/chat/Button.mjs +3 -3
  45. package/dist/components/chat/Chat.d.ts +17 -1
  46. package/dist/components/chat/Chat.js +378 -905
  47. package/dist/components/chat/Chat.js.map +1 -1
  48. package/dist/components/chat/Chat.mjs +12 -19
  49. package/dist/components/chat/ChatContext.d.ts +20 -0
  50. package/dist/components/chat/ChatContext.js +44 -74
  51. package/dist/components/chat/ChatContext.js.map +1 -1
  52. package/dist/components/chat/ChatContext.mjs +2 -2
  53. package/dist/components/chat/CodeBlock.js +58 -82
  54. package/dist/components/chat/CodeBlock.js.map +1 -1
  55. package/dist/components/chat/CodeBlock.mjs +2 -2
  56. package/dist/components/chat/Header.js +516 -4
  57. package/dist/components/chat/Header.js.map +1 -1
  58. package/dist/components/chat/Header.mjs +10 -3
  59. package/dist/components/chat/Icons.d.ts +10 -9
  60. package/dist/components/chat/Icons.js +125 -164
  61. package/dist/components/chat/Icons.js.map +1 -1
  62. package/dist/components/chat/Icons.mjs +9 -5
  63. package/dist/components/chat/Input.d.ts +1 -1
  64. package/dist/components/chat/Input.js +11 -9
  65. package/dist/components/chat/Input.js.map +1 -1
  66. package/dist/components/chat/Input.mjs +3 -3
  67. package/dist/components/chat/Markdown.js +58 -56
  68. package/dist/components/chat/Markdown.js.map +1 -1
  69. package/dist/components/chat/Markdown.mjs +3 -3
  70. package/dist/components/chat/Messages.d.ts +1 -1
  71. package/dist/components/chat/Messages.js +70 -60
  72. package/dist/components/chat/Messages.js.map +1 -1
  73. package/dist/components/chat/Messages.mjs +3 -3
  74. package/dist/components/chat/Modal.js +1708 -1749
  75. package/dist/components/chat/Modal.js.map +1 -1
  76. package/dist/components/chat/Modal.mjs +23 -23
  77. package/dist/components/chat/Popup.js +1708 -1749
  78. package/dist/components/chat/Popup.js.map +1 -1
  79. package/dist/components/chat/Popup.mjs +24 -24
  80. package/dist/components/chat/Response.js.map +1 -1
  81. package/dist/components/chat/Response.mjs +3 -3
  82. package/dist/components/chat/Sidebar.js +1710 -1751
  83. package/dist/components/chat/Sidebar.js.map +1 -1
  84. package/dist/components/chat/Sidebar.mjs +24 -24
  85. package/dist/components/chat/Suggestion.js +4 -40
  86. package/dist/components/chat/Suggestion.js.map +1 -1
  87. package/dist/components/chat/Suggestion.mjs +2 -2
  88. package/dist/components/chat/Window.js.map +1 -1
  89. package/dist/components/chat/Window.mjs +3 -3
  90. package/dist/components/chat/index.js +1710 -1751
  91. package/dist/components/chat/index.js.map +1 -1
  92. package/dist/components/chat/index.mjs +27 -27
  93. package/dist/components/chat/messages/AssistantMessage.js +211 -59
  94. package/dist/components/chat/messages/AssistantMessage.js.map +1 -1
  95. package/dist/components/chat/messages/AssistantMessage.mjs +5 -5
  96. package/dist/components/chat/messages/RenderTextMessage.js +18 -2
  97. package/dist/components/chat/messages/RenderTextMessage.js.map +1 -1
  98. package/dist/components/chat/messages/RenderTextMessage.mjs +1 -1
  99. package/dist/components/chat/props.d.ts +53 -0
  100. package/dist/components/chat/props.js.map +1 -1
  101. package/dist/components/crew/DefaultResponseRenderer.d.ts +110 -0
  102. package/dist/components/crew/DefaultResponseRenderer.js +175 -0
  103. package/dist/components/crew/DefaultResponseRenderer.js.map +1 -0
  104. package/dist/components/crew/DefaultResponseRenderer.mjs +10 -0
  105. package/dist/components/crew/DefaultResponseRenderer.mjs.map +1 -0
  106. package/dist/components/crew/DefaultStateRenderer.d.ts +88 -0
  107. package/dist/components/crew/DefaultStateRenderer.js +198 -0
  108. package/dist/components/crew/DefaultStateRenderer.js.map +1 -0
  109. package/dist/components/crew/DefaultStateRenderer.mjs +8 -0
  110. package/dist/components/crew/DefaultStateRenderer.mjs.map +1 -0
  111. package/dist/components/crew/index.d.ts +4 -0
  112. package/dist/components/crew/index.js +335 -0
  113. package/dist/components/crew/index.js.map +1 -0
  114. package/dist/components/crew/index.mjs +16 -0
  115. package/dist/components/crew/index.mjs.map +1 -0
  116. package/dist/components/crew/types.d.ts +340 -0
  117. package/dist/components/crew/types.js +19 -0
  118. package/dist/components/crew/types.js.map +1 -0
  119. package/dist/components/crew/types.mjs +2 -0
  120. package/dist/components/crew/types.mjs.map +1 -0
  121. package/dist/components/dev-console/console.js +51 -233
  122. package/dist/components/dev-console/console.js.map +1 -1
  123. package/dist/components/dev-console/console.mjs +5 -5
  124. package/dist/components/dev-console/index.js +51 -233
  125. package/dist/components/dev-console/index.js.map +1 -1
  126. package/dist/components/dev-console/index.mjs +5 -5
  127. package/dist/components/help-modal/index.js +29 -147
  128. package/dist/components/help-modal/index.js.map +1 -1
  129. package/dist/components/help-modal/index.mjs +1 -1
  130. package/dist/components/help-modal/modal.js +29 -147
  131. package/dist/components/help-modal/modal.js.map +1 -1
  132. package/dist/components/help-modal/modal.mjs +1 -1
  133. package/dist/components/index.d.ts +3 -0
  134. package/dist/components/index.js +2191 -1942
  135. package/dist/components/index.js.map +1 -1
  136. package/dist/components/index.mjs +43 -31
  137. package/dist/index.css +481 -90
  138. package/dist/index.css.map +1 -1
  139. package/dist/index.d.ts +3 -0
  140. package/dist/index.js +2192 -1943
  141. package/dist/index.js.map +1 -1
  142. package/dist/index.mjs +43 -31
  143. package/dist/types/css.d.ts +7 -1
  144. package/dist/types/css.js.map +1 -1
  145. package/package.json +4 -4
  146. package/src/components/chat/Chat.tsx +59 -22
  147. package/src/components/chat/ChatContext.tsx +29 -1
  148. package/src/components/chat/CodeBlock.tsx +2 -4
  149. package/src/components/chat/Header.tsx +8 -3
  150. package/src/components/chat/Icons.tsx +108 -108
  151. package/src/components/chat/Input.tsx +42 -38
  152. package/src/components/chat/Markdown.tsx +0 -3
  153. package/src/components/chat/Messages.tsx +68 -56
  154. package/src/components/chat/Suggestion.tsx +2 -3
  155. package/src/components/chat/messages/AssistantMessage.tsx +95 -3
  156. package/src/components/chat/messages/RenderTextMessage.tsx +17 -1
  157. package/src/components/chat/props.ts +66 -0
  158. package/src/components/crew/DefaultResponseRenderer.tsx +298 -0
  159. package/src/components/crew/DefaultStateRenderer.tsx +326 -0
  160. package/src/components/crew/index.ts +3 -0
  161. package/src/components/crew/types.ts +398 -0
  162. package/src/components/dev-console/console.tsx +16 -54
  163. package/src/components/help-modal/modal.tsx +38 -101
  164. package/src/components/index.ts +1 -0
  165. package/src/css/button.css +15 -4
  166. package/src/css/colors.css +27 -6
  167. package/src/css/console.css +46 -39
  168. package/src/css/crew.css +277 -0
  169. package/src/css/header.css +22 -5
  170. package/src/css/input.css +24 -17
  171. package/src/css/markdown.css +2 -1
  172. package/src/css/messages.css +125 -15
  173. package/src/css/panel.css +1 -0
  174. package/src/css/suggestions.css +14 -6
  175. package/src/styles.css +1 -0
  176. package/src/types/css.ts +7 -1
  177. package/dist/chunk-22K5DDPF.mjs.map +0 -1
  178. package/dist/chunk-2C3ANQCY.mjs.map +0 -1
  179. package/dist/chunk-3VNMQWGT.mjs +0 -25
  180. package/dist/chunk-3VNMQWGT.mjs.map +0 -1
  181. package/dist/chunk-6FTRYYR5.mjs.map +0 -1
  182. package/dist/chunk-CBBFRI3Q.mjs.map +0 -1
  183. package/dist/chunk-FZC7X5PK.mjs +0 -262
  184. package/dist/chunk-FZC7X5PK.mjs.map +0 -1
  185. package/dist/chunk-MMVDU6DF.mjs +0 -1
  186. package/dist/chunk-OFYI4UU4.mjs.map +0 -1
  187. package/dist/chunk-QXTRFMPM.mjs.map +0 -1
  188. package/dist/chunk-TI7SY2RI.mjs +0 -164
  189. package/dist/chunk-TI7SY2RI.mjs.map +0 -1
  190. package/dist/chunk-UPTB2MVO.mjs.map +0 -1
  191. package/dist/chunk-VEC45H6Q.mjs +0 -18
  192. package/dist/chunk-VEC45H6Q.mjs.map +0 -1
  193. package/dist/chunk-WGAZXTUA.mjs.map +0 -1
  194. package/dist/chunk-YQ3D5IQV.mjs.map +0 -1
  195. /package/dist/{chunk-YAGE7RCE.mjs.map → chunk-CGVOCLHN.mjs.map} +0 -0
  196. /package/dist/{chunk-AZU4QOV5.mjs.map → chunk-KG6DW6R2.mjs.map} +0 -0
  197. /package/dist/{chunk-3PJA5MFR.mjs.map → chunk-LKCAF2HG.mjs.map} +0 -0
  198. /package/dist/{chunk-ADTTDBLB.mjs.map → chunk-LXCH2BIB.mjs.map} +0 -0
  199. /package/dist/{chunk-MMVDU6DF.mjs.map → chunk-MWC5OV7Z.mjs.map} +0 -0
  200. /package/dist/{chunk-3XAXY2Z3.mjs.map → chunk-UZTZXMYS.mjs.map} +0 -0
  201. /package/dist/{chunk-RQNJNK2W.mjs.map → chunk-VC4NO5QZ.mjs.map} +0 -0
@@ -5,7 +5,7 @@ import AutoResizingTextarea from "./Textarea";
5
5
  import { usePushToTalk } from "../../hooks/use-push-to-talk";
6
6
  import { useCopilotContext } from "@copilotkit/react-core";
7
7
 
8
- export const Input = ({ inProgress, onSend, isVisible = false }: InputProps) => {
8
+ export const Input = ({ inProgress, onSend, isVisible = false, onStop }: InputProps) => {
9
9
  const context = useChatContext();
10
10
  const copilotContext = useCopilotContext();
11
11
 
@@ -42,10 +42,8 @@ export const Input = ({ inProgress, onSend, isVisible = false }: InputProps) =>
42
42
  inProgress,
43
43
  });
44
44
 
45
- const sendIcon =
46
- inProgress || pushToTalkState === "transcribing"
47
- ? context.icons.activityIcon
48
- : context.icons.sendIcon;
45
+ const isInProgress = inProgress || pushToTalkState === "transcribing";
46
+ const buttonIcon = isInProgress ? context.icons.stopIcon : context.icons.sendIcon;
49
47
  const showPushToTalk =
50
48
  pushToTalkConfigured &&
51
49
  (pushToTalkState === "idle" || pushToTalkState === "recording") &&
@@ -55,50 +53,56 @@ export const Input = ({ inProgress, onSend, isVisible = false }: InputProps) =>
55
53
  const interruptEvent = copilotContext.langGraphInterruptAction?.event;
56
54
  const interruptInProgress =
57
55
  interruptEvent?.name === "LangGraphInterruptEvent" && !interruptEvent?.response;
56
+
58
57
  return (
59
- !inProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interruptInProgress
58
+ (isInProgress || (!isInProgress && text.trim().length > 0)) &&
59
+ pushToTalkState === "idle" &&
60
+ !interruptInProgress
60
61
  );
61
62
  };
62
63
 
63
64
  const sendDisabled = !canSend();
64
65
 
65
66
  return (
66
- <div className="copilotKitInput" onClick={handleDivClick}>
67
- <AutoResizingTextarea
68
- ref={textareaRef}
69
- placeholder={context.labels.placeholder}
70
- autoFocus={true}
71
- maxRows={5}
72
- value={text}
73
- onChange={(event) => setText(event.target.value)}
74
- onKeyDown={(event) => {
75
- if (event.key === "Enter" && !event.shiftKey) {
76
- event.preventDefault();
77
- if (canSend()) {
78
- send();
67
+ <div className="copilotKitInputContainer">
68
+ <div className="copilotKitInput" onClick={handleDivClick}>
69
+ <AutoResizingTextarea
70
+ ref={textareaRef}
71
+ placeholder={context.labels.placeholder}
72
+ autoFocus={true}
73
+ maxRows={5}
74
+ value={text}
75
+ onChange={(event) => setText(event.target.value)}
76
+ onKeyDown={(event) => {
77
+ if (event.key === "Enter" && !event.shiftKey) {
78
+ event.preventDefault();
79
+ if (canSend()) {
80
+ send();
81
+ }
79
82
  }
80
- }
81
- }}
82
- />
83
- <div className="copilotKitInputControls">
84
- {showPushToTalk && (
83
+ }}
84
+ />
85
+ <div className="copilotKitInputControls">
86
+ <div style={{ flexGrow: 1 }} />
87
+ {showPushToTalk && (
88
+ <button
89
+ onClick={() =>
90
+ setPushToTalkState(pushToTalkState === "idle" ? "recording" : "transcribing")
91
+ }
92
+ className={pushToTalkState === "recording" ? "copilotKitPushToTalkRecording" : ""}
93
+ >
94
+ {context.icons.pushToTalkIcon}
95
+ </button>
96
+ )}
85
97
  <button
86
- onClick={() =>
87
- setPushToTalkState(pushToTalkState === "idle" ? "recording" : "transcribing")
88
- }
89
- className={pushToTalkState === "recording" ? "copilotKitPushToTalkRecording" : ""}
98
+ disabled={sendDisabled}
99
+ onClick={isInProgress ? onStop : send}
100
+ data-copilotkit-in-progress={inProgress}
101
+ data-test-id={inProgress ? "copilot-chat-request-in-progress" : "copilot-chat-ready"}
90
102
  >
91
- {context.icons.pushToTalkIcon}
103
+ {buttonIcon}
92
104
  </button>
93
- )}
94
- <button
95
- disabled={sendDisabled}
96
- onClick={send}
97
- data-copilotkit-in-progress={!!inProgress}
98
- data-testid={inProgress ? "copilot-chat-request-in-progress" : undefined}
99
- >
100
- {sendIcon}
101
- </button>
105
+ </div>
102
106
  </div>
103
107
  </div>
104
108
  );
@@ -25,9 +25,6 @@ export const Markdown = ({ content }: MarkdownProps) => {
25
25
  };
26
26
 
27
27
  const components: Components = {
28
- p({ children }) {
29
- return <p>{children}</p>;
30
- },
31
28
  a({ children, ...props }) {
32
29
  return (
33
30
  <a
@@ -14,6 +14,10 @@ export const Messages = ({
14
14
  RenderResultMessage,
15
15
  AssistantMessage,
16
16
  UserMessage,
17
+ onRegenerate,
18
+ onCopy,
19
+ onThumbsUp,
20
+ onThumbsDown,
17
21
  }: MessagesProps) => {
18
22
  const context = useChatContext();
19
23
  const initialMessages = useMemo(
@@ -44,62 +48,70 @@ export const Messages = ({
44
48
 
45
49
  return (
46
50
  <div className="copilotKitMessages" ref={messagesContainerRef}>
47
- {messages.map((message, index) => {
48
- const isCurrentMessage = index === messages.length - 1;
49
-
50
- if (message.isTextMessage()) {
51
- return (
52
- <RenderTextMessage
53
- key={index}
54
- message={message}
55
- inProgress={inProgress}
56
- index={index}
57
- isCurrentMessage={isCurrentMessage}
58
- AssistantMessage={AssistantMessage}
59
- UserMessage={UserMessage}
60
- />
61
- );
62
- } else if (message.isActionExecutionMessage()) {
63
- return (
64
- <RenderActionExecutionMessage
65
- key={index}
66
- message={message}
67
- inProgress={inProgress}
68
- index={index}
69
- isCurrentMessage={isCurrentMessage}
70
- actionResult={actionResults[message.id]}
71
- AssistantMessage={AssistantMessage}
72
- UserMessage={UserMessage}
73
- />
74
- );
75
- } else if (message.isAgentStateMessage()) {
76
- return (
77
- <RenderAgentStateMessage
78
- key={index}
79
- message={message}
80
- inProgress={inProgress}
81
- index={index}
82
- isCurrentMessage={isCurrentMessage}
83
- AssistantMessage={AssistantMessage}
84
- UserMessage={UserMessage}
85
- />
86
- );
87
- } else if (message.isResultMessage()) {
88
- return (
89
- <RenderResultMessage
90
- key={index}
91
- message={message}
92
- inProgress={inProgress}
93
- index={index}
94
- isCurrentMessage={isCurrentMessage}
95
- AssistantMessage={AssistantMessage}
96
- UserMessage={UserMessage}
97
- />
98
- );
99
- }
100
- })}
101
- {interrupt}
102
- <footer ref={messagesEndRef}>{children}</footer>
51
+ <div className="copilotKitMessagesContainer">
52
+ {messages.map((message, index) => {
53
+ const isCurrentMessage = index === messages.length - 1;
54
+
55
+ if (message.isTextMessage()) {
56
+ return (
57
+ <RenderTextMessage
58
+ key={index}
59
+ message={message}
60
+ inProgress={inProgress}
61
+ index={index}
62
+ isCurrentMessage={isCurrentMessage}
63
+ AssistantMessage={AssistantMessage}
64
+ UserMessage={UserMessage}
65
+ onRegenerate={onRegenerate}
66
+ onCopy={onCopy}
67
+ onThumbsUp={onThumbsUp}
68
+ onThumbsDown={onThumbsDown}
69
+ />
70
+ );
71
+ } else if (message.isActionExecutionMessage()) {
72
+ return (
73
+ <RenderActionExecutionMessage
74
+ key={index}
75
+ message={message}
76
+ inProgress={inProgress}
77
+ index={index}
78
+ isCurrentMessage={isCurrentMessage}
79
+ actionResult={actionResults[message.id]}
80
+ AssistantMessage={AssistantMessage}
81
+ UserMessage={UserMessage}
82
+ />
83
+ );
84
+ } else if (message.isAgentStateMessage()) {
85
+ return (
86
+ <RenderAgentStateMessage
87
+ key={index}
88
+ message={message}
89
+ inProgress={inProgress}
90
+ index={index}
91
+ isCurrentMessage={isCurrentMessage}
92
+ AssistantMessage={AssistantMessage}
93
+ UserMessage={UserMessage}
94
+ />
95
+ );
96
+ } else if (message.isResultMessage()) {
97
+ return (
98
+ <RenderResultMessage
99
+ key={index}
100
+ message={message}
101
+ inProgress={inProgress}
102
+ index={index}
103
+ isCurrentMessage={isCurrentMessage}
104
+ AssistantMessage={AssistantMessage}
105
+ UserMessage={UserMessage}
106
+ />
107
+ );
108
+ }
109
+ })}
110
+ {interrupt}
111
+ </div>
112
+ <footer className="copilotKitMessagesFooter" ref={messagesEndRef}>
113
+ {children}
114
+ </footer>
103
115
  </div>
104
116
  );
105
117
  };
@@ -18,11 +18,10 @@ export function Suggestion({ title, message, onClick, partial, className }: Sugg
18
18
  e.preventDefault();
19
19
  onClick(message);
20
20
  }}
21
- className={className || "suggestion"}
21
+ className={className || (partial ? "suggestion loading" : "suggestion")}
22
22
  data-test-id="suggestion"
23
23
  >
24
- {partial && SmallSpinnerIcon}
25
- <span>{title}</span>
24
+ {partial ? SmallSpinnerIcon : <span>{title}</span>}
26
25
  </button>
27
26
  );
28
27
  }
@@ -1,17 +1,109 @@
1
1
  import { AssistantMessageProps } from "../props";
2
2
  import { useChatContext } from "../ChatContext";
3
3
  import { Markdown } from "../Markdown";
4
+ import { RegenerateIcon, CopyIcon, ThumbsUpIcon, ThumbsDownIcon } from "../Icons";
5
+ import { useState } from "react";
4
6
 
5
7
  export const AssistantMessage = (props: AssistantMessageProps) => {
6
- const { icons } = useChatContext();
7
- const { message, isLoading, subComponent } = props;
8
+ const { icons, labels } = useChatContext();
9
+ const {
10
+ message,
11
+ isLoading,
12
+ subComponent,
13
+ onRegenerate,
14
+ onCopy,
15
+ onThumbsUp,
16
+ onThumbsDown,
17
+ isCurrentMessage,
18
+ } = props;
19
+ const [copied, setCopied] = useState(false);
20
+
21
+ const handleCopy = () => {
22
+ if (message && onCopy) {
23
+ navigator.clipboard.writeText(message);
24
+ setCopied(true);
25
+ onCopy(message);
26
+ setTimeout(() => setCopied(false), 2000);
27
+ } else if (message) {
28
+ navigator.clipboard.writeText(message);
29
+ setCopied(true);
30
+ setTimeout(() => setCopied(false), 2000);
31
+ }
32
+ };
33
+
34
+ const handleRegenerate = () => {
35
+ if (onRegenerate) {
36
+ onRegenerate();
37
+ }
38
+ };
39
+
40
+ const handleThumbsUp = () => {
41
+ if (onThumbsUp && message) {
42
+ onThumbsUp(message);
43
+ }
44
+ };
45
+
46
+ const handleThumbsDown = () => {
47
+ if (onThumbsDown && message) {
48
+ onThumbsDown(message);
49
+ }
50
+ };
51
+
52
+ const LoadingIcon = () => <span>{icons.activityIcon}</span>;
8
53
 
9
54
  return (
10
55
  <>
11
56
  {(message || isLoading) && (
12
57
  <div className="copilotKitMessage copilotKitAssistantMessage">
13
58
  {message && <Markdown content={message || ""} />}
14
- {isLoading && icons.spinnerIcon}
59
+ {isLoading && <LoadingIcon />}
60
+
61
+ {message && !isLoading && (
62
+ <div
63
+ className={`copilotKitMessageControls ${isCurrentMessage ? "currentMessage" : ""}`}
64
+ >
65
+ <button
66
+ className="copilotKitMessageControlButton"
67
+ onClick={handleRegenerate}
68
+ aria-label={labels.regenerateResponse}
69
+ title={labels.regenerateResponse}
70
+ >
71
+ {RegenerateIcon}
72
+ </button>
73
+ <button
74
+ className="copilotKitMessageControlButton"
75
+ onClick={handleCopy}
76
+ aria-label={labels.copyToClipboard}
77
+ title={labels.copyToClipboard}
78
+ >
79
+ {copied ? (
80
+ <span style={{ fontSize: "10px", fontWeight: "bold" }}>✓</span>
81
+ ) : (
82
+ CopyIcon
83
+ )}
84
+ </button>
85
+ {onThumbsUp && (
86
+ <button
87
+ className="copilotKitMessageControlButton"
88
+ onClick={handleThumbsUp}
89
+ aria-label={labels.thumbsUp}
90
+ title={labels.thumbsUp}
91
+ >
92
+ {ThumbsUpIcon}
93
+ </button>
94
+ )}
95
+ {onThumbsDown && (
96
+ <button
97
+ className="copilotKitMessageControlButton"
98
+ onClick={handleThumbsDown}
99
+ aria-label={labels.thumbsDown}
100
+ title={labels.thumbsDown}
101
+ >
102
+ {ThumbsDownIcon}
103
+ </button>
104
+ )}
105
+ </div>
106
+ )}
15
107
  </div>
16
108
  )}
17
109
  <div style={{ marginBottom: "0.5rem" }}>{subComponent}</div>
@@ -1,7 +1,18 @@
1
1
  import { RenderMessageProps } from "../props";
2
2
 
3
3
  export function RenderTextMessage(props: RenderMessageProps) {
4
- const { message, inProgress, index, isCurrentMessage, UserMessage, AssistantMessage } = props;
4
+ const {
5
+ message,
6
+ inProgress,
7
+ index,
8
+ isCurrentMessage,
9
+ UserMessage,
10
+ AssistantMessage,
11
+ onRegenerate,
12
+ onCopy,
13
+ onThumbsUp,
14
+ onThumbsDown,
15
+ } = props;
5
16
 
6
17
  if (message.isTextMessage()) {
7
18
  if (message.role === "user") {
@@ -22,6 +33,11 @@ export function RenderTextMessage(props: RenderMessageProps) {
22
33
  rawData={message}
23
34
  isLoading={inProgress && isCurrentMessage && !message.content}
24
35
  isGenerating={inProgress && isCurrentMessage && !!message.content}
36
+ isCurrentMessage={isCurrentMessage}
37
+ onRegenerate={onRegenerate}
38
+ onCopy={onCopy}
39
+ onThumbsUp={onThumbsUp}
40
+ onThumbsDown={onThumbsDown}
25
41
  />
26
42
  );
27
43
  }
@@ -29,6 +29,26 @@ export interface MessagesProps {
29
29
  RenderActionExecutionMessage: React.ComponentType<RenderMessageProps>;
30
30
  RenderAgentStateMessage: React.ComponentType<RenderMessageProps>;
31
31
  RenderResultMessage: React.ComponentType<RenderMessageProps>;
32
+
33
+ /**
34
+ * Callback function to regenerate the assistant's response
35
+ */
36
+ onRegenerate?: () => void;
37
+
38
+ /**
39
+ * Callback function when the message is copied
40
+ */
41
+ onCopy?: (message: string) => void;
42
+
43
+ /**
44
+ * Callback function for thumbs up feedback
45
+ */
46
+ onThumbsUp?: (message: string) => void;
47
+
48
+ /**
49
+ * Callback function for thumbs down feedback
50
+ */
51
+ onThumbsDown?: (message: string) => void;
32
52
  }
33
53
 
34
54
  export interface Renderer {
@@ -47,6 +67,11 @@ export interface AssistantMessageProps {
47
67
 
48
68
  message?: string;
49
69
 
70
+ /**
71
+ * Indicates if this is the last message
72
+ */
73
+ isCurrentMessage?: boolean;
74
+
50
75
  /**
51
76
  * The raw data from the assistant's response
52
77
  */
@@ -68,6 +93,26 @@ export interface AssistantMessageProps {
68
93
  * Whether a response is generating, this is when the LLM is actively generating and streaming content.
69
94
  */
70
95
  isGenerating: boolean;
96
+
97
+ /**
98
+ * Callback function to regenerate the assistant's response
99
+ */
100
+ onRegenerate?: () => void;
101
+
102
+ /**
103
+ * Callback function when the message is copied
104
+ */
105
+ onCopy?: (message: string) => void;
106
+
107
+ /**
108
+ * Callback function for thumbs up feedback
109
+ */
110
+ onThumbsUp?: (message: string) => void;
111
+
112
+ /**
113
+ * Callback function for thumbs down feedback
114
+ */
115
+ onThumbsDown?: (message: string) => void;
71
116
  }
72
117
 
73
118
  export interface RenderMessageProps {
@@ -78,12 +123,33 @@ export interface RenderMessageProps {
78
123
  actionResult?: string;
79
124
  AssistantMessage: React.ComponentType<AssistantMessageProps>;
80
125
  UserMessage: React.ComponentType<UserMessageProps>;
126
+
127
+ /**
128
+ * Callback function to regenerate the assistant's response
129
+ */
130
+ onRegenerate?: () => void;
131
+
132
+ /**
133
+ * Callback function when the message is copied
134
+ */
135
+ onCopy?: (message: string) => void;
136
+
137
+ /**
138
+ * Callback function for thumbs up feedback
139
+ */
140
+ onThumbsUp?: (message: string) => void;
141
+
142
+ /**
143
+ * Callback function for thumbs down feedback
144
+ */
145
+ onThumbsDown?: (message: string) => void;
81
146
  }
82
147
 
83
148
  export interface InputProps {
84
149
  inProgress: boolean;
85
150
  onSend: (text: string) => Promise<Message>;
86
151
  isVisible?: boolean;
152
+ onStop?: () => void;
87
153
  }
88
154
 
89
155
  export interface ResponseButtonProps {