@copilotkit/react-ui 1.7.2-next.2 → 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 (161) hide show
  1. package/CHANGELOG.md +12 -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-QXQDIFOC.mjs → chunk-5GNYGURH.mjs} +48 -37
  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-FBYETUFL.mjs +118 -0
  12. package/dist/chunk-FBYETUFL.mjs.map +1 -0
  13. package/dist/chunk-GDJAAFIK.mjs +24 -0
  14. package/dist/chunk-GDJAAFIK.mjs.map +1 -0
  15. package/dist/{chunk-6FTRYYR5.mjs → chunk-GJME6MK4.mjs} +72 -62
  16. package/dist/chunk-GJME6MK4.mjs.map +1 -0
  17. package/dist/{chunk-AELKLZSG.mjs → chunk-KG6DW6R2.mjs} +10 -10
  18. package/dist/{chunk-DLG7BZTA.mjs → chunk-LKCAF2HG.mjs} +2 -2
  19. package/dist/{chunk-R2O33F44.mjs → chunk-LXCH2BIB.mjs} +2 -2
  20. package/dist/chunk-ORSMX3SE.mjs +244 -0
  21. package/dist/chunk-ORSMX3SE.mjs.map +1 -0
  22. package/dist/{chunk-UPTB2MVO.mjs → chunk-PCTCOQK2.mjs} +4 -10
  23. package/dist/chunk-PCTCOQK2.mjs.map +1 -0
  24. package/dist/{chunk-ZIF5JJCH.mjs → chunk-QGK5GOSC.mjs} +24 -53
  25. package/dist/chunk-QGK5GOSC.mjs.map +1 -0
  26. package/dist/{chunk-WGAZXTUA.mjs → chunk-TOQ7P4DO.mjs} +6 -9
  27. package/dist/chunk-TOQ7P4DO.mjs.map +1 -0
  28. package/dist/{chunk-3XAXY2Z3.mjs → chunk-UZTZXMYS.mjs} +2 -2
  29. package/dist/{chunk-RQNJNK2W.mjs → chunk-VC4NO5QZ.mjs} +2 -2
  30. package/dist/{chunk-YQ3D5IQV.mjs → chunk-XNQO5AZZ.mjs} +2 -5
  31. package/dist/chunk-XNQO5AZZ.mjs.map +1 -0
  32. package/dist/chunk-YC4NBUGE.mjs +97 -0
  33. package/dist/chunk-YC4NBUGE.mjs.map +1 -0
  34. package/dist/components/chat/Button.js.map +1 -1
  35. package/dist/components/chat/Button.mjs +3 -3
  36. package/dist/components/chat/Chat.d.ts +17 -1
  37. package/dist/components/chat/Chat.js +378 -905
  38. package/dist/components/chat/Chat.js.map +1 -1
  39. package/dist/components/chat/Chat.mjs +11 -18
  40. package/dist/components/chat/ChatContext.d.ts +20 -0
  41. package/dist/components/chat/ChatContext.js +44 -74
  42. package/dist/components/chat/ChatContext.js.map +1 -1
  43. package/dist/components/chat/ChatContext.mjs +2 -2
  44. package/dist/components/chat/CodeBlock.js +58 -82
  45. package/dist/components/chat/CodeBlock.js.map +1 -1
  46. package/dist/components/chat/CodeBlock.mjs +2 -2
  47. package/dist/components/chat/Header.js +516 -4
  48. package/dist/components/chat/Header.js.map +1 -1
  49. package/dist/components/chat/Header.mjs +10 -3
  50. package/dist/components/chat/Icons.d.ts +10 -9
  51. package/dist/components/chat/Icons.js +125 -164
  52. package/dist/components/chat/Icons.js.map +1 -1
  53. package/dist/components/chat/Icons.mjs +9 -5
  54. package/dist/components/chat/Input.d.ts +1 -1
  55. package/dist/components/chat/Input.js +11 -9
  56. package/dist/components/chat/Input.js.map +1 -1
  57. package/dist/components/chat/Input.mjs +3 -3
  58. package/dist/components/chat/Markdown.js +58 -56
  59. package/dist/components/chat/Markdown.js.map +1 -1
  60. package/dist/components/chat/Markdown.mjs +3 -3
  61. package/dist/components/chat/Messages.d.ts +1 -1
  62. package/dist/components/chat/Messages.js +70 -60
  63. package/dist/components/chat/Messages.js.map +1 -1
  64. package/dist/components/chat/Messages.mjs +3 -3
  65. package/dist/components/chat/Modal.js +1708 -1749
  66. package/dist/components/chat/Modal.js.map +1 -1
  67. package/dist/components/chat/Modal.mjs +21 -21
  68. package/dist/components/chat/Popup.js +1708 -1749
  69. package/dist/components/chat/Popup.js.map +1 -1
  70. package/dist/components/chat/Popup.mjs +22 -22
  71. package/dist/components/chat/Response.js.map +1 -1
  72. package/dist/components/chat/Response.mjs +3 -3
  73. package/dist/components/chat/Sidebar.js +1710 -1751
  74. package/dist/components/chat/Sidebar.js.map +1 -1
  75. package/dist/components/chat/Sidebar.mjs +22 -22
  76. package/dist/components/chat/Suggestion.js +4 -40
  77. package/dist/components/chat/Suggestion.js.map +1 -1
  78. package/dist/components/chat/Suggestion.mjs +2 -2
  79. package/dist/components/chat/Window.js.map +1 -1
  80. package/dist/components/chat/Window.mjs +3 -3
  81. package/dist/components/chat/index.js +1710 -1751
  82. package/dist/components/chat/index.js.map +1 -1
  83. package/dist/components/chat/index.mjs +24 -24
  84. package/dist/components/chat/messages/AssistantMessage.js +211 -59
  85. package/dist/components/chat/messages/AssistantMessage.js.map +1 -1
  86. package/dist/components/chat/messages/AssistantMessage.mjs +5 -5
  87. package/dist/components/chat/messages/RenderTextMessage.js +18 -2
  88. package/dist/components/chat/messages/RenderTextMessage.js.map +1 -1
  89. package/dist/components/chat/messages/RenderTextMessage.mjs +1 -1
  90. package/dist/components/chat/props.d.ts +53 -0
  91. package/dist/components/chat/props.js.map +1 -1
  92. package/dist/components/dev-console/console.js +51 -233
  93. package/dist/components/dev-console/console.js.map +1 -1
  94. package/dist/components/dev-console/console.mjs +3 -3
  95. package/dist/components/dev-console/index.js +51 -233
  96. package/dist/components/dev-console/index.js.map +1 -1
  97. package/dist/components/dev-console/index.mjs +3 -3
  98. package/dist/components/help-modal/index.js +29 -147
  99. package/dist/components/help-modal/index.js.map +1 -1
  100. package/dist/components/help-modal/index.mjs +1 -1
  101. package/dist/components/help-modal/modal.js +29 -147
  102. package/dist/components/help-modal/modal.js.map +1 -1
  103. package/dist/components/help-modal/modal.mjs +1 -1
  104. package/dist/components/index.js +1683 -1724
  105. package/dist/components/index.js.map +1 -1
  106. package/dist/components/index.mjs +28 -28
  107. package/dist/index.css +254 -90
  108. package/dist/index.css.map +1 -1
  109. package/dist/index.js +1692 -1733
  110. package/dist/index.js.map +1 -1
  111. package/dist/index.mjs +28 -28
  112. package/dist/types/css.d.ts +7 -1
  113. package/dist/types/css.js.map +1 -1
  114. package/package.json +4 -4
  115. package/src/components/chat/Chat.tsx +59 -22
  116. package/src/components/chat/ChatContext.tsx +29 -1
  117. package/src/components/chat/CodeBlock.tsx +2 -4
  118. package/src/components/chat/Header.tsx +8 -3
  119. package/src/components/chat/Icons.tsx +108 -108
  120. package/src/components/chat/Input.tsx +42 -38
  121. package/src/components/chat/Markdown.tsx +0 -3
  122. package/src/components/chat/Messages.tsx +68 -56
  123. package/src/components/chat/Suggestion.tsx +2 -3
  124. package/src/components/chat/messages/AssistantMessage.tsx +95 -3
  125. package/src/components/chat/messages/RenderTextMessage.tsx +17 -1
  126. package/src/components/chat/props.ts +66 -0
  127. package/src/components/dev-console/console.tsx +16 -54
  128. package/src/components/help-modal/modal.tsx +38 -101
  129. package/src/css/button.css +15 -4
  130. package/src/css/colors.css +27 -6
  131. package/src/css/console.css +46 -39
  132. package/src/css/header.css +22 -5
  133. package/src/css/input.css +24 -17
  134. package/src/css/markdown.css +2 -1
  135. package/src/css/messages.css +125 -15
  136. package/src/css/panel.css +1 -0
  137. package/src/css/suggestions.css +14 -6
  138. package/src/types/css.ts +7 -1
  139. package/dist/chunk-3VNMQWGT.mjs +0 -25
  140. package/dist/chunk-3VNMQWGT.mjs.map +0 -1
  141. package/dist/chunk-6FTRYYR5.mjs.map +0 -1
  142. package/dist/chunk-CBBFRI3Q.mjs.map +0 -1
  143. package/dist/chunk-FZC7X5PK.mjs +0 -262
  144. package/dist/chunk-FZC7X5PK.mjs.map +0 -1
  145. package/dist/chunk-OFYI4UU4.mjs.map +0 -1
  146. package/dist/chunk-QXQDIFOC.mjs.map +0 -1
  147. package/dist/chunk-QXTRFMPM.mjs.map +0 -1
  148. package/dist/chunk-TI7SY2RI.mjs +0 -164
  149. package/dist/chunk-TI7SY2RI.mjs.map +0 -1
  150. package/dist/chunk-UPTB2MVO.mjs.map +0 -1
  151. package/dist/chunk-VEC45H6Q.mjs +0 -18
  152. package/dist/chunk-VEC45H6Q.mjs.map +0 -1
  153. package/dist/chunk-WGAZXTUA.mjs.map +0 -1
  154. package/dist/chunk-YQ3D5IQV.mjs.map +0 -1
  155. package/dist/chunk-ZIF5JJCH.mjs.map +0 -1
  156. /package/dist/{chunk-YAGE7RCE.mjs.map → chunk-CGVOCLHN.mjs.map} +0 -0
  157. /package/dist/{chunk-AELKLZSG.mjs.map → chunk-KG6DW6R2.mjs.map} +0 -0
  158. /package/dist/{chunk-DLG7BZTA.mjs.map → chunk-LKCAF2HG.mjs.map} +0 -0
  159. /package/dist/{chunk-R2O33F44.mjs.map → chunk-LXCH2BIB.mjs.map} +0 -0
  160. /package/dist/{chunk-3XAXY2Z3.mjs.map → chunk-UZTZXMYS.mjs.map} +0 -0
  161. /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 {
@@ -82,39 +82,6 @@ export function CopilotDevConsole() {
82
82
  checkForUpdates();
83
83
  }, []);
