@copilotkit/react-ui 0.14.1 → 0.15.0-alpha.1
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.
- package/.turbo/turbo-build.log +279 -196
- package/CHANGELOG.md +22 -0
- package/dist/chunk-47SYBLI2.mjs +110 -0
- package/dist/chunk-47SYBLI2.mjs.map +1 -0
- package/dist/chunk-6H3Y2XEI.mjs +56 -0
- package/dist/chunk-6H3Y2XEI.mjs.map +1 -0
- package/dist/chunk-7YXG7D47.mjs +191 -0
- package/dist/chunk-7YXG7D47.mjs.map +1 -0
- package/dist/chunk-DN3OI5WF.mjs +72 -0
- package/dist/chunk-DN3OI5WF.mjs.map +1 -0
- package/dist/chunk-DPUPEOGG.mjs +14 -0
- package/dist/chunk-DPUPEOGG.mjs.map +1 -0
- package/dist/chunk-FZRTAML3.mjs +3 -0
- package/dist/chunk-GPEJCUWA.mjs +14 -0
- package/dist/chunk-GPEJCUWA.mjs.map +1 -0
- package/dist/chunk-NXWVWC33.mjs +117 -0
- package/dist/chunk-NXWVWC33.mjs.map +1 -0
- package/dist/chunk-P4GBO6MW.mjs +3 -0
- package/dist/chunk-P4GBO6MW.mjs.map +1 -0
- package/dist/chunk-QFASQEFJ.mjs +51 -0
- package/dist/chunk-QFASQEFJ.mjs.map +1 -0
- package/dist/chunk-UIRFLYXI.mjs +53 -0
- package/dist/chunk-UIRFLYXI.mjs.map +1 -0
- package/dist/chunk-WB3YULQ4.mjs +3 -0
- package/dist/chunk-WB3YULQ4.mjs.map +1 -0
- package/dist/chunk-WM6BS77F.mjs +53 -0
- package/dist/chunk-WM6BS77F.mjs.map +1 -0
- package/dist/chunk-X3Z2EVFV.mjs +26 -0
- package/dist/chunk-X3Z2EVFV.mjs.map +1 -0
- package/dist/chunk-X4T6ZUVM.mjs +14 -0
- package/dist/chunk-X4T6ZUVM.mjs.map +1 -0
- package/dist/chunk-Y2RUG4B3.mjs +21 -0
- package/dist/chunk-Y2RUG4B3.mjs.map +1 -0
- package/dist/chunk-ZVAH2Z2W.mjs +61 -0
- package/dist/chunk-ZVAH2Z2W.mjs.map +1 -0
- package/dist/components/chat/Button.d.ts +7 -0
- package/dist/components/chat/Button.mjs +6 -0
- package/dist/components/chat/Button.mjs.map +1 -0
- package/dist/components/chat/Chat.d.ts +95 -0
- package/dist/components/chat/Chat.mjs +16 -0
- package/dist/components/chat/Chat.mjs.map +1 -0
- package/dist/components/chat/ChatContext.d.ts +105 -0
- package/dist/components/chat/ChatContext.mjs +5 -0
- package/dist/components/chat/ChatContext.mjs.map +1 -0
- package/dist/components/chat/CodeBlock.d.ts +14 -0
- package/dist/components/chat/CodeBlock.mjs +6 -0
- package/dist/components/chat/CodeBlock.mjs.map +1 -0
- package/dist/components/chat/Header.d.ts +7 -0
- package/dist/components/chat/Header.mjs +6 -0
- package/dist/components/chat/Header.mjs.map +1 -0
- package/dist/components/chat/Icons.d.ts +15 -0
- package/dist/components/chat/Icons.mjs +4 -0
- package/dist/components/chat/Icons.mjs.map +1 -0
- package/dist/components/chat/Input.d.ts +7 -0
- package/dist/components/chat/Input.mjs +7 -0
- package/dist/components/chat/Input.mjs.map +1 -0
- package/dist/components/chat/Markdown.d.ts +8 -0
- package/dist/components/chat/Markdown.mjs +7 -0
- package/dist/components/chat/Markdown.mjs.map +1 -0
- package/dist/components/chat/Messages.d.ts +7 -0
- package/dist/components/chat/Messages.mjs +9 -0
- package/dist/components/chat/Messages.mjs.map +1 -0
- package/dist/components/chat/Popup.d.ts +9 -0
- package/dist/components/chat/Popup.mjs +17 -0
- package/dist/components/chat/Popup.mjs.map +1 -0
- package/dist/components/chat/Response.d.ts +7 -0
- package/dist/components/chat/Response.mjs +6 -0
- package/dist/components/chat/Response.mjs.map +1 -0
- package/dist/components/chat/Sidebar.d.ts +12 -0
- package/dist/components/chat/Sidebar.mjs +17 -0
- package/dist/components/chat/Sidebar.mjs.map +1 -0
- package/dist/components/chat/Textarea.d.ts +13 -0
- package/dist/components/chat/Textarea.mjs +4 -0
- package/dist/components/chat/Textarea.mjs.map +1 -0
- package/dist/components/chat/Window.d.ts +6 -0
- package/dist/components/chat/Window.mjs +4 -0
- package/dist/components/chat/Window.mjs.map +1 -0
- package/dist/components/chat/index.d.ts +7 -0
- package/dist/components/chat/index.mjs +20 -0
- package/dist/components/chat/index.mjs.map +1 -0
- package/dist/components/chat/props.d.ts +33 -0
- package/dist/components/chat/props.mjs +3 -0
- package/dist/components/chat/props.mjs.map +1 -0
- package/dist/components/chat-components/copilot-chat.mjs +1 -1
- package/dist/components/chat-components/ui/badge.d.ts +1 -1
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.mjs +18 -2
- package/dist/components/sidebar/copilot-sidebar-ui-provider.mjs +1 -1
- package/dist/components/sidebar/copilot-sidebar.mjs +1 -1
- package/dist/index.css +452 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +18 -2
- package/package.json +5 -5
- package/src/components/chat/Button.tsx +24 -0
- package/src/components/chat/Chat.tsx +186 -0
- package/src/components/chat/ChatContext.tsx +176 -0
- package/src/components/chat/CodeBlock.tsx +149 -0
- package/src/components/chat/Header.tsx +16 -0
- package/src/components/chat/Icons.tsx +179 -0
- package/src/components/chat/Input.tsx +51 -0
- package/src/components/chat/Markdown.tsx +62 -0
- package/src/components/chat/Messages.tsx +113 -0
- package/src/components/chat/Popup.tsx +10 -0
- package/src/components/chat/Response.tsx +13 -0
- package/src/components/chat/Sidebar.tsx +28 -0
- package/src/components/chat/Textarea.tsx +61 -0
- package/src/components/chat/Window.tsx +141 -0
- package/src/components/chat/index.tsx +3 -0
- package/src/components/chat/props.ts +36 -0
- package/src/components/index.ts +2 -0
- package/src/css/animations.css +29 -0
- package/src/css/button.css +54 -0
- package/src/css/colors.css +61 -0
- package/src/css/header.css +43 -0
- package/src/css/input.css +79 -0
- package/src/css/messages.css +57 -0
- package/src/css/popup.css +22 -0
- package/src/css/response.css +29 -0
- package/src/css/sidebar.css +34 -0
- package/src/css/window.css +58 -0
- package/src/styles.css +11 -0
- package/dist/chunk-U6NJWGTV.mjs +0 -3
- /package/dist/{chunk-U6NJWGTV.mjs.map → chunk-FZRTAML3.mjs.map} +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import * as DefaultIcons from "./Icons";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Icons for CopilotKitChat component.
|
|
6
|
+
*/
|
|
7
|
+
export interface CopilotKitChatIcons {
|
|
8
|
+
/**
|
|
9
|
+
* The icon to use for the open chat button.
|
|
10
|
+
* @default <OpenIcon />
|
|
11
|
+
*/
|
|
12
|
+
openIcon?: React.ReactNode;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The icon to use for the close chat button.
|
|
16
|
+
* @default <CloseIcon />
|
|
17
|
+
*/
|
|
18
|
+
closeIcon?: React.ReactNode;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The icon to use for the close chat button in the header.
|
|
22
|
+
* @default <HeaderCloseIcon />
|
|
23
|
+
*/
|
|
24
|
+
headerCloseIcon?: React.ReactNode;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The icon to use for the send button.
|
|
28
|
+
* @default <SendIcon />
|
|
29
|
+
*/
|
|
30
|
+
sendIcon?: React.ReactNode;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The icon to use for the activity indicator.
|
|
34
|
+
* @default <ActivityIcon />
|
|
35
|
+
*/
|
|
36
|
+
activityIcon?: React.ReactNode;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The icon to use for the spinner.
|
|
40
|
+
* @default <SpinnerIcon />
|
|
41
|
+
*/
|
|
42
|
+
spinnerIcon?: React.ReactNode;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The icon to use for the stop button.
|
|
46
|
+
* @default <StopIcon />
|
|
47
|
+
*/
|
|
48
|
+
stopIcon?: React.ReactNode;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The icon to use for the regenerate button.
|
|
52
|
+
* @default <RegenerateIcon />
|
|
53
|
+
*/
|
|
54
|
+
regenerateIcon?: React.ReactNode;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Labels for CopilotKitChat component.
|
|
59
|
+
*/
|
|
60
|
+
export interface CopilotKitChatLabels {
|
|
61
|
+
/**
|
|
62
|
+
* The initial message(s) to display in the chat window.
|
|
63
|
+
*/
|
|
64
|
+
initial?: string | string[];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The title to display in the header.
|
|
68
|
+
* @default "CopilotKit"
|
|
69
|
+
*/
|
|
70
|
+
title?: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The placeholder to display in the input.
|
|
74
|
+
* @default "Type a message..."
|
|
75
|
+
*/
|
|
76
|
+
placeholder?: string;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The message to display while the chat GPT is "thinking".
|
|
80
|
+
* @default "Thinking..."
|
|
81
|
+
*/
|
|
82
|
+
thinking?: string;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The message to display when the chat is done executing a function.
|
|
86
|
+
* @default "✅ Done"
|
|
87
|
+
*/
|
|
88
|
+
done?: string;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The message to display when an error occurs.
|
|
92
|
+
* @default "❌ An error occurred. Please try again."
|
|
93
|
+
*/
|
|
94
|
+
error?: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The label to display on the stop button.
|
|
98
|
+
* @default "Stop generating"
|
|
99
|
+
*/
|
|
100
|
+
stopGenerating?: string;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The label to display on the regenerate button.
|
|
104
|
+
* @default "Regenerate response"
|
|
105
|
+
*/
|
|
106
|
+
regenerateResponse?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
interface ChatContext {
|
|
110
|
+
labels: Required<CopilotKitChatLabels>;
|
|
111
|
+
icons: Required<CopilotKitChatIcons>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export const ChatContext = React.createContext<ChatContext | undefined>(undefined);
|
|
115
|
+
|
|
116
|
+
export function useChatContext(): ChatContext {
|
|
117
|
+
const context = React.useContext(ChatContext);
|
|
118
|
+
if (context === undefined) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return context;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface ChatContextProps {
|
|
127
|
+
// temperature?: number;
|
|
128
|
+
// instructions?: string;
|
|
129
|
+
// maxFeedback?: number;
|
|
130
|
+
labels?: CopilotKitChatLabels;
|
|
131
|
+
icons?: CopilotKitChatIcons;
|
|
132
|
+
children?: React.ReactNode;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const ChatContextProvider: React.FC<ChatContextProps> = ({
|
|
136
|
+
// temperature,
|
|
137
|
+
// instructions,
|
|
138
|
+
// maxFeedback,
|
|
139
|
+
labels,
|
|
140
|
+
icons,
|
|
141
|
+
children,
|
|
142
|
+
}) => {
|
|
143
|
+
const context = useMemo(
|
|
144
|
+
() => ({
|
|
145
|
+
labels: {
|
|
146
|
+
...{
|
|
147
|
+
initial: "",
|
|
148
|
+
title: "CopilotKit",
|
|
149
|
+
placeholder: "Type a message...",
|
|
150
|
+
thinking: "Thinking...",
|
|
151
|
+
done: "✅ Done",
|
|
152
|
+
error: "❌ An error occurred. Please try again.",
|
|
153
|
+
stopGenerating: "Stop generating",
|
|
154
|
+
regenerateResponse: "Regenerate response",
|
|
155
|
+
},
|
|
156
|
+
...labels,
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
icons: {
|
|
160
|
+
...{
|
|
161
|
+
openIcon: DefaultIcons.OpenIcon,
|
|
162
|
+
closeIcon: DefaultIcons.CloseIcon,
|
|
163
|
+
headerCloseIcon: DefaultIcons.HeaderCloseIcon,
|
|
164
|
+
sendIcon: DefaultIcons.SendIcon,
|
|
165
|
+
activityIcon: DefaultIcons.ActivityIcon,
|
|
166
|
+
spinnerIcon: DefaultIcons.SpinnerIcon,
|
|
167
|
+
stopIcon: DefaultIcons.StopIcon,
|
|
168
|
+
regenerateIcon: DefaultIcons.RegenerateIcon,
|
|
169
|
+
},
|
|
170
|
+
icons,
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
[labels, icons],
|
|
174
|
+
);
|
|
175
|
+
return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;
|
|
176
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { FC, memo } from "react";
|
|
4
|
+
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
5
|
+
|
|
6
|
+
import { useCopyToClipboard } from "../../hooks/use-copy-to-clipboard";
|
|
7
|
+
import { CheckIcon, CopyIcon, DownloadIcon } from "./Icons";
|
|
8
|
+
|
|
9
|
+
interface CodeActionButtonProps {
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const CodeActionButton: FC<CodeActionButtonProps> = ({ onClick, children }) => {
|
|
15
|
+
let className =
|
|
16
|
+
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background " +
|
|
17
|
+
"transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring " +
|
|
18
|
+
"focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ";
|
|
19
|
+
|
|
20
|
+
className +=
|
|
21
|
+
"hover:bg-zinc-800 focus-visible:ring-1 focus-visible:ring-slate-700 focus-visible:ring-offset-0 ";
|
|
22
|
+
className += "hover:bg-accent hover:text-accent-foreground ";
|
|
23
|
+
className += "h-10 w-10";
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<button className={className} onClick={onClick}>
|
|
27
|
+
{children}
|
|
28
|
+
</button>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
interface Props {
|
|
33
|
+
language: string;
|
|
34
|
+
value: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface languageMap {
|
|
38
|
+
[key: string]: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const programmingLanguages: languageMap = {
|
|
42
|
+
javascript: ".js",
|
|
43
|
+
python: ".py",
|
|
44
|
+
java: ".java",
|
|
45
|
+
c: ".c",
|
|
46
|
+
cpp: ".cpp",
|
|
47
|
+
"c++": ".cpp",
|
|
48
|
+
"c#": ".cs",
|
|
49
|
+
ruby: ".rb",
|
|
50
|
+
php: ".php",
|
|
51
|
+
swift: ".swift",
|
|
52
|
+
"objective-c": ".m",
|
|
53
|
+
kotlin: ".kt",
|
|
54
|
+
typescript: ".ts",
|
|
55
|
+
go: ".go",
|
|
56
|
+
perl: ".pl",
|
|
57
|
+
rust: ".rs",
|
|
58
|
+
scala: ".scala",
|
|
59
|
+
haskell: ".hs",
|
|
60
|
+
lua: ".lua",
|
|
61
|
+
shell: ".sh",
|
|
62
|
+
sql: ".sql",
|
|
63
|
+
html: ".html",
|
|
64
|
+
css: ".css",
|
|
65
|
+
// add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const generateRandomString = (length: number, lowercase = false) => {
|
|
69
|
+
const chars = "ABCDEFGHJKLMNPQRSTUVWXY3456789"; // excluding similar looking characters like Z, 2, I, 1, O, 0
|
|
70
|
+
let result = "";
|
|
71
|
+
for (let i = 0; i < length; i++) {
|
|
72
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
73
|
+
}
|
|
74
|
+
return lowercase ? result.toLowerCase() : result;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const CodeBlock: FC<Props> = memo(({ language, value }) => {
|
|
78
|
+
const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2000 });
|
|
79
|
+
|
|
80
|
+
const downloadAsFile = () => {
|
|
81
|
+
if (typeof window === "undefined") {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const fileExtension = programmingLanguages[language] || ".file";
|
|
85
|
+
const suggestedFileName = `file-${generateRandomString(3, true)}${fileExtension}`;
|
|
86
|
+
const fileName = window.prompt("Enter file name" || "", suggestedFileName);
|
|
87
|
+
|
|
88
|
+
if (!fileName) {
|
|
89
|
+
// User pressed cancel on prompt.
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const blob = new Blob([value], { type: "text/plain" });
|
|
94
|
+
const url = URL.createObjectURL(blob);
|
|
95
|
+
const link = document.createElement("a");
|
|
96
|
+
link.download = fileName;
|
|
97
|
+
link.href = url;
|
|
98
|
+
link.style.display = "none";
|
|
99
|
+
document.body.appendChild(link);
|
|
100
|
+
link.click();
|
|
101
|
+
document.body.removeChild(link);
|
|
102
|
+
URL.revokeObjectURL(url);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const onCopy = () => {
|
|
106
|
+
if (isCopied) return;
|
|
107
|
+
copyToClipboard(value);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<div className="codeblock relative w-full bg-zinc-950 font-sans">
|
|
112
|
+
<div className="flex w-full items-center justify-between bg-zinc-800 px-6 py-2 pr-4 text-zinc-100">
|
|
113
|
+
<span className="text-xs lowercase">{language}</span>
|
|
114
|
+
<div className="flex items-center space-x-1">
|
|
115
|
+
<CodeActionButton onClick={downloadAsFile}>
|
|
116
|
+
<DownloadIcon />
|
|
117
|
+
<span className="sr-only">Download</span>
|
|
118
|
+
</CodeActionButton>
|
|
119
|
+
<CodeActionButton onClick={onCopy}>
|
|
120
|
+
{isCopied ? <CheckIcon /> : <CopyIcon />}
|
|
121
|
+
<span className="sr-only">Copy code</span>
|
|
122
|
+
</CodeActionButton>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
<SyntaxHighlighter
|
|
126
|
+
language={language}
|
|
127
|
+
PreTag="div"
|
|
128
|
+
showLineNumbers
|
|
129
|
+
customStyle={{
|
|
130
|
+
margin: 0,
|
|
131
|
+
width: "100%",
|
|
132
|
+
background: "transparent",
|
|
133
|
+
padding: "1.5rem 1rem",
|
|
134
|
+
}}
|
|
135
|
+
codeTagProps={{
|
|
136
|
+
style: {
|
|
137
|
+
fontSize: "0.9rem",
|
|
138
|
+
fontFamily: "var(--font-mono)",
|
|
139
|
+
},
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
{value}
|
|
143
|
+
</SyntaxHighlighter>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
CodeBlock.displayName = "CodeBlock";
|
|
148
|
+
|
|
149
|
+
export { CodeBlock };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { HeaderProps } from "./props";
|
|
3
|
+
import { useChatContext } from "./ChatContext";
|
|
4
|
+
|
|
5
|
+
export const Header: React.FC<HeaderProps> = ({ setOpen }) => {
|
|
6
|
+
const context = useChatContext();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div className="copilotKitHeader">
|
|
10
|
+
<div>{context.labels.title}</div>
|
|
11
|
+
<button onClick={() => setOpen(false)} aria-label="Close">
|
|
12
|
+
{context.icons.headerCloseIcon}
|
|
13
|
+
</button>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export const OpenIcon = (
|
|
4
|
+
<svg
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
fill="currentColor"
|
|
8
|
+
width="24"
|
|
9
|
+
height="24"
|
|
10
|
+
>
|
|
11
|
+
<g transform="translate(24, 0) scale(-1, 1)">
|
|
12
|
+
<path
|
|
13
|
+
fillRule="evenodd"
|
|
14
|
+
d="M5.337 21.718a6.707 6.707 0 01-.533-.074.75.75 0 01-.44-1.223 3.73 3.73 0 00.814-1.686c.023-.115-.022-.317-.254-.543C3.274 16.587 2.25 14.41 2.25 12c0-5.03 4.428-9 9.75-9s9.75 3.97 9.75 9c0 5.03-4.428 9-9.75 9-.833 0-1.643-.097-2.417-.279a6.721 6.721 0 01-4.246.997z"
|
|
15
|
+
clipRule="evenodd"
|
|
16
|
+
/>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const CloseIcon = (
|
|
22
|
+
<svg
|
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
fill="none"
|
|
25
|
+
viewBox="0 0 24 24"
|
|
26
|
+
strokeWidth="1.5"
|
|
27
|
+
stroke="currentColor"
|
|
28
|
+
width="24"
|
|
29
|
+
height="24"
|
|
30
|
+
>
|
|
31
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const HeaderCloseIcon = (
|
|
36
|
+
<svg
|
|
37
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
38
|
+
fill="none"
|
|
39
|
+
viewBox="0 0 24 24"
|
|
40
|
+
strokeWidth="1.5"
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
width="24"
|
|
43
|
+
height="24"
|
|
44
|
+
>
|
|
45
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
46
|
+
</svg>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export const SendIcon = (
|
|
50
|
+
<svg
|
|
51
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
52
|
+
fill="none"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
strokeWidth={1.5}
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
width="24"
|
|
57
|
+
height="24"
|
|
58
|
+
>
|
|
59
|
+
<path
|
|
60
|
+
strokeLinecap="round"
|
|
61
|
+
strokeLinejoin="round"
|
|
62
|
+
d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5"
|
|
63
|
+
/>
|
|
64
|
+
</svg>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
export const SpinnerIcon = (
|
|
68
|
+
<svg
|
|
69
|
+
style={{
|
|
70
|
+
animation: "copilotKitSpinAnimation 1s linear infinite",
|
|
71
|
+
color: "rgb(107 114 128)",
|
|
72
|
+
}}
|
|
73
|
+
width="24"
|
|
74
|
+
height="24"
|
|
75
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
76
|
+
fill="none"
|
|
77
|
+
viewBox="0 0 24 24"
|
|
78
|
+
>
|
|
79
|
+
<circle
|
|
80
|
+
style={{ opacity: 0.25 }}
|
|
81
|
+
cx="12"
|
|
82
|
+
cy="12"
|
|
83
|
+
r="10"
|
|
84
|
+
stroke="currentColor"
|
|
85
|
+
strokeWidth="4"
|
|
86
|
+
></circle>
|
|
87
|
+
<path
|
|
88
|
+
style={{ opacity: 0.75 }}
|
|
89
|
+
fill="currentColor"
|
|
90
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
91
|
+
></path>
|
|
92
|
+
</svg>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
export const ActivityIcon = (
|
|
96
|
+
<svg
|
|
97
|
+
style={{
|
|
98
|
+
display: "inline-block",
|
|
99
|
+
marginLeft: "0.25rem",
|
|
100
|
+
marginRight: "0.25rem",
|
|
101
|
+
}}
|
|
102
|
+
height="24"
|
|
103
|
+
width="24"
|
|
104
|
+
viewBox="0 0 27 27"
|
|
105
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
106
|
+
fill="currentColor"
|
|
107
|
+
>
|
|
108
|
+
<circle className="copilotKitActivityDot1" cx="4" cy="12" r="3" />
|
|
109
|
+
<circle className="copilotKitActivityDot1 copilotKitActivityDot2" cx="12" cy="12" r="3" />
|
|
110
|
+
<circle className="copilotKitActivityDot1 copilotKitActivityDot3" cx="20" cy="12" r="3" />
|
|
111
|
+
</svg>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
export function CheckIcon({ className, ...props }: React.ComponentProps<"svg">) {
|
|
115
|
+
return (
|
|
116
|
+
<svg
|
|
117
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
118
|
+
viewBox="0 0 256 256"
|
|
119
|
+
fill="currentColor"
|
|
120
|
+
style={{ height: "1rem", width: "1rem" }}
|
|
121
|
+
className={className}
|
|
122
|
+
{...props}
|
|
123
|
+
>
|
|
124
|
+
<path d="m229.66 77.66-128 128a8 8 0 0 1-11.32 0l-56-56a8 8 0 0 1 11.32-11.32L96 188.69 218.34 66.34a8 8 0 0 1 11.32 11.32Z" />
|
|
125
|
+
</svg>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function DownloadIcon({ className, ...props }: React.ComponentProps<"svg">) {
|
|
130
|
+
return (
|
|
131
|
+
<svg
|
|
132
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
133
|
+
viewBox="0 0 256 256"
|
|
134
|
+
fill="currentColor"
|
|
135
|
+
style={{ height: "1rem", width: "1rem" }}
|
|
136
|
+
className={className}
|
|
137
|
+
{...props}
|
|
138
|
+
>
|
|
139
|
+
<path d="M224 152v56a16 16 0 0 1-16 16H48a16 16 0 0 1-16-16v-56a8 8 0 0 1 16 0v56h160v-56a8 8 0 0 1 16 0Zm-101.66 5.66a8 8 0 0 0 11.32 0l40-40a8 8 0 0 0-11.32-11.32L136 132.69V40a8 8 0 0 0-16 0v92.69l-26.34-26.35a8 8 0 0 0-11.32 11.32Z" />
|
|
140
|
+
</svg>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function CopyIcon({ className, ...props }: React.ComponentProps<"svg">) {
|
|
145
|
+
return (
|
|
146
|
+
<svg
|
|
147
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
148
|
+
viewBox="0 0 256 256"
|
|
149
|
+
fill="currentColor"
|
|
150
|
+
style={{ height: "1rem", width: "1rem" }}
|
|
151
|
+
className={className}
|
|
152
|
+
{...props}
|
|
153
|
+
>
|
|
154
|
+
<path d="M216 32H88a8 8 0 0 0-8 8v40H40a8 8 0 0 0-8 8v128a8 8 0 0 0 8 8h128a8 8 0 0 0 8-8v-40h40a8 8 0 0 0 8-8V40a8 8 0 0 0-8-8Zm-56 176H48V96h112Zm48-48h-32V88a8 8 0 0 0-8-8H96V48h112Z" />
|
|
155
|
+
</svg>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const StopIcon = (
|
|
160
|
+
<svg
|
|
161
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
162
|
+
viewBox="0 0 256 256"
|
|
163
|
+
fill="currentColor"
|
|
164
|
+
style={{ height: "1rem", width: "1rem" }}
|
|
165
|
+
>
|
|
166
|
+
<path d="M128 24a104 104 0 1 0 104 104A104.11 104.11 0 0 0 128 24Zm0 192a88 88 0 1 1 88-88 88.1 88.1 0 0 1-88 88Zm24-120h-48a8 8 0 0 0-8 8v48a8 8 0 0 0 8 8h48a8 8 0 0 0 8-8v-48a8 8 0 0 0-8-8Zm-8 48h-32v-32h32Z" />
|
|
167
|
+
</svg>
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
export const RegenerateIcon = (
|
|
171
|
+
<svg
|
|
172
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
173
|
+
viewBox="0 0 256 256"
|
|
174
|
+
fill="currentColor"
|
|
175
|
+
style={{ height: "1rem", width: "1rem" }}
|
|
176
|
+
>
|
|
177
|
+
<path d="M197.67 186.37a8 8 0 0 1 0 11.29C196.58 198.73 170.82 224 128 224c-37.39 0-64.53-22.4-80-39.85V208a8 8 0 0 1-16 0v-48a8 8 0 0 1 8-8h48a8 8 0 0 1 0 16H55.44C67.76 183.35 93 208 128 208c36 0 58.14-21.46 58.36-21.68a8 8 0 0 1 11.31.05ZM216 40a8 8 0 0 0-8 8v23.85C192.53 54.4 165.39 32 128 32c-42.82 0-68.58 25.27-69.66 26.34a8 8 0 0 0 11.3 11.34C69.86 69.46 92 48 128 48c35 0 60.24 24.65 72.56 40H168a8 8 0 0 0 0 16h48a8 8 0 0 0 8-8V48a8 8 0 0 0-8-8Z" />
|
|
178
|
+
</svg>
|
|
179
|
+
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { useRef, useState } from "react";
|
|
2
|
+
import { InputProps } from "./props";
|
|
3
|
+
import { useChatContext } from "./ChatContext";
|
|
4
|
+
import AutoResizingTextarea from "./Textarea";
|
|
5
|
+
|
|
6
|
+
export const Input: React.FC<InputProps> = ({ inProgress, onSend, children }) => {
|
|
7
|
+
const context = useChatContext();
|
|
8
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
9
|
+
|
|
10
|
+
const handleDivClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
11
|
+
// Check if the clicked element is not the textarea itself
|
|
12
|
+
if (event.target !== event.currentTarget) return;
|
|
13
|
+
|
|
14
|
+
textareaRef.current?.focus();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const [text, setText] = useState("");
|
|
18
|
+
const send = () => {
|
|
19
|
+
if (inProgress) return;
|
|
20
|
+
onSend(text);
|
|
21
|
+
setText("");
|
|
22
|
+
|
|
23
|
+
textareaRef.current?.focus();
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const icon = inProgress ? context.icons.activityIcon : context.icons.sendIcon;
|
|
27
|
+
const disabled = inProgress || text.length === 0;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className="copilotKitInput" onClick={handleDivClick}>
|
|
31
|
+
<span>{children}</span>
|
|
32
|
+
<button className="copilotKitSendButton" disabled={disabled} onClick={send}>
|
|
33
|
+
{icon}
|
|
34
|
+
</button>
|
|
35
|
+
<AutoResizingTextarea
|
|
36
|
+
ref={textareaRef}
|
|
37
|
+
placeholder={context.labels.placeholder}
|
|
38
|
+
autoFocus={true}
|
|
39
|
+
maxRows={5}
|
|
40
|
+
value={text}
|
|
41
|
+
onChange={(event) => setText(event.target.value)}
|
|
42
|
+
onKeyDown={(event) => {
|
|
43
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
send();
|
|
46
|
+
}
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FC, memo } from "react";
|
|
3
|
+
import ReactMarkdown, { Options, Components } from "react-markdown";
|
|
4
|
+
import { CodeBlock } from "./CodeBlock";
|
|
5
|
+
import remarkGfm from "remark-gfm";
|
|
6
|
+
import remarkMath from "remark-math";
|
|
7
|
+
|
|
8
|
+
const MemoizedReactMarkdown: FC<Options> = memo(
|
|
9
|
+
ReactMarkdown,
|
|
10
|
+
(prevProps, nextProps) =>
|
|
11
|
+
prevProps.children === nextProps.children && prevProps.className === nextProps.className,
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
type MarkdownProps = {
|
|
15
|
+
content: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Markdown: React.FC<MarkdownProps> = ({ content }) => {
|
|
19
|
+
return (
|
|
20
|
+
<MemoizedReactMarkdown
|
|
21
|
+
className="prose break-words dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 text-sm"
|
|
22
|
+
components={components}
|
|
23
|
+
remarkPlugins={[remarkGfm, remarkMath]}
|
|
24
|
+
>
|
|
25
|
+
{content}
|
|
26
|
+
</MemoizedReactMarkdown>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const components: Components = {
|
|
31
|
+
p({ children }) {
|
|
32
|
+
return <p className="mb-2 last:mb-0">{children}</p>;
|
|
33
|
+
},
|
|
34
|
+
code({ children, className, inline, ...props }) {
|
|
35
|
+
if (children.length) {
|
|
36
|
+
if (children[0] == "▍") {
|
|
37
|
+
return <span className="mt-1 animate-pulse cursor-default">▍</span>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
children[0] = (children[0] as string).replace("`▍`", "▍");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const match = /language-(\w+)/.exec(className || "");
|
|
44
|
+
|
|
45
|
+
if (inline) {
|
|
46
|
+
return (
|
|
47
|
+
<code className={className} {...props}>
|
|
48
|
+
{children}
|
|
49
|
+
</code>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<CodeBlock
|
|
55
|
+
key={Math.random()}
|
|
56
|
+
language={(match && match[1]) || ""}
|
|
57
|
+
value={String(children).replace(/\n$/, "")}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
};
|