@copilotkitnext/react 0.0.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$colon$css.log +9 -0
- package/.turbo/turbo-build.log +28 -0
- package/.turbo/turbo-check-types.log +0 -0
- package/.turbo/turbo-lint.log +78 -0
- package/.turbo/turbo-test.log +79 -0
- package/LICENSE +11 -0
- package/components.json +20 -0
- package/dist/index.d.mts +363 -0
- package/dist/index.d.ts +363 -0
- package/dist/index.js +2322 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2291 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles.css +2 -0
- package/eslint.config.mjs +11 -0
- package/package.json +84 -0
- package/postcss.config.js +7 -0
- package/src/__tests__/setup.ts +2 -0
- package/src/components/chat/CopilotChat.tsx +90 -0
- package/src/components/chat/CopilotChatAssistantMessage.tsx +478 -0
- package/src/components/chat/CopilotChatAudioRecorder.tsx +157 -0
- package/src/components/chat/CopilotChatInput.tsx +596 -0
- package/src/components/chat/CopilotChatMessageView.tsx +85 -0
- package/src/components/chat/CopilotChatToolCallsView.tsx +43 -0
- package/src/components/chat/CopilotChatUserMessage.tsx +337 -0
- package/src/components/chat/CopilotChatView.tsx +385 -0
- package/src/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +684 -0
- package/src/components/chat/__tests__/CopilotChatInput.test.tsx +531 -0
- package/src/components/chat/__tests__/setup.ts +1 -0
- package/src/components/chat/index.ts +35 -0
- package/src/components/index.ts +4 -0
- package/src/components/ui/button.tsx +123 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/tooltip.tsx +59 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/use-agent-context.tsx +17 -0
- package/src/hooks/use-agent.tsx +48 -0
- package/src/hooks/use-frontend-tool.tsx +46 -0
- package/src/hooks/use-human-in-the-loop.tsx +76 -0
- package/src/hooks/use-render-tool-call.tsx +81 -0
- package/src/index.ts +4 -0
- package/src/lib/__tests__/completePartialMarkdown.test.ts +495 -0
- package/src/lib/__tests__/renderSlot.test.tsx +610 -0
- package/src/lib/slots.tsx +55 -0
- package/src/lib/utils.ts +6 -0
- package/src/providers/CopilotChatConfigurationProvider.tsx +81 -0
- package/src/providers/CopilotKitProvider.tsx +269 -0
- package/src/providers/__tests__/CopilotKitProvider.test.tsx +487 -0
- package/src/providers/__tests__/CopilotKitProvider.wildcard.test.tsx +261 -0
- package/src/providers/index.ts +14 -0
- package/src/styles/globals.css +302 -0
- package/src/types/frontend-tool.ts +8 -0
- package/src/types/human-in-the-loop.ts +33 -0
- package/src/types/index.ts +3 -0
- package/src/types/react-tool-call-render.ts +29 -0
- package/tailwind.config.js +9 -0
- package/test.css +2355 -0
- package/tsconfig.json +23 -0
- package/tsup.config.ts +19 -0
- package/vitest.config.mjs +15 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { useAgent } from "@/hooks/use-agent";
|
|
2
|
+
import { CopilotChatView, CopilotChatViewProps } from "./CopilotChatView";
|
|
3
|
+
import { CopilotChatConfigurationProvider } from "@/providers/CopilotChatConfigurationProvider";
|
|
4
|
+
import { DEFAULT_AGENT_ID, randomUUID } from "@copilotkitnext/shared";
|
|
5
|
+
import { useCallback, useState, useEffect, useMemo } from "react";
|
|
6
|
+
import { merge } from "ts-deepmerge";
|
|
7
|
+
|
|
8
|
+
export type CopilotChatProps = Omit<CopilotChatViewProps, "messages"> & {
|
|
9
|
+
agentId?: string;
|
|
10
|
+
threadId?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function CopilotChat({
|
|
14
|
+
agentId = DEFAULT_AGENT_ID,
|
|
15
|
+
threadId,
|
|
16
|
+
...props
|
|
17
|
+
}: CopilotChatProps) {
|
|
18
|
+
const { agent } = useAgent({ agentId });
|
|
19
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
20
|
+
threadId = threadId ?? useMemo(() => randomUUID(), []);
|
|
21
|
+
|
|
22
|
+
const subscriber = {
|
|
23
|
+
onTextMessageStartEvent: () => setIsLoading(false),
|
|
24
|
+
onToolCallStartEvent: () => setIsLoading(false),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const connect = async () => {
|
|
29
|
+
setIsLoading(true);
|
|
30
|
+
await agent?.runAgent(
|
|
31
|
+
{
|
|
32
|
+
forwardedProps: { __copilotkitConnect: true },
|
|
33
|
+
},
|
|
34
|
+
subscriber
|
|
35
|
+
);
|
|
36
|
+
setIsLoading(false);
|
|
37
|
+
};
|
|
38
|
+
if (agent) {
|
|
39
|
+
agent.threadId = threadId;
|
|
40
|
+
if ("isCopilotKitAgent" in agent) {
|
|
41
|
+
connect();
|
|
42
|
+
} else {
|
|
43
|
+
setIsLoading(false);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return () => {};
|
|
47
|
+
}, [threadId, agent]);
|
|
48
|
+
|
|
49
|
+
const [inputValue, setInputValue] = useState("");
|
|
50
|
+
const onSubmitInput = useCallback(
|
|
51
|
+
async (value: string) => {
|
|
52
|
+
setInputValue("");
|
|
53
|
+
agent?.addMessage({
|
|
54
|
+
id: randomUUID(),
|
|
55
|
+
role: "user",
|
|
56
|
+
content: value,
|
|
57
|
+
});
|
|
58
|
+
setIsLoading(true);
|
|
59
|
+
await agent?.runAgent({}, subscriber);
|
|
60
|
+
setIsLoading(false);
|
|
61
|
+
},
|
|
62
|
+
[agent]
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const mergedProps = merge(
|
|
66
|
+
{
|
|
67
|
+
messageView: { isLoading },
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
...props,
|
|
71
|
+
...(typeof props.messageView === "string"
|
|
72
|
+
? { messageView: { className: props.messageView } }
|
|
73
|
+
: props.messageView !== undefined
|
|
74
|
+
? { messageView: props.messageView }
|
|
75
|
+
: {}),
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<CopilotChatConfigurationProvider
|
|
81
|
+
inputValue={inputValue}
|
|
82
|
+
onSubmitInput={onSubmitInput}
|
|
83
|
+
onChangeInput={setInputValue}
|
|
84
|
+
>
|
|
85
|
+
<CopilotChatView
|
|
86
|
+
{...{ messages: agent?.messages ?? [], ...mergedProps }}
|
|
87
|
+
/>
|
|
88
|
+
</CopilotChatConfigurationProvider>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import { AssistantMessage, Message } from "@ag-ui/core";
|
|
2
|
+
import { MarkdownHooks } from "react-markdown";
|
|
3
|
+
import remarkGfm from "remark-gfm";
|
|
4
|
+
import remarkMath from "remark-math";
|
|
5
|
+
import rehypePrettyCode from "rehype-pretty-code";
|
|
6
|
+
import rehypeKatex from "rehype-katex";
|
|
7
|
+
import { useState } from "react";
|
|
8
|
+
import {
|
|
9
|
+
Copy,
|
|
10
|
+
Check,
|
|
11
|
+
ThumbsUp,
|
|
12
|
+
ThumbsDown,
|
|
13
|
+
Volume2,
|
|
14
|
+
RefreshCw,
|
|
15
|
+
} from "lucide-react";
|
|
16
|
+
import { cn } from "@/lib/utils";
|
|
17
|
+
import { useCopilotChatConfiguration } from "@/providers/CopilotChatConfigurationProvider";
|
|
18
|
+
import { twMerge } from "tailwind-merge";
|
|
19
|
+
import { Button } from "@/components/ui/button";
|
|
20
|
+
import {
|
|
21
|
+
Tooltip,
|
|
22
|
+
TooltipContent,
|
|
23
|
+
TooltipTrigger,
|
|
24
|
+
} from "@/components/ui/tooltip";
|
|
25
|
+
import "katex/dist/katex.min.css";
|
|
26
|
+
import { WithSlots, renderSlot } from "@/lib/slots";
|
|
27
|
+
import { completePartialMarkdown } from "@copilotkitnext/core";
|
|
28
|
+
import CopilotChatToolCallsView from "./CopilotChatToolCallsView";
|
|
29
|
+
|
|
30
|
+
export type CopilotChatAssistantMessageProps = WithSlots<
|
|
31
|
+
{
|
|
32
|
+
markdownRenderer: typeof CopilotChatAssistantMessage.MarkdownRenderer;
|
|
33
|
+
toolbar: typeof CopilotChatAssistantMessage.Toolbar;
|
|
34
|
+
copyButton: typeof CopilotChatAssistantMessage.CopyButton;
|
|
35
|
+
thumbsUpButton: typeof CopilotChatAssistantMessage.ThumbsUpButton;
|
|
36
|
+
thumbsDownButton: typeof CopilotChatAssistantMessage.ThumbsDownButton;
|
|
37
|
+
readAloudButton: typeof CopilotChatAssistantMessage.ReadAloudButton;
|
|
38
|
+
regenerateButton: typeof CopilotChatAssistantMessage.RegenerateButton;
|
|
39
|
+
toolCallsView: typeof CopilotChatToolCallsView;
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
onThumbsUp?: (message: AssistantMessage) => void;
|
|
43
|
+
onThumbsDown?: (message: AssistantMessage) => void;
|
|
44
|
+
onReadAloud?: (message: AssistantMessage) => void;
|
|
45
|
+
onRegenerate?: (message: AssistantMessage) => void;
|
|
46
|
+
message: AssistantMessage;
|
|
47
|
+
messages?: Message[];
|
|
48
|
+
isLoading?: boolean;
|
|
49
|
+
additionalToolbarItems?: React.ReactNode;
|
|
50
|
+
toolbarVisible?: boolean;
|
|
51
|
+
} & React.HTMLAttributes<HTMLDivElement>
|
|
52
|
+
>;
|
|
53
|
+
|
|
54
|
+
export function CopilotChatAssistantMessage({
|
|
55
|
+
message,
|
|
56
|
+
messages,
|
|
57
|
+
isLoading,
|
|
58
|
+
onThumbsUp,
|
|
59
|
+
onThumbsDown,
|
|
60
|
+
onReadAloud,
|
|
61
|
+
onRegenerate,
|
|
62
|
+
additionalToolbarItems,
|
|
63
|
+
toolbarVisible = true,
|
|
64
|
+
markdownRenderer,
|
|
65
|
+
toolbar,
|
|
66
|
+
copyButton,
|
|
67
|
+
thumbsUpButton,
|
|
68
|
+
thumbsDownButton,
|
|
69
|
+
readAloudButton,
|
|
70
|
+
regenerateButton,
|
|
71
|
+
toolCallsView,
|
|
72
|
+
children,
|
|
73
|
+
className,
|
|
74
|
+
...props
|
|
75
|
+
}: CopilotChatAssistantMessageProps) {
|
|
76
|
+
const boundMarkdownRenderer = renderSlot(
|
|
77
|
+
markdownRenderer,
|
|
78
|
+
CopilotChatAssistantMessage.MarkdownRenderer,
|
|
79
|
+
{
|
|
80
|
+
content: message.content || "",
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const boundCopyButton = renderSlot(
|
|
85
|
+
copyButton,
|
|
86
|
+
CopilotChatAssistantMessage.CopyButton,
|
|
87
|
+
{
|
|
88
|
+
onClick: async () => {
|
|
89
|
+
if (message.content) {
|
|
90
|
+
try {
|
|
91
|
+
await navigator.clipboard.writeText(message.content);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error("Failed to copy message:", err);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const boundThumbsUpButton = renderSlot(
|
|
101
|
+
thumbsUpButton,
|
|
102
|
+
CopilotChatAssistantMessage.ThumbsUpButton,
|
|
103
|
+
{
|
|
104
|
+
onClick: onThumbsUp,
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const boundThumbsDownButton = renderSlot(
|
|
109
|
+
thumbsDownButton,
|
|
110
|
+
CopilotChatAssistantMessage.ThumbsDownButton,
|
|
111
|
+
{
|
|
112
|
+
onClick: onThumbsDown,
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const boundReadAloudButton = renderSlot(
|
|
117
|
+
readAloudButton,
|
|
118
|
+
CopilotChatAssistantMessage.ReadAloudButton,
|
|
119
|
+
{
|
|
120
|
+
onClick: onReadAloud,
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const boundRegenerateButton = renderSlot(
|
|
125
|
+
regenerateButton,
|
|
126
|
+
CopilotChatAssistantMessage.RegenerateButton,
|
|
127
|
+
{
|
|
128
|
+
onClick: onRegenerate,
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const boundToolbar = renderSlot(
|
|
133
|
+
toolbar,
|
|
134
|
+
CopilotChatAssistantMessage.Toolbar,
|
|
135
|
+
{
|
|
136
|
+
children: (
|
|
137
|
+
<div className="flex items-center gap-1">
|
|
138
|
+
{boundCopyButton}
|
|
139
|
+
{(onThumbsUp || thumbsUpButton) && boundThumbsUpButton}
|
|
140
|
+
{(onThumbsDown || thumbsDownButton) && boundThumbsDownButton}
|
|
141
|
+
{(onReadAloud || readAloudButton) && boundReadAloudButton}
|
|
142
|
+
{(onRegenerate || regenerateButton) && boundRegenerateButton}
|
|
143
|
+
{additionalToolbarItems}
|
|
144
|
+
</div>
|
|
145
|
+
),
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const boundToolCallsView = renderSlot(
|
|
150
|
+
toolCallsView,
|
|
151
|
+
CopilotChatToolCallsView,
|
|
152
|
+
{
|
|
153
|
+
message,
|
|
154
|
+
messages,
|
|
155
|
+
isLoading,
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
if (children) {
|
|
160
|
+
return (
|
|
161
|
+
<>
|
|
162
|
+
{children({
|
|
163
|
+
markdownRenderer: boundMarkdownRenderer,
|
|
164
|
+
toolbar: boundToolbar,
|
|
165
|
+
toolCallsView: boundToolCallsView,
|
|
166
|
+
copyButton: boundCopyButton,
|
|
167
|
+
thumbsUpButton: boundThumbsUpButton,
|
|
168
|
+
thumbsDownButton: boundThumbsDownButton,
|
|
169
|
+
readAloudButton: boundReadAloudButton,
|
|
170
|
+
regenerateButton: boundRegenerateButton,
|
|
171
|
+
message,
|
|
172
|
+
messages,
|
|
173
|
+
isLoading,
|
|
174
|
+
onThumbsUp,
|
|
175
|
+
onThumbsDown,
|
|
176
|
+
onReadAloud,
|
|
177
|
+
onRegenerate,
|
|
178
|
+
additionalToolbarItems,
|
|
179
|
+
toolbarVisible,
|
|
180
|
+
})}
|
|
181
|
+
</>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<div
|
|
187
|
+
className={twMerge(
|
|
188
|
+
"prose max-w-full break-words dark:prose-invert",
|
|
189
|
+
className
|
|
190
|
+
)}
|
|
191
|
+
{...props}
|
|
192
|
+
data-message-id={message.id}
|
|
193
|
+
>
|
|
194
|
+
{boundMarkdownRenderer}
|
|
195
|
+
{boundToolCallsView}
|
|
196
|
+
{toolbarVisible && boundToolbar}
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
202
|
+
export namespace CopilotChatAssistantMessage {
|
|
203
|
+
const InlineCode = ({
|
|
204
|
+
children,
|
|
205
|
+
...props
|
|
206
|
+
}: React.HTMLAttributes<HTMLElement>) => {
|
|
207
|
+
return (
|
|
208
|
+
<code
|
|
209
|
+
className="px-[4.8px] py-[2.5px] bg-[rgb(236,236,236)] dark:bg-gray-800 rounded text-sm font-mono font-medium! text-foreground!"
|
|
210
|
+
{...props}
|
|
211
|
+
>
|
|
212
|
+
{children}
|
|
213
|
+
</code>
|
|
214
|
+
);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
218
|
+
const CodeBlock = ({ children, className, onClick, ...props }: any) => {
|
|
219
|
+
const { labels } = useCopilotChatConfiguration();
|
|
220
|
+
const [copied, setCopied] = useState(false);
|
|
221
|
+
|
|
222
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
223
|
+
const getCodeContent = (node: any): string => {
|
|
224
|
+
if (typeof node === "string") return node;
|
|
225
|
+
if (Array.isArray(node)) return node.map(getCodeContent).join("");
|
|
226
|
+
if (node?.props?.children) return getCodeContent(node.props.children);
|
|
227
|
+
return "";
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const codeContent = getCodeContent(children);
|
|
231
|
+
const language = props["data-language"] as string | undefined;
|
|
232
|
+
|
|
233
|
+
const copyToClipboard = async () => {
|
|
234
|
+
if (!codeContent.trim()) return;
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
setCopied(true);
|
|
238
|
+
setTimeout(() => setCopied(false), 2000);
|
|
239
|
+
if (onClick) {
|
|
240
|
+
onClick();
|
|
241
|
+
}
|
|
242
|
+
} catch (err) {
|
|
243
|
+
console.error("Failed to copy code:", err);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<div className="relative">
|
|
249
|
+
<div className="flex items-center justify-between px-4 pr-3 py-3 text-xs">
|
|
250
|
+
{language && (
|
|
251
|
+
<span className="font-regular text-muted-foreground dark:text-white">
|
|
252
|
+
{language}
|
|
253
|
+
</span>
|
|
254
|
+
)}
|
|
255
|
+
|
|
256
|
+
<button
|
|
257
|
+
className={cn(
|
|
258
|
+
"px-2 gap-0.5 text-xs flex items-center cursor-pointer text-muted-foreground dark:text-white"
|
|
259
|
+
)}
|
|
260
|
+
onClick={copyToClipboard}
|
|
261
|
+
title={
|
|
262
|
+
copied
|
|
263
|
+
? labels.assistantMessageToolbarCopyCodeCopiedLabel
|
|
264
|
+
: `${labels.assistantMessageToolbarCopyCodeLabel} code`
|
|
265
|
+
}
|
|
266
|
+
>
|
|
267
|
+
{copied ? (
|
|
268
|
+
<Check className="h-[10px]! w-[10px]!" />
|
|
269
|
+
) : (
|
|
270
|
+
<Copy className="h-[10px]! w-[10px]!" />
|
|
271
|
+
)}
|
|
272
|
+
<span className="text-[11px]">
|
|
273
|
+
{copied
|
|
274
|
+
? labels.assistantMessageToolbarCopyCodeCopiedLabel
|
|
275
|
+
: labels.assistantMessageToolbarCopyCodeLabel}
|
|
276
|
+
</span>
|
|
277
|
+
</button>
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
<pre
|
|
281
|
+
className={cn(
|
|
282
|
+
className,
|
|
283
|
+
"rounded-2xl bg-transparent border-t-0 my-1!"
|
|
284
|
+
)}
|
|
285
|
+
{...props}
|
|
286
|
+
>
|
|
287
|
+
{children}
|
|
288
|
+
</pre>
|
|
289
|
+
</div>
|
|
290
|
+
);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
export const MarkdownRenderer: React.FC<
|
|
294
|
+
React.HTMLAttributes<HTMLDivElement> & { content: string }
|
|
295
|
+
> = ({ content, className }) => (
|
|
296
|
+
<div className={className}>
|
|
297
|
+
<MarkdownHooks
|
|
298
|
+
/* async plugins are now fine ✨ */
|
|
299
|
+
remarkPlugins={[remarkGfm, remarkMath]}
|
|
300
|
+
rehypePlugins={[
|
|
301
|
+
[
|
|
302
|
+
rehypePrettyCode,
|
|
303
|
+
{
|
|
304
|
+
keepBackground: false,
|
|
305
|
+
theme: {
|
|
306
|
+
dark: "one-dark-pro",
|
|
307
|
+
light: "one-light",
|
|
308
|
+
},
|
|
309
|
+
bypassInlineCode: true,
|
|
310
|
+
},
|
|
311
|
+
],
|
|
312
|
+
rehypeKatex,
|
|
313
|
+
]}
|
|
314
|
+
components={{
|
|
315
|
+
pre: CodeBlock,
|
|
316
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
317
|
+
code: ({ className, children, ...props }: any) => {
|
|
318
|
+
// For inline code, use custom styling
|
|
319
|
+
if (typeof children === "string") {
|
|
320
|
+
return <InlineCode {...props}>{children}</InlineCode>;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// For code blocks, just return the code element as-is
|
|
324
|
+
return (
|
|
325
|
+
<code className={className} {...props}>
|
|
326
|
+
{children}
|
|
327
|
+
</code>
|
|
328
|
+
);
|
|
329
|
+
},
|
|
330
|
+
}}
|
|
331
|
+
>
|
|
332
|
+
{completePartialMarkdown(content || "")}
|
|
333
|
+
</MarkdownHooks>
|
|
334
|
+
</div>
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
export const Toolbar: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
|
338
|
+
className,
|
|
339
|
+
...props
|
|
340
|
+
}) => (
|
|
341
|
+
<div
|
|
342
|
+
className={twMerge(
|
|
343
|
+
"w-full bg-transparent flex items-center -ml-[5px] -mt-[0px]",
|
|
344
|
+
className
|
|
345
|
+
)}
|
|
346
|
+
{...props}
|
|
347
|
+
/>
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
export const ToolbarButton: React.FC<
|
|
351
|
+
React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
352
|
+
title: string;
|
|
353
|
+
children: React.ReactNode;
|
|
354
|
+
}
|
|
355
|
+
> = ({ title, children, ...props }) => {
|
|
356
|
+
return (
|
|
357
|
+
<Tooltip>
|
|
358
|
+
<TooltipTrigger asChild>
|
|
359
|
+
<Button
|
|
360
|
+
type="button"
|
|
361
|
+
variant="assistantMessageToolbarButton"
|
|
362
|
+
aria-label={title}
|
|
363
|
+
{...props}
|
|
364
|
+
>
|
|
365
|
+
{children}
|
|
366
|
+
</Button>
|
|
367
|
+
</TooltipTrigger>
|
|
368
|
+
<TooltipContent side="bottom">
|
|
369
|
+
<p>{title}</p>
|
|
370
|
+
</TooltipContent>
|
|
371
|
+
</Tooltip>
|
|
372
|
+
);
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
export const CopyButton: React.FC<
|
|
376
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
377
|
+
> = ({ className, title, onClick, ...props }) => {
|
|
378
|
+
const { labels } = useCopilotChatConfiguration();
|
|
379
|
+
const [copied, setCopied] = useState(false);
|
|
380
|
+
|
|
381
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
382
|
+
setCopied(true);
|
|
383
|
+
setTimeout(() => setCopied(false), 2000);
|
|
384
|
+
|
|
385
|
+
if (onClick) {
|
|
386
|
+
onClick(event);
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
<ToolbarButton
|
|
392
|
+
title={title || labels.assistantMessageToolbarCopyMessageLabel}
|
|
393
|
+
onClick={handleClick}
|
|
394
|
+
className={className}
|
|
395
|
+
{...props}
|
|
396
|
+
>
|
|
397
|
+
{copied ? (
|
|
398
|
+
<Check className="size-[18px]" />
|
|
399
|
+
) : (
|
|
400
|
+
<Copy className="size-[18px]" />
|
|
401
|
+
)}
|
|
402
|
+
</ToolbarButton>
|
|
403
|
+
);
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
export const ThumbsUpButton: React.FC<
|
|
407
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
408
|
+
> = ({ title, ...props }) => {
|
|
409
|
+
const { labels } = useCopilotChatConfiguration();
|
|
410
|
+
return (
|
|
411
|
+
<ToolbarButton
|
|
412
|
+
title={title || labels.assistantMessageToolbarThumbsUpLabel}
|
|
413
|
+
{...props}
|
|
414
|
+
>
|
|
415
|
+
<ThumbsUp className="size-[18px]" />
|
|
416
|
+
</ToolbarButton>
|
|
417
|
+
);
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
export const ThumbsDownButton: React.FC<
|
|
421
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
422
|
+
> = ({ title, ...props }) => {
|
|
423
|
+
const { labels } = useCopilotChatConfiguration();
|
|
424
|
+
return (
|
|
425
|
+
<ToolbarButton
|
|
426
|
+
title={title || labels.assistantMessageToolbarThumbsDownLabel}
|
|
427
|
+
{...props}
|
|
428
|
+
>
|
|
429
|
+
<ThumbsDown className="size-[18px]" />
|
|
430
|
+
</ToolbarButton>
|
|
431
|
+
);
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
export const ReadAloudButton: React.FC<
|
|
435
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
436
|
+
> = ({ title, ...props }) => {
|
|
437
|
+
const { labels } = useCopilotChatConfiguration();
|
|
438
|
+
return (
|
|
439
|
+
<ToolbarButton
|
|
440
|
+
title={title || labels.assistantMessageToolbarReadAloudLabel}
|
|
441
|
+
{...props}
|
|
442
|
+
>
|
|
443
|
+
<Volume2 className="size-[20px]" />
|
|
444
|
+
</ToolbarButton>
|
|
445
|
+
);
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
export const RegenerateButton: React.FC<
|
|
449
|
+
React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
450
|
+
> = ({ title, ...props }) => {
|
|
451
|
+
const { labels } = useCopilotChatConfiguration();
|
|
452
|
+
return (
|
|
453
|
+
<ToolbarButton
|
|
454
|
+
title={title || labels.assistantMessageToolbarRegenerateLabel}
|
|
455
|
+
{...props}
|
|
456
|
+
>
|
|
457
|
+
<RefreshCw className="size-[18px]" />
|
|
458
|
+
</ToolbarButton>
|
|
459
|
+
);
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
CopilotChatAssistantMessage.MarkdownRenderer.displayName =
|
|
464
|
+
"CopilotChatAssistantMessage.MarkdownRenderer";
|
|
465
|
+
CopilotChatAssistantMessage.Toolbar.displayName =
|
|
466
|
+
"CopilotChatAssistantMessage.Toolbar";
|
|
467
|
+
CopilotChatAssistantMessage.CopyButton.displayName =
|
|
468
|
+
"CopilotChatAssistantMessage.CopyButton";
|
|
469
|
+
CopilotChatAssistantMessage.ThumbsUpButton.displayName =
|
|
470
|
+
"CopilotChatAssistantMessage.ThumbsUpButton";
|
|
471
|
+
CopilotChatAssistantMessage.ThumbsDownButton.displayName =
|
|
472
|
+
"CopilotChatAssistantMessage.ThumbsDownButton";
|
|
473
|
+
CopilotChatAssistantMessage.ReadAloudButton.displayName =
|
|
474
|
+
"CopilotChatAssistantMessage.ReadAloudButton";
|
|
475
|
+
CopilotChatAssistantMessage.RegenerateButton.displayName =
|
|
476
|
+
"CopilotChatAssistantMessage.RegenerateButton";
|
|
477
|
+
|
|
478
|
+
export default CopilotChatAssistantMessage;
|