Skip to content

Commit 20f0727

Browse files
authored
feat: chat interface redesign (CopilotKit#1419)
1 parent a3891bb commit 20f0727

35 files changed

Lines changed: 904 additions & 509 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@copilotkit/react-ui": minor
3+
---
4+
5+
- feat(chat): redesign chat
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
@tailwind base;
22
@tailwind components;
33
@tailwind utilities;
4+
5+
.copilotKitHeader {
6+
--copilot-kit-primary-color: rgb(255, 255, 255);
7+
--copilot-kit-contrast-color: rgb(28, 28, 28);
8+
}

CopilotKit/packages/react-ui/src/components/chat/Chat.tsx

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,26 @@ export interface CopilotChatProps {
118118
*/
119119
onReloadMessages?: OnReloadMessages;
120120

121+
/**
122+
* A callback function to regenerate the assistant's response
123+
*/
124+
onRegenerate?: () => void;
125+
126+
/**
127+
* A callback function when the message is copied
128+
*/
129+
onCopy?: (message: string) => void;
130+
131+
/**
132+
* A callback function for thumbs up feedback
133+
*/
134+
onThumbsUp?: (message: string) => void;
135+
136+
/**
137+
* A callback function for thumbs down feedback
138+
*/
139+
onThumbsDown?: (message: string) => void;
140+
121141
/**
122142
* Icons can be used to set custom icons for the chat window.
123143
*/
@@ -254,6 +274,10 @@ export function CopilotChat({
254274
onInProgress,
255275
onStopGeneration,
256276
onReloadMessages,
277+
onRegenerate,
278+
onCopy,
279+
onThumbsUp,
280+
onThumbsDown,
257281
Messages = DefaultMessages,
258282
RenderTextMessage = DefaultRenderTextMessage,
259283
RenderActionExecutionMessage = DefaultRenderActionExecutionMessage,
@@ -312,9 +336,22 @@ export function CopilotChat({
312336
const chatContext = React.useContext(ChatContext);
313337
const isVisible = chatContext ? chatContext.open : true;
314338

339+
const handleRegenerate = () => {
340+
if (onRegenerate) {
341+
onRegenerate();
342+
}
343+
344+
reloadMessages();
345+
};
346+
347+
const handleCopy = (message: string) => {
348+
if (onCopy) {
349+
onCopy(message);
350+
}
351+
};
352+
315353
return (
316354
<WrappedCopilotChat icons={icons} labels={labels} className={className}>
317-
<CopilotDevConsole />
318355
<Messages
319356
AssistantMessage={AssistantMessage}
320357
UserMessage={UserMessage}
@@ -324,32 +361,32 @@ export function CopilotChat({
324361
RenderResultMessage={RenderResultMessage}
325362
messages={visibleMessages}
326363
inProgress={isLoading}
364+
onRegenerate={handleRegenerate}
365+
onCopy={handleCopy}
366+
onThumbsUp={onThumbsUp}
367+
onThumbsDown={onThumbsDown}
327368
>
328369
{currentSuggestions.length > 0 && (
329-
<div>
330-
<h6>Suggested:</h6>
331-
<div className="suggestions">
332-
{currentSuggestions.map((suggestion, index) => (
333-
<Suggestion
334-
key={index}
335-
title={suggestion.title}
336-
message={suggestion.message}
337-
partial={suggestion.partial}
338-
className={suggestion.className}
339-
onClick={(message) => sendMessage(message)}
340-
/>
341-
))}
342-
</div>
370+
<div className="suggestions">
371+
{currentSuggestions.map((suggestion, index) => (
372+
<Suggestion
373+
key={index}
374+
title={suggestion.title}
375+
message={suggestion.message}
376+
partial={suggestion.partial}
377+
className={suggestion.className}
378+
onClick={(message) => sendMessage(message)}
379+
/>
380+
))}
343381
</div>
344382
)}
345-
{showResponseButton && visibleMessages.length > 0 && (
346-
<ResponseButton
347-
onClick={isLoading ? stopGeneration : reloadMessages}
348-
inProgress={isLoading}
349-
/>
350-
)}
351383
</Messages>
352-
<Input inProgress={isLoading} onSend={sendMessage} isVisible={isVisible} />
384+
<Input
385+
inProgress={isLoading}
386+
onSend={sendMessage}
387+
isVisible={isVisible}
388+
onStop={stopGeneration}
389+
/>
353390
</WrappedCopilotChat>
354391
);
355392
}

CopilotKit/packages/react-ui/src/components/chat/ChatContext.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,30 @@ export interface CopilotChatLabels {
9999
* @default "Regenerate response"
100100
*/
101101
regenerateResponse?: string;
102+
103+
/**
104+
* The label for the copy button.
105+
* @default "Copy to clipboard"
106+
*/
107+
copyToClipboard?: string;
108+
109+
/**
110+
* The label for the thumbs up button.
111+
* @default "Thumbs up"
112+
*/
113+
thumbsUp?: string;
114+
115+
/**
116+
* The label for the thumbs down button.
117+
* @default "Thumbs down"
118+
*/
119+
thumbsDown?: string;
120+
121+
/**
122+
* The text to display when content is copied.
123+
* @default "Copied!"
124+
*/
125+
copied?: string;
102126
}
103127

104128
interface ChatContext {
@@ -150,6 +174,10 @@ export const ChatContextProvider = ({
150174
error: "❌ An error occurred. Please try again.",
151175
stopGenerating: "Stop generating",
152176
regenerateResponse: "Regenerate response",
177+
copyToClipboard: "Copy to clipboard",
178+
thumbsUp: "Thumbs up",
179+
thumbsDown: "Thumbs down",
180+
copied: "Copied!",
153181
},
154182
...labels,
155183
}),
@@ -167,7 +195,7 @@ export const ChatContextProvider = ({
167195
spinnerIcon: DefaultIcons.SpinnerIcon,
168196
stopIcon: DefaultIcons.StopIcon,
169197
regenerateIcon: DefaultIcons.RegenerateIcon,
170-
pushToTalkIcon: DefaultIcons.PushToTalkIcon,
198+
pushToTalkIcon: DefaultIcons.MicrophoneIcon,
171199
},
172200
...icons,
173201
}),

CopilotKit/packages/react-ui/src/components/chat/CodeBlock.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,10 @@ const CodeBlock: FC<Props> = memo(({ language, value }) => {
9292
<span className="copilotKitCodeBlockToolbarLanguage">{language}</span>
9393
<div className="copilotKitCodeBlockToolbarButtons">
9494
<button className="copilotKitCodeBlockToolbarButton" onClick={downloadAsFile}>
95-
<DownloadIcon />
96-
<span className="sr-only">Download</span>
95+
{DownloadIcon}
9796
</button>
9897
<button className="copilotKitCodeBlockToolbarButton" onClick={onCopy}>
99-
{isCopied ? <CheckIcon /> : <CopyIcon />}
100-
<span className="sr-only">Copy code</span>
98+
{isCopied ? CheckIcon : CopyIcon}
10199
</button>
102100
</div>
103101
</div>
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import { HeaderProps } from "./props";
22
import { useChatContext } from "./ChatContext";
3+
import { CopilotDevConsole } from "../dev-console";
4+
import React from "react";
35

46
export const Header = ({}: HeaderProps) => {
57
const { setOpen, icons, labels } = useChatContext();
68

79
return (
810
<div className="copilotKitHeader">
911
<div>{labels.title}</div>
10-
<button onClick={() => setOpen(false)} aria-label="Close">
11-
{icons.headerCloseIcon}
12-
</button>
12+
<div className="copilotKitHeaderControls">
13+
<CopilotDevConsole />
14+
<button onClick={() => setOpen(false)} aria-label="Close">
15+
{icons.headerCloseIcon}
16+
</button>
17+
</div>
1318
</div>
1419
);
1520
};

0 commit comments

Comments
 (0)