84
84
 
85
- useEffect(() => {
86
- const handleResize = (entries: ResizeObserverEntry[]) => {
87
- for (let entry of entries) {
88
- if (entry.target === consoleRef.current) {
89
- const width = entry.contentRect.width;
90
- if (width < 400) {
91
- setDebugButtonMode("compact");
92
- } else {
93
- setDebugButtonMode("full");
94
- }
95
- }
96
- }
97
- };
98
-
99
- const observer = new ResizeObserver(handleResize);
100
- if (consoleRef.current) {
101
- observer.observe(consoleRef.current);
102
-
103
- const initialWidth = consoleRef.current.getBoundingClientRect().width;
104
- if (initialWidth < 400) {
105
- setDebugButtonMode("compact");
106
- } else {
107
- setDebugButtonMode("full");
108
- }
109
- }
110
-
111
- return () => {
112
- if (consoleRef.current) {
113
- observer.unobserve(consoleRef.current);
114
- }
115
- };
116
- }, [consoleRef.current]);
117
-
118
85
  if (!showDevConsole) {
119
86
  return null;
120
87
  }
@@ -127,11 +94,6 @@ export function CopilotDevConsole() {
127
94
  (versionStatus === "outdated" ? "copilotKitDevConsoleWarnOutdated" : "")
128
95
  }
129
96
  >
130
- <div className="copilotKitDevConsoleLogo">
131
- <a href="https://copilotkit.ai" target="_blank">
132
- {CopilotKitIcon}
133
- </a>
134
- </div>
135
97
  <VersionInfo
136
98
  showDevConsole={context.showDevConsole}
137
99
  versionStatus={versionStatus}
@@ -205,22 +167,20 @@ function VersionInfo({
205
167
  });
206
168
  };
207
169
 
208
- return (
209
- <div className="copilotKitVersionInfo">
210
- <header>
211
- COPILOTKIT DEV CONSOLE{showDevConsole === "auto" && <aside>{asideLabel}</aside>}
212
- </header>
213
- <section>
214
- Version: {versionLabel} ({currentVersionLabel}) {versionIcon}
215
- </section>
216
- {(versionStatus === "update-available" || versionStatus === "outdated") && (
217
- <footer>
218
- <button onClick={handleCopyClick}>{copyStatus || installCommand}</button>
219
- </footer>
220
- )}
221
- </div>
222
- );
170
+ if (versionStatus === "update-available" || versionStatus === "outdated") {
171
+ return (
172
+ <div className="copilotKitVersionInfo">
173
+ <p>
174
+ {currentVersionLabel} {versionIcon}
175
+ </p>
176
+ <button onClick={handleCopyClick}>{copyStatus || installCommand}</button>
177
+ </div>
178
+ );
179
+ }
180
+
181
+ return null;
223
182
  }
183
+
224
184
  export default function DebugMenuButton({
225
185
  setShowDevConsole,
226
186
  checkForUpdates,
@@ -236,7 +196,9 @@ export default function DebugMenuButton({
236
196
  return (
237
197
  <div className="bg-black top-24 w-52 text-right">
238
198
  <Menu>
239
- <MenuButton className={`copilotKitDebugMenuButton ${mode === "compact" ? "compact" : ""}`}>
199
+ <MenuButton
200
+ className={`copilotKitDebugMenuTriggerButton ${mode === "compact" ? "compact" : ""}`}
201
+ >
240
202
  {mode == "compact" ? "Debug" : <>Debug {ChevronDownIcon}</>}
241
203
  </MenuButton>
242
204