@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
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2291 @@
|
|
|
1
|
+
// src/components/chat/CopilotChatInput.tsx
|
|
2
|
+
import {
|
|
3
|
+
useState,
|
|
4
|
+
useRef as useRef2,
|
|
5
|
+
useEffect as useEffect2,
|
|
6
|
+
forwardRef as forwardRef2,
|
|
7
|
+
useImperativeHandle as useImperativeHandle2
|
|
8
|
+
} from "react";
|
|
9
|
+
import { twMerge as twMerge3 } from "tailwind-merge";
|
|
10
|
+
import { Plus, Settings2, Mic, ArrowUp, X, Check } from "lucide-react";
|
|
11
|
+
|
|
12
|
+
// src/providers/CopilotChatConfigurationProvider.tsx
|
|
13
|
+
import { createContext, useContext } from "react";
|
|
14
|
+
import { jsx } from "react/jsx-runtime";
|
|
15
|
+
var CopilotChatDefaultLabels = {
|
|
16
|
+
chatInputPlaceholder: "Type a message...",
|
|
17
|
+
chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
|
|
18
|
+
chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
|
|
19
|
+
chatInputToolbarFinishTranscribeButtonLabel: "Finish",
|
|
20
|
+
chatInputToolbarAddButtonLabel: "Add photos or files",
|
|
21
|
+
chatInputToolbarToolsButtonLabel: "Tools",
|
|
22
|
+
assistantMessageToolbarCopyCodeLabel: "Copy",
|
|
23
|
+
assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
|
|
24
|
+
assistantMessageToolbarCopyMessageLabel: "Copy",
|
|
25
|
+
assistantMessageToolbarThumbsUpLabel: "Good response",
|
|
26
|
+
assistantMessageToolbarThumbsDownLabel: "Bad response",
|
|
27
|
+
assistantMessageToolbarReadAloudLabel: "Read aloud",
|
|
28
|
+
assistantMessageToolbarRegenerateLabel: "Regenerate",
|
|
29
|
+
userMessageToolbarCopyMessageLabel: "Copy",
|
|
30
|
+
userMessageToolbarEditMessageLabel: "Edit",
|
|
31
|
+
chatDisclaimerText: "AI can make mistakes. Please verify important information."
|
|
32
|
+
};
|
|
33
|
+
var CopilotChatConfiguration = createContext(null);
|
|
34
|
+
var CopilotChatConfigurationProvider = ({ children, labels = {}, inputValue, onSubmitInput, onChangeInput }) => {
|
|
35
|
+
const mergedLabels = {
|
|
36
|
+
...CopilotChatDefaultLabels,
|
|
37
|
+
...labels
|
|
38
|
+
};
|
|
39
|
+
const configurationValue = {
|
|
40
|
+
labels: mergedLabels,
|
|
41
|
+
inputValue,
|
|
42
|
+
onSubmitInput,
|
|
43
|
+
onChangeInput
|
|
44
|
+
};
|
|
45
|
+
return /* @__PURE__ */ jsx(CopilotChatConfiguration.Provider, { value: configurationValue, children });
|
|
46
|
+
};
|
|
47
|
+
var useCopilotChatConfiguration = () => {
|
|
48
|
+
const configuration = useContext(CopilotChatConfiguration);
|
|
49
|
+
if (!configuration) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"useCopilotChatConfiguration must be used within CopilotChatConfigurationProvider"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return configuration;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/components/ui/button.tsx
|
|
58
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
59
|
+
import { cva } from "class-variance-authority";
|
|
60
|
+
|
|
61
|
+
// src/lib/utils.ts
|
|
62
|
+
import { clsx } from "clsx";
|
|
63
|
+
import { twMerge } from "tailwind-merge";
|
|
64
|
+
function cn(...inputs) {
|
|
65
|
+
return twMerge(clsx(inputs));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/components/ui/button.tsx
|
|
69
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
70
|
+
var buttonVariants = cva(
|
|
71
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
72
|
+
{
|
|
73
|
+
variants: {
|
|
74
|
+
variant: {
|
|
75
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
76
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
77
|
+
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
78
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
79
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50 cursor-pointer",
|
|
80
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
81
|
+
assistantMessageToolbarButton: [
|
|
82
|
+
"cursor-pointer",
|
|
83
|
+
// Background and text
|
|
84
|
+
"p-0 text-[rgb(93,93,93)] hover:bg-[#E8E8E8]",
|
|
85
|
+
// Dark mode - lighter gray for better contrast
|
|
86
|
+
"dark:text-[rgb(243,243,243)] dark:hover:bg-[#303030]",
|
|
87
|
+
// Shape and sizing
|
|
88
|
+
"h-8 w-8",
|
|
89
|
+
// Interactions
|
|
90
|
+
"transition-colors",
|
|
91
|
+
// Hover states
|
|
92
|
+
"hover:text-[rgb(93,93,93)]",
|
|
93
|
+
"dark:hover:text-[rgb(243,243,243)]"
|
|
94
|
+
],
|
|
95
|
+
chatInputToolbarPrimary: [
|
|
96
|
+
"cursor-pointer",
|
|
97
|
+
// Background and text
|
|
98
|
+
"bg-black text-white",
|
|
99
|
+
// Dark mode
|
|
100
|
+
"dark:bg-white dark:text-black dark:focus-visible:outline-white",
|
|
101
|
+
// Shape and sizing
|
|
102
|
+
"rounded-full",
|
|
103
|
+
// Interactions
|
|
104
|
+
"transition-colors",
|
|
105
|
+
// Focus states
|
|
106
|
+
"focus:outline-none",
|
|
107
|
+
// Hover states
|
|
108
|
+
"hover:opacity-70 disabled:hover:opacity-100",
|
|
109
|
+
// Disabled states
|
|
110
|
+
"disabled:cursor-not-allowed disabled:bg-[#00000014] disabled:text-[rgb(13,13,13)]",
|
|
111
|
+
"dark:disabled:bg-[#454545] dark:disabled:text-white "
|
|
112
|
+
],
|
|
113
|
+
chatInputToolbarSecondary: [
|
|
114
|
+
"cursor-pointer",
|
|
115
|
+
// Background and text
|
|
116
|
+
"bg-transparent text-[#444444]",
|
|
117
|
+
// Dark mode
|
|
118
|
+
"dark:text-white dark:border-[#404040]",
|
|
119
|
+
// Shape and sizing
|
|
120
|
+
"rounded-full",
|
|
121
|
+
// Interactions
|
|
122
|
+
"transition-colors",
|
|
123
|
+
// Focus states
|
|
124
|
+
"focus:outline-none",
|
|
125
|
+
// Hover states
|
|
126
|
+
"hover:bg-[#f8f8f8] hover:text-[#333333]",
|
|
127
|
+
"dark:hover:bg-[#404040] dark:hover:text-[#FFFFFF]",
|
|
128
|
+
// Disabled states
|
|
129
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
130
|
+
"disabled:hover:bg-transparent disabled:hover:text-[#444444]",
|
|
131
|
+
"dark:disabled:hover:bg-transparent dark:disabled:hover:text-[#CCCCCC]"
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
size: {
|
|
135
|
+
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
136
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
137
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
138
|
+
icon: "size-9",
|
|
139
|
+
chatInputToolbarIcon: [
|
|
140
|
+
// Shape and sizing
|
|
141
|
+
"h-9 w-9 rounded-full"
|
|
142
|
+
],
|
|
143
|
+
chatInputToolbarIconLabel: [
|
|
144
|
+
// Shape and sizing
|
|
145
|
+
"h-9 px-3 rounded-full",
|
|
146
|
+
// Layout
|
|
147
|
+
"gap-2",
|
|
148
|
+
// Typography
|
|
149
|
+
"font-normal"
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
defaultVariants: {
|
|
154
|
+
variant: "default",
|
|
155
|
+
size: "default"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
function Button({
|
|
160
|
+
className,
|
|
161
|
+
variant,
|
|
162
|
+
size,
|
|
163
|
+
asChild = false,
|
|
164
|
+
...props
|
|
165
|
+
}) {
|
|
166
|
+
const Comp = asChild ? Slot : "button";
|
|
167
|
+
return /* @__PURE__ */ jsx2(
|
|
168
|
+
Comp,
|
|
169
|
+
{
|
|
170
|
+
"data-slot": "button",
|
|
171
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
172
|
+
...props
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/components/ui/tooltip.tsx
|
|
178
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
179
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
180
|
+
function TooltipProvider({
|
|
181
|
+
delayDuration = 0,
|
|
182
|
+
...props
|
|
183
|
+
}) {
|
|
184
|
+
return /* @__PURE__ */ jsx3(
|
|
185
|
+
TooltipPrimitive.Provider,
|
|
186
|
+
{
|
|
187
|
+
"data-slot": "tooltip-provider",
|
|
188
|
+
delayDuration,
|
|
189
|
+
...props
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
function Tooltip({
|
|
194
|
+
...props
|
|
195
|
+
}) {
|
|
196
|
+
return /* @__PURE__ */ jsx3(TooltipProvider, { children: /* @__PURE__ */ jsx3(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
|
|
197
|
+
}
|
|
198
|
+
function TooltipTrigger({
|
|
199
|
+
...props
|
|
200
|
+
}) {
|
|
201
|
+
return /* @__PURE__ */ jsx3(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
202
|
+
}
|
|
203
|
+
function TooltipContent({
|
|
204
|
+
className,
|
|
205
|
+
sideOffset = 0,
|
|
206
|
+
children,
|
|
207
|
+
...props
|
|
208
|
+
}) {
|
|
209
|
+
return /* @__PURE__ */ jsx3(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
210
|
+
TooltipPrimitive.Content,
|
|
211
|
+
{
|
|
212
|
+
"data-slot": "tooltip-content",
|
|
213
|
+
sideOffset,
|
|
214
|
+
className: cn(
|
|
215
|
+
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
216
|
+
className
|
|
217
|
+
),
|
|
218
|
+
...props,
|
|
219
|
+
children: [
|
|
220
|
+
children,
|
|
221
|
+
/* @__PURE__ */ jsx3(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
) });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/components/ui/dropdown-menu.tsx
|
|
228
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
229
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
|
230
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
231
|
+
function DropdownMenu({
|
|
232
|
+
...props
|
|
233
|
+
}) {
|
|
234
|
+
return /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
|
|
235
|
+
}
|
|
236
|
+
function DropdownMenuTrigger({
|
|
237
|
+
...props
|
|
238
|
+
}) {
|
|
239
|
+
return /* @__PURE__ */ jsx4(
|
|
240
|
+
DropdownMenuPrimitive.Trigger,
|
|
241
|
+
{
|
|
242
|
+
"data-slot": "dropdown-menu-trigger",
|
|
243
|
+
...props
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
function DropdownMenuContent({
|
|
248
|
+
className,
|
|
249
|
+
sideOffset = 4,
|
|
250
|
+
...props
|
|
251
|
+
}) {
|
|
252
|
+
return /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx4(
|
|
253
|
+
DropdownMenuPrimitive.Content,
|
|
254
|
+
{
|
|
255
|
+
"data-slot": "dropdown-menu-content",
|
|
256
|
+
sideOffset,
|
|
257
|
+
className: cn(
|
|
258
|
+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
|
259
|
+
className
|
|
260
|
+
),
|
|
261
|
+
...props
|
|
262
|
+
}
|
|
263
|
+
) });
|
|
264
|
+
}
|
|
265
|
+
function DropdownMenuItem({
|
|
266
|
+
className,
|
|
267
|
+
inset,
|
|
268
|
+
variant = "default",
|
|
269
|
+
...props
|
|
270
|
+
}) {
|
|
271
|
+
return /* @__PURE__ */ jsx4(
|
|
272
|
+
DropdownMenuPrimitive.Item,
|
|
273
|
+
{
|
|
274
|
+
"data-slot": "dropdown-menu-item",
|
|
275
|
+
"data-inset": inset,
|
|
276
|
+
"data-variant": variant,
|
|
277
|
+
className: cn(
|
|
278
|
+
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
279
|
+
className
|
|
280
|
+
),
|
|
281
|
+
...props
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
function DropdownMenuSeparator({
|
|
286
|
+
className,
|
|
287
|
+
...props
|
|
288
|
+
}) {
|
|
289
|
+
return /* @__PURE__ */ jsx4(
|
|
290
|
+
DropdownMenuPrimitive.Separator,
|
|
291
|
+
{
|
|
292
|
+
"data-slot": "dropdown-menu-separator",
|
|
293
|
+
className: cn("bg-border -mx-1 my-1 h-px", className),
|
|
294
|
+
...props
|
|
295
|
+
}
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
function DropdownMenuSub({
|
|
299
|
+
...props
|
|
300
|
+
}) {
|
|
301
|
+
return /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
|
|
302
|
+
}
|
|
303
|
+
function DropdownMenuSubTrigger({
|
|
304
|
+
className,
|
|
305
|
+
inset,
|
|
306
|
+
children,
|
|
307
|
+
...props
|
|
308
|
+
}) {
|
|
309
|
+
return /* @__PURE__ */ jsxs2(
|
|
310
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
311
|
+
{
|
|
312
|
+
"data-slot": "dropdown-menu-sub-trigger",
|
|
313
|
+
"data-inset": inset,
|
|
314
|
+
className: cn(
|
|
315
|
+
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
|
316
|
+
className
|
|
317
|
+
),
|
|
318
|
+
...props,
|
|
319
|
+
children: [
|
|
320
|
+
children,
|
|
321
|
+
/* @__PURE__ */ jsx4(ChevronRightIcon, { className: "ml-auto size-4" })
|
|
322
|
+
]
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
function DropdownMenuSubContent({
|
|
327
|
+
className,
|
|
328
|
+
...props
|
|
329
|
+
}) {
|
|
330
|
+
return /* @__PURE__ */ jsx4(
|
|
331
|
+
DropdownMenuPrimitive.SubContent,
|
|
332
|
+
{
|
|
333
|
+
"data-slot": "dropdown-menu-sub-content",
|
|
334
|
+
className: cn(
|
|
335
|
+
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
|
336
|
+
className
|
|
337
|
+
),
|
|
338
|
+
...props
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/components/chat/CopilotChatAudioRecorder.tsx
|
|
344
|
+
import { useRef, useEffect, useImperativeHandle, forwardRef } from "react";
|
|
345
|
+
import { twMerge as twMerge2 } from "tailwind-merge";
|
|
346
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
347
|
+
var AudioRecorderError = class extends Error {
|
|
348
|
+
constructor(message) {
|
|
349
|
+
super(message);
|
|
350
|
+
this.name = "AudioRecorderError";
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
var CopilotChatAudioRecorder = forwardRef((props, ref) => {
|
|
354
|
+
const { className, ...divProps } = props;
|
|
355
|
+
const canvasRef = useRef(null);
|
|
356
|
+
const getLoudness = (n) => {
|
|
357
|
+
const elapsed = Date.now() / 1e3;
|
|
358
|
+
const samples = [];
|
|
359
|
+
for (let i = 0; i < n; i++) {
|
|
360
|
+
const position = i / n * 10 + elapsed * 0.5;
|
|
361
|
+
const wave1 = Math.sin(position * 2) * 0.3;
|
|
362
|
+
const wave2 = Math.sin(position * 5 + elapsed) * 0.2;
|
|
363
|
+
const wave3 = Math.sin(position * 0.5 + elapsed * 0.3) * 0.4;
|
|
364
|
+
const noise = (Math.random() - 0.5) * 0.1;
|
|
365
|
+
const envelope = Math.sin(elapsed * 0.7) * 0.5 + 0.5;
|
|
366
|
+
let amplitude = (wave1 + wave2 + wave3 + noise) * envelope;
|
|
367
|
+
amplitude = Math.max(0, Math.min(1, amplitude * 0.5 + 0.3));
|
|
368
|
+
samples.push(amplitude);
|
|
369
|
+
}
|
|
370
|
+
return samples;
|
|
371
|
+
};
|
|
372
|
+
useEffect(() => {
|
|
373
|
+
const canvas = canvasRef.current;
|
|
374
|
+
if (!canvas) return;
|
|
375
|
+
const ctx = canvas.getContext("2d");
|
|
376
|
+
if (!ctx) return;
|
|
377
|
+
let animationId;
|
|
378
|
+
const draw = () => {
|
|
379
|
+
const rect = canvas.getBoundingClientRect();
|
|
380
|
+
const dpr = window.devicePixelRatio || 1;
|
|
381
|
+
if (canvas.width !== rect.width * dpr || canvas.height !== rect.height * dpr) {
|
|
382
|
+
canvas.width = rect.width * dpr;
|
|
383
|
+
canvas.height = rect.height * dpr;
|
|
384
|
+
ctx.scale(dpr, dpr);
|
|
385
|
+
ctx.imageSmoothingEnabled = false;
|
|
386
|
+
}
|
|
387
|
+
const barWidth = 2;
|
|
388
|
+
const minHeight = 2;
|
|
389
|
+
const maxHeight = 20;
|
|
390
|
+
const gap = 2;
|
|
391
|
+
const numSamples = Math.ceil(rect.width / (barWidth + gap));
|
|
392
|
+
const loudnessData = getLoudness(numSamples);
|
|
393
|
+
ctx.clearRect(0, 0, rect.width, rect.height);
|
|
394
|
+
const computedStyle = getComputedStyle(canvas);
|
|
395
|
+
const currentForeground = computedStyle.color;
|
|
396
|
+
ctx.fillStyle = currentForeground;
|
|
397
|
+
const centerY = rect.height / 2;
|
|
398
|
+
for (let i = 0; i < loudnessData.length; i++) {
|
|
399
|
+
const sample = loudnessData[i] ?? 0;
|
|
400
|
+
const barHeight = Math.round(
|
|
401
|
+
sample * (maxHeight - minHeight) + minHeight
|
|
402
|
+
);
|
|
403
|
+
const x = Math.round(i * (barWidth + gap));
|
|
404
|
+
const y = Math.round(centerY - barHeight / 2);
|
|
405
|
+
ctx.fillRect(x, y, barWidth, barHeight);
|
|
406
|
+
}
|
|
407
|
+
animationId = requestAnimationFrame(draw);
|
|
408
|
+
};
|
|
409
|
+
draw();
|
|
410
|
+
return () => {
|
|
411
|
+
if (animationId) {
|
|
412
|
+
cancelAnimationFrame(animationId);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}, []);
|
|
416
|
+
useImperativeHandle(
|
|
417
|
+
ref,
|
|
418
|
+
() => ({
|
|
419
|
+
get state() {
|
|
420
|
+
return "idle";
|
|
421
|
+
},
|
|
422
|
+
start: async () => {
|
|
423
|
+
},
|
|
424
|
+
stop: () => new Promise((resolve) => {
|
|
425
|
+
const emptyBlob = new Blob([], { type: "audio/webm" });
|
|
426
|
+
resolve(emptyBlob);
|
|
427
|
+
}),
|
|
428
|
+
dispose: () => {
|
|
429
|
+
}
|
|
430
|
+
}),
|
|
431
|
+
[]
|
|
432
|
+
);
|
|
433
|
+
return /* @__PURE__ */ jsx5("div", { className: twMerge2("h-[44px] w-full px-5", className), ...divProps, children: /* @__PURE__ */ jsx5(
|
|
434
|
+
"canvas",
|
|
435
|
+
{
|
|
436
|
+
ref: canvasRef,
|
|
437
|
+
className: "w-full h-full",
|
|
438
|
+
style: { imageRendering: "pixelated" }
|
|
439
|
+
}
|
|
440
|
+
) });
|
|
441
|
+
});
|
|
442
|
+
CopilotChatAudioRecorder.displayName = "WebAudioRecorder";
|
|
443
|
+
|
|
444
|
+
// src/lib/slots.tsx
|
|
445
|
+
import React2 from "react";
|
|
446
|
+
function renderSlot(slot, DefaultComponent, props) {
|
|
447
|
+
if (typeof slot === "string") {
|
|
448
|
+
return React2.createElement(DefaultComponent, {
|
|
449
|
+
...props,
|
|
450
|
+
className: slot
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
if (typeof slot === "function") {
|
|
454
|
+
const Comp = slot;
|
|
455
|
+
return React2.createElement(Comp, props);
|
|
456
|
+
}
|
|
457
|
+
if (slot && typeof slot === "object" && !React2.isValidElement(slot)) {
|
|
458
|
+
return React2.createElement(DefaultComponent, {
|
|
459
|
+
...props,
|
|
460
|
+
...slot
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return React2.createElement(DefaultComponent, props);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/components/chat/CopilotChatInput.tsx
|
|
467
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
468
|
+
function CopilotChatInput({
|
|
469
|
+
mode = "input",
|
|
470
|
+
onSubmitMessage,
|
|
471
|
+
onStartTranscribe,
|
|
472
|
+
onCancelTranscribe,
|
|
473
|
+
onFinishTranscribe,
|
|
474
|
+
onAddFile,
|
|
475
|
+
onChange,
|
|
476
|
+
value,
|
|
477
|
+
toolsMenu,
|
|
478
|
+
autoFocus = true,
|
|
479
|
+
additionalToolbarItems,
|
|
480
|
+
textArea,
|
|
481
|
+
sendButton,
|
|
482
|
+
startTranscribeButton,
|
|
483
|
+
cancelTranscribeButton,
|
|
484
|
+
finishTranscribeButton,
|
|
485
|
+
addFileButton,
|
|
486
|
+
toolsButton,
|
|
487
|
+
toolbar,
|
|
488
|
+
audioRecorder,
|
|
489
|
+
children,
|
|
490
|
+
className,
|
|
491
|
+
...props
|
|
492
|
+
}) {
|
|
493
|
+
const { inputValue, onSubmitInput, onChangeInput } = useCopilotChatConfiguration();
|
|
494
|
+
value ??= inputValue;
|
|
495
|
+
onSubmitMessage ??= onSubmitInput;
|
|
496
|
+
onChange ??= onChangeInput;
|
|
497
|
+
const inputRef = useRef2(null);
|
|
498
|
+
const audioRecorderRef = useRef2(null);
|
|
499
|
+
useEffect2(() => {
|
|
500
|
+
const recorder = audioRecorderRef.current;
|
|
501
|
+
if (!recorder) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (mode === "transcribe") {
|
|
505
|
+
recorder.start().catch(console.error);
|
|
506
|
+
} else {
|
|
507
|
+
if (recorder.state === "recording") {
|
|
508
|
+
recorder.stop().catch(console.error);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}, [mode]);
|
|
512
|
+
const handleChange = (e) => {
|
|
513
|
+
onChange?.(e.target.value);
|
|
514
|
+
};
|
|
515
|
+
const handleKeyDown = (e) => {
|
|
516
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
517
|
+
e.preventDefault();
|
|
518
|
+
send();
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
const send = () => {
|
|
522
|
+
const trimmed = value?.trim();
|
|
523
|
+
if (trimmed) {
|
|
524
|
+
onSubmitMessage?.(trimmed);
|
|
525
|
+
if (inputRef.current) {
|
|
526
|
+
inputRef.current.focus();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
const BoundTextArea = renderSlot(textArea, CopilotChatInput.TextArea, {
|
|
531
|
+
ref: inputRef,
|
|
532
|
+
value,
|
|
533
|
+
onChange: handleChange,
|
|
534
|
+
onKeyDown: handleKeyDown,
|
|
535
|
+
autoFocus
|
|
536
|
+
});
|
|
537
|
+
const BoundAudioRecorder = renderSlot(
|
|
538
|
+
audioRecorder,
|
|
539
|
+
CopilotChatAudioRecorder,
|
|
540
|
+
{
|
|
541
|
+
ref: audioRecorderRef
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
const BoundSendButton = renderSlot(sendButton, CopilotChatInput.SendButton, {
|
|
545
|
+
onClick: send,
|
|
546
|
+
disabled: !value?.trim() || !onSubmitMessage
|
|
547
|
+
});
|
|
548
|
+
const BoundStartTranscribeButton = renderSlot(
|
|
549
|
+
startTranscribeButton,
|
|
550
|
+
CopilotChatInput.StartTranscribeButton,
|
|
551
|
+
{
|
|
552
|
+
onClick: onStartTranscribe
|
|
553
|
+
}
|
|
554
|
+
);
|
|
555
|
+
const BoundCancelTranscribeButton = renderSlot(
|
|
556
|
+
cancelTranscribeButton,
|
|
557
|
+
CopilotChatInput.CancelTranscribeButton,
|
|
558
|
+
{
|
|
559
|
+
onClick: onCancelTranscribe
|
|
560
|
+
}
|
|
561
|
+
);
|
|
562
|
+
const BoundFinishTranscribeButton = renderSlot(
|
|
563
|
+
finishTranscribeButton,
|
|
564
|
+
CopilotChatInput.FinishTranscribeButton,
|
|
565
|
+
{
|
|
566
|
+
onClick: onFinishTranscribe
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
const BoundAddFileButton = renderSlot(
|
|
570
|
+
addFileButton,
|
|
571
|
+
CopilotChatInput.AddFileButton,
|
|
572
|
+
{
|
|
573
|
+
onClick: onAddFile,
|
|
574
|
+
disabled: mode === "transcribe"
|
|
575
|
+
}
|
|
576
|
+
);
|
|
577
|
+
const BoundToolsButton = renderSlot(
|
|
578
|
+
toolsButton,
|
|
579
|
+
CopilotChatInput.ToolsButton,
|
|
580
|
+
{
|
|
581
|
+
disabled: mode === "transcribe",
|
|
582
|
+
toolsMenu
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
const BoundToolbar = renderSlot(
|
|
586
|
+
typeof toolbar === "string" || toolbar === void 0 ? twMerge3(
|
|
587
|
+
toolbar,
|
|
588
|
+
"w-full h-[60px] bg-transparent flex items-center justify-between"
|
|
589
|
+
) : toolbar,
|
|
590
|
+
CopilotChatInput.Toolbar,
|
|
591
|
+
{
|
|
592
|
+
children: /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
593
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center", children: [
|
|
594
|
+
onAddFile && BoundAddFileButton,
|
|
595
|
+
BoundToolsButton,
|
|
596
|
+
additionalToolbarItems
|
|
597
|
+
] }),
|
|
598
|
+
/* @__PURE__ */ jsx6("div", { className: "flex items-center", children: mode === "transcribe" ? /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
599
|
+
onCancelTranscribe && BoundCancelTranscribeButton,
|
|
600
|
+
onFinishTranscribe && BoundFinishTranscribeButton
|
|
601
|
+
] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
602
|
+
onStartTranscribe && BoundStartTranscribeButton,
|
|
603
|
+
BoundSendButton
|
|
604
|
+
] }) })
|
|
605
|
+
] })
|
|
606
|
+
}
|
|
607
|
+
);
|
|
608
|
+
if (children) {
|
|
609
|
+
return /* @__PURE__ */ jsx6(Fragment, { children: children({
|
|
610
|
+
textArea: BoundTextArea,
|
|
611
|
+
audioRecorder: BoundAudioRecorder,
|
|
612
|
+
sendButton: BoundSendButton,
|
|
613
|
+
startTranscribeButton: BoundStartTranscribeButton,
|
|
614
|
+
cancelTranscribeButton: BoundCancelTranscribeButton,
|
|
615
|
+
finishTranscribeButton: BoundFinishTranscribeButton,
|
|
616
|
+
addFileButton: BoundAddFileButton,
|
|
617
|
+
toolsButton: BoundToolsButton,
|
|
618
|
+
toolbar: BoundToolbar,
|
|
619
|
+
onSubmitMessage,
|
|
620
|
+
onStartTranscribe,
|
|
621
|
+
onCancelTranscribe,
|
|
622
|
+
onFinishTranscribe,
|
|
623
|
+
onAddFile,
|
|
624
|
+
mode,
|
|
625
|
+
toolsMenu,
|
|
626
|
+
autoFocus,
|
|
627
|
+
additionalToolbarItems
|
|
628
|
+
}) });
|
|
629
|
+
}
|
|
630
|
+
return /* @__PURE__ */ jsxs3(
|
|
631
|
+
"div",
|
|
632
|
+
{
|
|
633
|
+
className: twMerge3(
|
|
634
|
+
// Layout
|
|
635
|
+
"flex w-full flex-col items-center justify-center",
|
|
636
|
+
// Interaction
|
|
637
|
+
"cursor-text",
|
|
638
|
+
// Overflow and clipping
|
|
639
|
+
"overflow-visible bg-clip-padding contain-inline-size",
|
|
640
|
+
// Background
|
|
641
|
+
"bg-white dark:bg-[#303030]",
|
|
642
|
+
// Visual effects
|
|
643
|
+
"shadow-[0_4px_4px_0_#0000000a,0_0_1px_0_#0000009e] rounded-[28px]",
|
|
644
|
+
className
|
|
645
|
+
),
|
|
646
|
+
...props,
|
|
647
|
+
children: [
|
|
648
|
+
mode === "transcribe" ? BoundAudioRecorder : BoundTextArea,
|
|
649
|
+
BoundToolbar
|
|
650
|
+
]
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
((CopilotChatInput2) => {
|
|
655
|
+
CopilotChatInput2.SendButton = ({ className, ...props }) => /* @__PURE__ */ jsx6("div", { className: "mr-[10px]", children: /* @__PURE__ */ jsx6(
|
|
656
|
+
Button,
|
|
657
|
+
{
|
|
658
|
+
type: "button",
|
|
659
|
+
variant: "chatInputToolbarPrimary",
|
|
660
|
+
size: "chatInputToolbarIcon",
|
|
661
|
+
className,
|
|
662
|
+
...props,
|
|
663
|
+
children: /* @__PURE__ */ jsx6(ArrowUp, { className: "size-[18px]" })
|
|
664
|
+
}
|
|
665
|
+
) });
|
|
666
|
+
CopilotChatInput2.ToolbarButton = ({ icon, labelKey, defaultClassName, className, ...props }) => {
|
|
667
|
+
const { labels } = useCopilotChatConfiguration();
|
|
668
|
+
return /* @__PURE__ */ jsxs3(Tooltip, { children: [
|
|
669
|
+
/* @__PURE__ */ jsx6(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(
|
|
670
|
+
Button,
|
|
671
|
+
{
|
|
672
|
+
type: "button",
|
|
673
|
+
variant: "chatInputToolbarSecondary",
|
|
674
|
+
size: "chatInputToolbarIcon",
|
|
675
|
+
className: twMerge3(defaultClassName, className),
|
|
676
|
+
...props,
|
|
677
|
+
children: icon
|
|
678
|
+
}
|
|
679
|
+
) }),
|
|
680
|
+
/* @__PURE__ */ jsx6(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsx6("p", { children: labels[labelKey] }) })
|
|
681
|
+
] });
|
|
682
|
+
};
|
|
683
|
+
CopilotChatInput2.StartTranscribeButton = (props) => /* @__PURE__ */ jsx6(
|
|
684
|
+
CopilotChatInput2.ToolbarButton,
|
|
685
|
+
{
|
|
686
|
+
icon: /* @__PURE__ */ jsx6(Mic, { className: "size-[18px]" }),
|
|
687
|
+
labelKey: "chatInputToolbarStartTranscribeButtonLabel",
|
|
688
|
+
defaultClassName: "mr-2",
|
|
689
|
+
...props
|
|
690
|
+
}
|
|
691
|
+
);
|
|
692
|
+
CopilotChatInput2.CancelTranscribeButton = (props) => /* @__PURE__ */ jsx6(
|
|
693
|
+
CopilotChatInput2.ToolbarButton,
|
|
694
|
+
{
|
|
695
|
+
icon: /* @__PURE__ */ jsx6(X, { className: "size-[18px]" }),
|
|
696
|
+
labelKey: "chatInputToolbarCancelTranscribeButtonLabel",
|
|
697
|
+
defaultClassName: "mr-2",
|
|
698
|
+
...props
|
|
699
|
+
}
|
|
700
|
+
);
|
|
701
|
+
CopilotChatInput2.FinishTranscribeButton = (props) => /* @__PURE__ */ jsx6(
|
|
702
|
+
CopilotChatInput2.ToolbarButton,
|
|
703
|
+
{
|
|
704
|
+
icon: /* @__PURE__ */ jsx6(Check, { className: "size-[18px]" }),
|
|
705
|
+
labelKey: "chatInputToolbarFinishTranscribeButtonLabel",
|
|
706
|
+
defaultClassName: "mr-[10px]",
|
|
707
|
+
...props
|
|
708
|
+
}
|
|
709
|
+
);
|
|
710
|
+
CopilotChatInput2.AddFileButton = (props) => /* @__PURE__ */ jsx6(
|
|
711
|
+
CopilotChatInput2.ToolbarButton,
|
|
712
|
+
{
|
|
713
|
+
icon: /* @__PURE__ */ jsx6(Plus, { className: "size-[20px]" }),
|
|
714
|
+
labelKey: "chatInputToolbarAddButtonLabel",
|
|
715
|
+
defaultClassName: "ml-2",
|
|
716
|
+
...props
|
|
717
|
+
}
|
|
718
|
+
);
|
|
719
|
+
CopilotChatInput2.ToolsButton = ({ className, toolsMenu, ...props }) => {
|
|
720
|
+
const { labels } = useCopilotChatConfiguration();
|
|
721
|
+
const renderMenuItems = (items) => {
|
|
722
|
+
return items.map((item, index) => {
|
|
723
|
+
if (item === "-") {
|
|
724
|
+
return /* @__PURE__ */ jsx6(DropdownMenuSeparator, {}, index);
|
|
725
|
+
} else if (item.items && item.items.length > 0) {
|
|
726
|
+
return /* @__PURE__ */ jsxs3(DropdownMenuSub, { children: [
|
|
727
|
+
/* @__PURE__ */ jsx6(DropdownMenuSubTrigger, { children: item.label }),
|
|
728
|
+
/* @__PURE__ */ jsx6(DropdownMenuSubContent, { children: renderMenuItems(item.items) })
|
|
729
|
+
] }, index);
|
|
730
|
+
} else {
|
|
731
|
+
return /* @__PURE__ */ jsx6(DropdownMenuItem, { onClick: item.action, children: item.label }, index);
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
};
|
|
735
|
+
if (!toolsMenu || toolsMenu.length === 0) {
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
return /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
|
|
739
|
+
/* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs3(
|
|
740
|
+
Button,
|
|
741
|
+
{
|
|
742
|
+
type: "button",
|
|
743
|
+
variant: "chatInputToolbarSecondary",
|
|
744
|
+
size: "chatInputToolbarIconLabel",
|
|
745
|
+
className,
|
|
746
|
+
...props,
|
|
747
|
+
children: [
|
|
748
|
+
/* @__PURE__ */ jsx6(Settings2, { className: "size-[18px]" }),
|
|
749
|
+
/* @__PURE__ */ jsx6("span", { className: "text-sm font-normal", children: labels.chatInputToolbarToolsButtonLabel })
|
|
750
|
+
]
|
|
751
|
+
}
|
|
752
|
+
) }),
|
|
753
|
+
/* @__PURE__ */ jsx6(DropdownMenuContent, { side: "top", align: "end", children: renderMenuItems(toolsMenu) })
|
|
754
|
+
] });
|
|
755
|
+
};
|
|
756
|
+
CopilotChatInput2.Toolbar = ({
|
|
757
|
+
className,
|
|
758
|
+
...props
|
|
759
|
+
}) => /* @__PURE__ */ jsx6(
|
|
760
|
+
"div",
|
|
761
|
+
{
|
|
762
|
+
className: twMerge3(
|
|
763
|
+
"w-full h-[60px] bg-transparent flex items-center",
|
|
764
|
+
className
|
|
765
|
+
),
|
|
766
|
+
...props
|
|
767
|
+
}
|
|
768
|
+
);
|
|
769
|
+
CopilotChatInput2.TextArea = forwardRef2(
|
|
770
|
+
function TextArea2({ maxRows = 5, style, className, ...props }, ref) {
|
|
771
|
+
const internalTextareaRef = useRef2(null);
|
|
772
|
+
const [maxHeight, setMaxHeight] = useState(0);
|
|
773
|
+
const { labels } = useCopilotChatConfiguration();
|
|
774
|
+
useImperativeHandle2(
|
|
775
|
+
ref,
|
|
776
|
+
() => internalTextareaRef.current
|
|
777
|
+
);
|
|
778
|
+
const adjustHeight = () => {
|
|
779
|
+
const textarea = internalTextareaRef.current;
|
|
780
|
+
if (textarea && maxHeight > 0) {
|
|
781
|
+
textarea.style.height = "auto";
|
|
782
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
useEffect2(() => {
|
|
786
|
+
const calculateMaxHeight = () => {
|
|
787
|
+
const textarea = internalTextareaRef.current;
|
|
788
|
+
if (textarea) {
|
|
789
|
+
const currentValue = textarea.value;
|
|
790
|
+
textarea.value = "";
|
|
791
|
+
textarea.style.height = "auto";
|
|
792
|
+
const computedStyle = window.getComputedStyle(textarea);
|
|
793
|
+
const paddingTop = parseFloat(computedStyle.paddingTop);
|
|
794
|
+
const paddingBottom = parseFloat(computedStyle.paddingBottom);
|
|
795
|
+
const contentHeight = textarea.scrollHeight - paddingTop - paddingBottom;
|
|
796
|
+
setMaxHeight(contentHeight * maxRows + paddingTop + paddingBottom);
|
|
797
|
+
textarea.value = currentValue;
|
|
798
|
+
if (currentValue) {
|
|
799
|
+
textarea.style.height = "auto";
|
|
800
|
+
textarea.style.height = `${Math.min(textarea.scrollHeight, contentHeight * maxRows + paddingTop + paddingBottom)}px`;
|
|
801
|
+
}
|
|
802
|
+
if (props.autoFocus) {
|
|
803
|
+
textarea.focus();
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
calculateMaxHeight();
|
|
808
|
+
}, [maxRows, props.autoFocus]);
|
|
809
|
+
useEffect2(() => {
|
|
810
|
+
adjustHeight();
|
|
811
|
+
}, [props.value, maxHeight]);
|
|
812
|
+
const handleInput = (e) => {
|
|
813
|
+
adjustHeight();
|
|
814
|
+
if (props.onChange) {
|
|
815
|
+
props.onChange(e);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
return /* @__PURE__ */ jsx6(
|
|
819
|
+
"textarea",
|
|
820
|
+
{
|
|
821
|
+
ref: internalTextareaRef,
|
|
822
|
+
...props,
|
|
823
|
+
onChange: handleInput,
|
|
824
|
+
style: {
|
|
825
|
+
overflow: "auto",
|
|
826
|
+
resize: "none",
|
|
827
|
+
maxHeight: `${maxHeight}px`,
|
|
828
|
+
...style
|
|
829
|
+
},
|
|
830
|
+
placeholder: labels.chatInputPlaceholder,
|
|
831
|
+
className: twMerge3(
|
|
832
|
+
// Layout and sizing
|
|
833
|
+
"w-full p-5 pb-0",
|
|
834
|
+
// Behavior
|
|
835
|
+
"outline-none resize-none",
|
|
836
|
+
// Background
|
|
837
|
+
"bg-transparent",
|
|
838
|
+
// Typography
|
|
839
|
+
"antialiased font-regular leading-relaxed text-[16px]",
|
|
840
|
+
// Placeholder styles
|
|
841
|
+
"placeholder:text-[#00000077] dark:placeholder:text-[#fffc]",
|
|
842
|
+
className
|
|
843
|
+
),
|
|
844
|
+
rows: 1
|
|
845
|
+
}
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
);
|
|
849
|
+
CopilotChatInput2.AudioRecorder = CopilotChatAudioRecorder;
|
|
850
|
+
})(CopilotChatInput || (CopilotChatInput = {}));
|
|
851
|
+
CopilotChatInput.TextArea.displayName = "CopilotChatInput.TextArea";
|
|
852
|
+
CopilotChatInput.SendButton.displayName = "CopilotChatInput.SendButton";
|
|
853
|
+
CopilotChatInput.ToolbarButton.displayName = "CopilotChatInput.ToolbarButton";
|
|
854
|
+
CopilotChatInput.StartTranscribeButton.displayName = "CopilotChatInput.StartTranscribeButton";
|
|
855
|
+
CopilotChatInput.CancelTranscribeButton.displayName = "CopilotChatInput.CancelTranscribeButton";
|
|
856
|
+
CopilotChatInput.FinishTranscribeButton.displayName = "CopilotChatInput.FinishTranscribeButton";
|
|
857
|
+
CopilotChatInput.AddFileButton.displayName = "CopilotChatInput.AddButton";
|
|
858
|
+
CopilotChatInput.ToolsButton.displayName = "CopilotChatInput.ToolsButton";
|
|
859
|
+
CopilotChatInput.Toolbar.displayName = "CopilotChatInput.Toolbar";
|
|
860
|
+
var CopilotChatInput_default = CopilotChatInput;
|
|
861
|
+
|
|
862
|
+
// src/components/chat/CopilotChatAssistantMessage.tsx
|
|
863
|
+
import { MarkdownHooks } from "react-markdown";
|
|
864
|
+
import remarkGfm from "remark-gfm";
|
|
865
|
+
import remarkMath from "remark-math";
|
|
866
|
+
import rehypePrettyCode from "rehype-pretty-code";
|
|
867
|
+
import rehypeKatex from "rehype-katex";
|
|
868
|
+
import { useState as useState5 } from "react";
|
|
869
|
+
import {
|
|
870
|
+
Copy,
|
|
871
|
+
Check as Check2,
|
|
872
|
+
ThumbsUp,
|
|
873
|
+
ThumbsDown,
|
|
874
|
+
Volume2,
|
|
875
|
+
RefreshCw
|
|
876
|
+
} from "lucide-react";
|
|
877
|
+
import { twMerge as twMerge4 } from "tailwind-merge";
|
|
878
|
+
import "katex/dist/katex.min.css";
|
|
879
|
+
import { completePartialMarkdown } from "@copilotkitnext/core";
|
|
880
|
+
|
|
881
|
+
// src/hooks/use-render-tool-call.tsx
|
|
882
|
+
import { useCallback } from "react";
|
|
883
|
+
import { ToolCallStatus } from "@copilotkitnext/core";
|
|
884
|
+
|
|
885
|
+
// src/providers/CopilotKitProvider.tsx
|
|
886
|
+
import {
|
|
887
|
+
createContext as createContext2,
|
|
888
|
+
useContext as useContext2,
|
|
889
|
+
useMemo,
|
|
890
|
+
useEffect as useEffect3,
|
|
891
|
+
useState as useState2,
|
|
892
|
+
useReducer,
|
|
893
|
+
useRef as useRef3
|
|
894
|
+
} from "react";
|
|
895
|
+
import {
|
|
896
|
+
CopilotKitCore
|
|
897
|
+
} from "@copilotkitnext/core";
|
|
898
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
899
|
+
var CopilotKitContext = createContext2({
|
|
900
|
+
copilotkit: null,
|
|
901
|
+
renderToolCalls: [],
|
|
902
|
+
currentRenderToolCalls: [],
|
|
903
|
+
setCurrentRenderToolCalls: () => {
|
|
904
|
+
}
|
|
905
|
+
});
|
|
906
|
+
function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
|
|
907
|
+
const empty = useMemo(() => [], []);
|
|
908
|
+
const value = prop ?? empty;
|
|
909
|
+
const initial = useRef3(value);
|
|
910
|
+
useEffect3(() => {
|
|
911
|
+
if (warningMessage && value !== initial.current && (isMeaningfulChange ? isMeaningfulChange(initial.current, value) : true)) {
|
|
912
|
+
console.error(warningMessage);
|
|
913
|
+
}
|
|
914
|
+
}, [value, warningMessage]);
|
|
915
|
+
return value;
|
|
916
|
+
}
|
|
917
|
+
var CopilotKitProvider = ({
|
|
918
|
+
children,
|
|
919
|
+
runtimeUrl,
|
|
920
|
+
headers = {},
|
|
921
|
+
properties = {},
|
|
922
|
+
agents = {},
|
|
923
|
+
renderToolCalls,
|
|
924
|
+
frontendTools,
|
|
925
|
+
humanInTheLoop
|
|
926
|
+
}) => {
|
|
927
|
+
const renderToolCallsList = useStableArrayProp(
|
|
928
|
+
renderToolCalls,
|
|
929
|
+
"renderToolCalls must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.",
|
|
930
|
+
(initial, next) => {
|
|
931
|
+
const key = (rc) => `${rc?.agentId ?? ""}:${rc?.name ?? ""}`;
|
|
932
|
+
const setFrom = (arr) => new Set(arr.map(key));
|
|
933
|
+
const a = setFrom(initial);
|
|
934
|
+
const b = setFrom(next);
|
|
935
|
+
if (a.size !== b.size) return true;
|
|
936
|
+
for (const k of a) if (!b.has(k)) return true;
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
);
|
|
940
|
+
const frontendToolsList = useStableArrayProp(
|
|
941
|
+
frontendTools,
|
|
942
|
+
"frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead."
|
|
943
|
+
);
|
|
944
|
+
const humanInTheLoopList = useStableArrayProp(
|
|
945
|
+
humanInTheLoop,
|
|
946
|
+
"humanInTheLoop must be a stable array. If you want to dynamically add or remove human-in-the-loop tools, use `useHumanInTheLoop` instead."
|
|
947
|
+
);
|
|
948
|
+
const initialRenderToolCalls = useMemo(() => renderToolCallsList, []);
|
|
949
|
+
const [currentRenderToolCalls, setCurrentRenderToolCalls] = useState2([]);
|
|
950
|
+
const processedHumanInTheLoopTools = useMemo(() => {
|
|
951
|
+
const processedTools = [];
|
|
952
|
+
const processedRenderToolCalls = [];
|
|
953
|
+
humanInTheLoopList.forEach((tool) => {
|
|
954
|
+
const frontendTool = {
|
|
955
|
+
name: tool.name,
|
|
956
|
+
description: tool.description,
|
|
957
|
+
parameters: tool.parameters,
|
|
958
|
+
followUp: tool.followUp,
|
|
959
|
+
...tool.agentId && { agentId: tool.agentId },
|
|
960
|
+
handler: async () => {
|
|
961
|
+
return new Promise((resolve) => {
|
|
962
|
+
console.warn(
|
|
963
|
+
`Human-in-the-loop tool '${tool.name}' called but no interactive handler is set up.`
|
|
964
|
+
);
|
|
965
|
+
resolve(void 0);
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
processedTools.push(frontendTool);
|
|
970
|
+
if (tool.render) {
|
|
971
|
+
processedRenderToolCalls.push({
|
|
972
|
+
name: tool.name,
|
|
973
|
+
args: tool.parameters,
|
|
974
|
+
render: tool.render,
|
|
975
|
+
...tool.agentId && { agentId: tool.agentId }
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
return { tools: processedTools, renderToolCalls: processedRenderToolCalls };
|
|
980
|
+
}, [humanInTheLoopList]);
|
|
981
|
+
const allTools = useMemo(() => {
|
|
982
|
+
const tools = {};
|
|
983
|
+
frontendToolsList.forEach((tool) => {
|
|
984
|
+
tools[tool.name] = tool;
|
|
985
|
+
});
|
|
986
|
+
processedHumanInTheLoopTools.tools.forEach((tool) => {
|
|
987
|
+
tools[tool.name] = tool;
|
|
988
|
+
});
|
|
989
|
+
return tools;
|
|
990
|
+
}, [frontendToolsList, processedHumanInTheLoopTools]);
|
|
991
|
+
const allRenderToolCalls = useMemo(() => {
|
|
992
|
+
const combined = [...renderToolCallsList];
|
|
993
|
+
frontendToolsList.forEach((tool) => {
|
|
994
|
+
if (tool.render && tool.parameters) {
|
|
995
|
+
combined.push({
|
|
996
|
+
name: tool.name,
|
|
997
|
+
args: tool.parameters,
|
|
998
|
+
render: tool.render
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
combined.push(...processedHumanInTheLoopTools.renderToolCalls);
|
|
1003
|
+
return combined;
|
|
1004
|
+
}, [renderToolCallsList, frontendToolsList, processedHumanInTheLoopTools]);
|
|
1005
|
+
const copilotkit = useMemo(() => {
|
|
1006
|
+
const config = {
|
|
1007
|
+
// Don't set runtimeUrl during initialization to prevent server-side fetching
|
|
1008
|
+
runtimeUrl: void 0,
|
|
1009
|
+
headers,
|
|
1010
|
+
properties,
|
|
1011
|
+
agents,
|
|
1012
|
+
tools: allTools
|
|
1013
|
+
};
|
|
1014
|
+
const copilotkit2 = new CopilotKitCore(config);
|
|
1015
|
+
return copilotkit2;
|
|
1016
|
+
}, [allTools]);
|
|
1017
|
+
useEffect3(() => {
|
|
1018
|
+
setCurrentRenderToolCalls(
|
|
1019
|
+
(prev) => prev === allRenderToolCalls ? prev : allRenderToolCalls
|
|
1020
|
+
);
|
|
1021
|
+
}, [allRenderToolCalls]);
|
|
1022
|
+
useEffect3(() => {
|
|
1023
|
+
copilotkit.setRuntimeUrl(runtimeUrl);
|
|
1024
|
+
copilotkit.setHeaders(headers);
|
|
1025
|
+
copilotkit.setProperties(properties);
|
|
1026
|
+
copilotkit.setAgents(agents);
|
|
1027
|
+
}, [runtimeUrl, headers, properties, agents]);
|
|
1028
|
+
return /* @__PURE__ */ jsx7(
|
|
1029
|
+
CopilotKitContext.Provider,
|
|
1030
|
+
{
|
|
1031
|
+
value: {
|
|
1032
|
+
copilotkit,
|
|
1033
|
+
renderToolCalls: allRenderToolCalls,
|
|
1034
|
+
currentRenderToolCalls,
|
|
1035
|
+
setCurrentRenderToolCalls
|
|
1036
|
+
},
|
|
1037
|
+
children
|
|
1038
|
+
}
|
|
1039
|
+
);
|
|
1040
|
+
};
|
|
1041
|
+
var useCopilotKit = () => {
|
|
1042
|
+
const context = useContext2(CopilotKitContext);
|
|
1043
|
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
1044
|
+
if (!context) {
|
|
1045
|
+
throw new Error("useCopilotKit must be used within CopilotKitProvider");
|
|
1046
|
+
}
|
|
1047
|
+
useEffect3(() => {
|
|
1048
|
+
const unsubscribe = context.copilotkit.subscribe({
|
|
1049
|
+
onRuntimeLoaded: () => {
|
|
1050
|
+
forceUpdate();
|
|
1051
|
+
},
|
|
1052
|
+
onRuntimeLoadError: () => {
|
|
1053
|
+
forceUpdate();
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
return () => {
|
|
1057
|
+
unsubscribe();
|
|
1058
|
+
};
|
|
1059
|
+
}, []);
|
|
1060
|
+
return context;
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
// src/hooks/use-render-tool-call.tsx
|
|
1064
|
+
import { partialJSONParse } from "@copilotkitnext/shared";
|
|
1065
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1066
|
+
function useRenderToolCall() {
|
|
1067
|
+
const { currentRenderToolCalls } = useCopilotKit();
|
|
1068
|
+
const renderToolCall = useCallback(
|
|
1069
|
+
({
|
|
1070
|
+
toolCall,
|
|
1071
|
+
toolMessage,
|
|
1072
|
+
isLoading
|
|
1073
|
+
}) => {
|
|
1074
|
+
const renderConfig = currentRenderToolCalls.find(
|
|
1075
|
+
(rc) => rc.name === toolCall.function.name
|
|
1076
|
+
) || currentRenderToolCalls.find((rc) => rc.name === "*");
|
|
1077
|
+
if (!renderConfig) {
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
const RenderComponent = renderConfig.render;
|
|
1081
|
+
const args = partialJSONParse(toolCall.function.arguments);
|
|
1082
|
+
if (toolMessage) {
|
|
1083
|
+
return /* @__PURE__ */ jsx8(
|
|
1084
|
+
RenderComponent,
|
|
1085
|
+
{
|
|
1086
|
+
args,
|
|
1087
|
+
status: ToolCallStatus.Complete,
|
|
1088
|
+
result: toolMessage.content
|
|
1089
|
+
},
|
|
1090
|
+
toolCall.id
|
|
1091
|
+
);
|
|
1092
|
+
} else if (isLoading) {
|
|
1093
|
+
return /* @__PURE__ */ jsx8(
|
|
1094
|
+
RenderComponent,
|
|
1095
|
+
{
|
|
1096
|
+
args,
|
|
1097
|
+
status: ToolCallStatus.InProgress,
|
|
1098
|
+
result: void 0
|
|
1099
|
+
},
|
|
1100
|
+
toolCall.id
|
|
1101
|
+
);
|
|
1102
|
+
} else {
|
|
1103
|
+
return /* @__PURE__ */ jsx8(
|
|
1104
|
+
RenderComponent,
|
|
1105
|
+
{
|
|
1106
|
+
args,
|
|
1107
|
+
status: ToolCallStatus.Complete,
|
|
1108
|
+
result: ""
|
|
1109
|
+
},
|
|
1110
|
+
toolCall.id
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
},
|
|
1114
|
+
[currentRenderToolCalls]
|
|
1115
|
+
);
|
|
1116
|
+
return renderToolCall;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// src/hooks/use-frontend-tool.tsx
|
|
1120
|
+
import { useEffect as useEffect4 } from "react";
|
|
1121
|
+
function useFrontendTool(tool) {
|
|
1122
|
+
const { renderToolCalls, copilotkit, setCurrentRenderToolCalls } = useCopilotKit();
|
|
1123
|
+
useEffect4(() => {
|
|
1124
|
+
if (tool.name in copilotkit.tools) {
|
|
1125
|
+
console.warn(
|
|
1126
|
+
`Tool '${tool.name}' already exists. It will be overridden.`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
copilotkit.addTool(tool);
|
|
1130
|
+
if (tool.render && tool.name in renderToolCalls) {
|
|
1131
|
+
console.warn(
|
|
1132
|
+
`Render component for tool '${tool.name}' already exists. It will be overridden.`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
if (tool.render && tool.parameters) {
|
|
1136
|
+
setCurrentRenderToolCalls((prev) => [
|
|
1137
|
+
...prev,
|
|
1138
|
+
{
|
|
1139
|
+
name: tool.name,
|
|
1140
|
+
args: tool.parameters,
|
|
1141
|
+
render: tool.render
|
|
1142
|
+
}
|
|
1143
|
+
]);
|
|
1144
|
+
}
|
|
1145
|
+
return () => {
|
|
1146
|
+
copilotkit.removeTool(tool.name);
|
|
1147
|
+
setCurrentRenderToolCalls(
|
|
1148
|
+
(prev) => prev.filter((rc) => rc.name !== tool.name)
|
|
1149
|
+
);
|
|
1150
|
+
};
|
|
1151
|
+
}, [tool, copilotkit, renderToolCalls, setCurrentRenderToolCalls]);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// src/hooks/use-human-in-the-loop.tsx
|
|
1155
|
+
import { useState as useState3, useCallback as useCallback2, useRef as useRef4 } from "react";
|
|
1156
|
+
import React6 from "react";
|
|
1157
|
+
function useHumanInTheLoop(tool) {
|
|
1158
|
+
const [status, setStatus] = useState3(
|
|
1159
|
+
"inProgress"
|
|
1160
|
+
);
|
|
1161
|
+
const resolvePromiseRef = useRef4(null);
|
|
1162
|
+
const respond = useCallback2(async (result) => {
|
|
1163
|
+
if (resolvePromiseRef.current) {
|
|
1164
|
+
resolvePromiseRef.current(result);
|
|
1165
|
+
setStatus("complete");
|
|
1166
|
+
resolvePromiseRef.current = null;
|
|
1167
|
+
}
|
|
1168
|
+
}, []);
|
|
1169
|
+
const handler = useCallback2(async () => {
|
|
1170
|
+
return new Promise((resolve) => {
|
|
1171
|
+
setStatus("executing");
|
|
1172
|
+
resolvePromiseRef.current = resolve;
|
|
1173
|
+
});
|
|
1174
|
+
}, []);
|
|
1175
|
+
const RenderComponent = useCallback2(
|
|
1176
|
+
(props) => {
|
|
1177
|
+
const ToolComponent = tool.render;
|
|
1178
|
+
if (status === "inProgress" && props.status === "inProgress") {
|
|
1179
|
+
const enhancedProps = {
|
|
1180
|
+
...props,
|
|
1181
|
+
name: tool.name,
|
|
1182
|
+
description: tool.description || "",
|
|
1183
|
+
respond: void 0
|
|
1184
|
+
};
|
|
1185
|
+
return React6.createElement(ToolComponent, enhancedProps);
|
|
1186
|
+
} else if (status === "executing" && props.status === "executing") {
|
|
1187
|
+
const enhancedProps = {
|
|
1188
|
+
...props,
|
|
1189
|
+
name: tool.name,
|
|
1190
|
+
description: tool.description || "",
|
|
1191
|
+
respond
|
|
1192
|
+
};
|
|
1193
|
+
return React6.createElement(ToolComponent, enhancedProps);
|
|
1194
|
+
} else if (status === "complete" && props.status === "complete") {
|
|
1195
|
+
const enhancedProps = {
|
|
1196
|
+
...props,
|
|
1197
|
+
name: tool.name,
|
|
1198
|
+
description: tool.description || "",
|
|
1199
|
+
respond: void 0
|
|
1200
|
+
};
|
|
1201
|
+
return React6.createElement(ToolComponent, enhancedProps);
|
|
1202
|
+
}
|
|
1203
|
+
return React6.createElement(ToolComponent, props);
|
|
1204
|
+
},
|
|
1205
|
+
[tool.render, tool.name, tool.description, status, respond]
|
|
1206
|
+
);
|
|
1207
|
+
const frontendTool = {
|
|
1208
|
+
...tool,
|
|
1209
|
+
handler,
|
|
1210
|
+
render: RenderComponent
|
|
1211
|
+
};
|
|
1212
|
+
useFrontendTool(frontendTool);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// src/hooks/use-agent.tsx
|
|
1216
|
+
import { useMemo as useMemo2, useEffect as useEffect5, useReducer as useReducer2, useState as useState4 } from "react";
|
|
1217
|
+
import { DEFAULT_AGENT_ID } from "@copilotkitnext/shared";
|
|
1218
|
+
function useAgent({ agentId } = {}) {
|
|
1219
|
+
agentId ??= DEFAULT_AGENT_ID;
|
|
1220
|
+
const { copilotkit } = useCopilotKit();
|
|
1221
|
+
const [, forceUpdate] = useReducer2((x) => x + 1, 0);
|
|
1222
|
+
const [isRunning, setIsRunning] = useState4(false);
|
|
1223
|
+
const agent = useMemo2(() => {
|
|
1224
|
+
return copilotkit.getAgent(agentId);
|
|
1225
|
+
}, [agentId, copilotkit.agents, copilotkit.didLoadRuntime, copilotkit]);
|
|
1226
|
+
useEffect5(() => {
|
|
1227
|
+
const subscription = agent?.subscribe({
|
|
1228
|
+
onMessagesChanged() {
|
|
1229
|
+
forceUpdate();
|
|
1230
|
+
},
|
|
1231
|
+
onStateChanged() {
|
|
1232
|
+
forceUpdate();
|
|
1233
|
+
},
|
|
1234
|
+
onRunInitialized() {
|
|
1235
|
+
setIsRunning(true);
|
|
1236
|
+
},
|
|
1237
|
+
onRunFinalized() {
|
|
1238
|
+
setIsRunning(false);
|
|
1239
|
+
},
|
|
1240
|
+
onRunFailed() {
|
|
1241
|
+
setIsRunning(false);
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
return () => subscription?.unsubscribe();
|
|
1245
|
+
}, [agent]);
|
|
1246
|
+
return {
|
|
1247
|
+
agent,
|
|
1248
|
+
isRunning
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// src/hooks/use-agent-context.tsx
|
|
1253
|
+
import { useEffect as useEffect6 } from "react";
|
|
1254
|
+
function useAgentContext(context) {
|
|
1255
|
+
const { description, value } = context;
|
|
1256
|
+
const { copilotkit } = useCopilotKit();
|
|
1257
|
+
useEffect6(() => {
|
|
1258
|
+
if (!copilotkit) return;
|
|
1259
|
+
const id = copilotkit.addContext(context);
|
|
1260
|
+
return () => {
|
|
1261
|
+
copilotkit.removeContext(id);
|
|
1262
|
+
};
|
|
1263
|
+
}, [description, value, copilotkit]);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// src/components/chat/CopilotChatToolCallsView.tsx
|
|
1267
|
+
import React7 from "react";
|
|
1268
|
+
import { Fragment as Fragment2, jsx as jsx9 } from "react/jsx-runtime";
|
|
1269
|
+
function CopilotChatToolCallsView({
|
|
1270
|
+
message,
|
|
1271
|
+
messages = [],
|
|
1272
|
+
isLoading = false
|
|
1273
|
+
}) {
|
|
1274
|
+
const renderToolCall = useRenderToolCall();
|
|
1275
|
+
if (!message.toolCalls || message.toolCalls.length === 0) {
|
|
1276
|
+
return null;
|
|
1277
|
+
}
|
|
1278
|
+
return /* @__PURE__ */ jsx9(Fragment2, { children: message.toolCalls.map((toolCall) => {
|
|
1279
|
+
const toolMessage = messages.find(
|
|
1280
|
+
(m) => m.role === "tool" && m.toolCallId === toolCall.id
|
|
1281
|
+
);
|
|
1282
|
+
return /* @__PURE__ */ jsx9(React7.Fragment, { children: renderToolCall({
|
|
1283
|
+
toolCall,
|
|
1284
|
+
toolMessage,
|
|
1285
|
+
isLoading
|
|
1286
|
+
}) }, toolCall.id);
|
|
1287
|
+
}) });
|
|
1288
|
+
}
|
|
1289
|
+
var CopilotChatToolCallsView_default = CopilotChatToolCallsView;
|
|
1290
|
+
|
|
1291
|
+
// src/components/chat/CopilotChatAssistantMessage.tsx
|
|
1292
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1293
|
+
function CopilotChatAssistantMessage({
|
|
1294
|
+
message,
|
|
1295
|
+
messages,
|
|
1296
|
+
isLoading,
|
|
1297
|
+
onThumbsUp,
|
|
1298
|
+
onThumbsDown,
|
|
1299
|
+
onReadAloud,
|
|
1300
|
+
onRegenerate,
|
|
1301
|
+
additionalToolbarItems,
|
|
1302
|
+
toolbarVisible = true,
|
|
1303
|
+
markdownRenderer,
|
|
1304
|
+
toolbar,
|
|
1305
|
+
copyButton,
|
|
1306
|
+
thumbsUpButton,
|
|
1307
|
+
thumbsDownButton,
|
|
1308
|
+
readAloudButton,
|
|
1309
|
+
regenerateButton,
|
|
1310
|
+
toolCallsView,
|
|
1311
|
+
children,
|
|
1312
|
+
className,
|
|
1313
|
+
...props
|
|
1314
|
+
}) {
|
|
1315
|
+
const boundMarkdownRenderer = renderSlot(
|
|
1316
|
+
markdownRenderer,
|
|
1317
|
+
CopilotChatAssistantMessage.MarkdownRenderer,
|
|
1318
|
+
{
|
|
1319
|
+
content: message.content || ""
|
|
1320
|
+
}
|
|
1321
|
+
);
|
|
1322
|
+
const boundCopyButton = renderSlot(
|
|
1323
|
+
copyButton,
|
|
1324
|
+
CopilotChatAssistantMessage.CopyButton,
|
|
1325
|
+
{
|
|
1326
|
+
onClick: async () => {
|
|
1327
|
+
if (message.content) {
|
|
1328
|
+
try {
|
|
1329
|
+
await navigator.clipboard.writeText(message.content);
|
|
1330
|
+
} catch (err) {
|
|
1331
|
+
console.error("Failed to copy message:", err);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
);
|
|
1337
|
+
const boundThumbsUpButton = renderSlot(
|
|
1338
|
+
thumbsUpButton,
|
|
1339
|
+
CopilotChatAssistantMessage.ThumbsUpButton,
|
|
1340
|
+
{
|
|
1341
|
+
onClick: onThumbsUp
|
|
1342
|
+
}
|
|
1343
|
+
);
|
|
1344
|
+
const boundThumbsDownButton = renderSlot(
|
|
1345
|
+
thumbsDownButton,
|
|
1346
|
+
CopilotChatAssistantMessage.ThumbsDownButton,
|
|
1347
|
+
{
|
|
1348
|
+
onClick: onThumbsDown
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
const boundReadAloudButton = renderSlot(
|
|
1352
|
+
readAloudButton,
|
|
1353
|
+
CopilotChatAssistantMessage.ReadAloudButton,
|
|
1354
|
+
{
|
|
1355
|
+
onClick: onReadAloud
|
|
1356
|
+
}
|
|
1357
|
+
);
|
|
1358
|
+
const boundRegenerateButton = renderSlot(
|
|
1359
|
+
regenerateButton,
|
|
1360
|
+
CopilotChatAssistantMessage.RegenerateButton,
|
|
1361
|
+
{
|
|
1362
|
+
onClick: onRegenerate
|
|
1363
|
+
}
|
|
1364
|
+
);
|
|
1365
|
+
const boundToolbar = renderSlot(
|
|
1366
|
+
toolbar,
|
|
1367
|
+
CopilotChatAssistantMessage.Toolbar,
|
|
1368
|
+
{
|
|
1369
|
+
children: /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-1", children: [
|
|
1370
|
+
boundCopyButton,
|
|
1371
|
+
(onThumbsUp || thumbsUpButton) && boundThumbsUpButton,
|
|
1372
|
+
(onThumbsDown || thumbsDownButton) && boundThumbsDownButton,
|
|
1373
|
+
(onReadAloud || readAloudButton) && boundReadAloudButton,
|
|
1374
|
+
(onRegenerate || regenerateButton) && boundRegenerateButton,
|
|
1375
|
+
additionalToolbarItems
|
|
1376
|
+
] })
|
|
1377
|
+
}
|
|
1378
|
+
);
|
|
1379
|
+
const boundToolCallsView = renderSlot(
|
|
1380
|
+
toolCallsView,
|
|
1381
|
+
CopilotChatToolCallsView_default,
|
|
1382
|
+
{
|
|
1383
|
+
message,
|
|
1384
|
+
messages,
|
|
1385
|
+
isLoading
|
|
1386
|
+
}
|
|
1387
|
+
);
|
|
1388
|
+
if (children) {
|
|
1389
|
+
return /* @__PURE__ */ jsx10(Fragment3, { children: children({
|
|
1390
|
+
markdownRenderer: boundMarkdownRenderer,
|
|
1391
|
+
toolbar: boundToolbar,
|
|
1392
|
+
toolCallsView: boundToolCallsView,
|
|
1393
|
+
copyButton: boundCopyButton,
|
|
1394
|
+
thumbsUpButton: boundThumbsUpButton,
|
|
1395
|
+
thumbsDownButton: boundThumbsDownButton,
|
|
1396
|
+
readAloudButton: boundReadAloudButton,
|
|
1397
|
+
regenerateButton: boundRegenerateButton,
|
|
1398
|
+
message,
|
|
1399
|
+
messages,
|
|
1400
|
+
isLoading,
|
|
1401
|
+
onThumbsUp,
|
|
1402
|
+
onThumbsDown,
|
|
1403
|
+
onReadAloud,
|
|
1404
|
+
onRegenerate,
|
|
1405
|
+
additionalToolbarItems,
|
|
1406
|
+
toolbarVisible
|
|
1407
|
+
}) });
|
|
1408
|
+
}
|
|
1409
|
+
return /* @__PURE__ */ jsxs4(
|
|
1410
|
+
"div",
|
|
1411
|
+
{
|
|
1412
|
+
className: twMerge4(
|
|
1413
|
+
"prose max-w-full break-words dark:prose-invert",
|
|
1414
|
+
className
|
|
1415
|
+
),
|
|
1416
|
+
...props,
|
|
1417
|
+
"data-message-id": message.id,
|
|
1418
|
+
children: [
|
|
1419
|
+
boundMarkdownRenderer,
|
|
1420
|
+
boundToolCallsView,
|
|
1421
|
+
toolbarVisible && boundToolbar
|
|
1422
|
+
]
|
|
1423
|
+
}
|
|
1424
|
+
);
|
|
1425
|
+
}
|
|
1426
|
+
((CopilotChatAssistantMessage2) => {
|
|
1427
|
+
const InlineCode = ({
|
|
1428
|
+
children,
|
|
1429
|
+
...props
|
|
1430
|
+
}) => {
|
|
1431
|
+
return /* @__PURE__ */ jsx10(
|
|
1432
|
+
"code",
|
|
1433
|
+
{
|
|
1434
|
+
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!",
|
|
1435
|
+
...props,
|
|
1436
|
+
children
|
|
1437
|
+
}
|
|
1438
|
+
);
|
|
1439
|
+
};
|
|
1440
|
+
const CodeBlock = ({ children, className, onClick, ...props }) => {
|
|
1441
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1442
|
+
const [copied, setCopied] = useState5(false);
|
|
1443
|
+
const getCodeContent = (node) => {
|
|
1444
|
+
if (typeof node === "string") return node;
|
|
1445
|
+
if (Array.isArray(node)) return node.map(getCodeContent).join("");
|
|
1446
|
+
if (node?.props?.children) return getCodeContent(node.props.children);
|
|
1447
|
+
return "";
|
|
1448
|
+
};
|
|
1449
|
+
const codeContent = getCodeContent(children);
|
|
1450
|
+
const language = props["data-language"];
|
|
1451
|
+
const copyToClipboard = async () => {
|
|
1452
|
+
if (!codeContent.trim()) return;
|
|
1453
|
+
try {
|
|
1454
|
+
setCopied(true);
|
|
1455
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
1456
|
+
if (onClick) {
|
|
1457
|
+
onClick();
|
|
1458
|
+
}
|
|
1459
|
+
} catch (err) {
|
|
1460
|
+
console.error("Failed to copy code:", err);
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
return /* @__PURE__ */ jsxs4("div", { className: "relative", children: [
|
|
1464
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between px-4 pr-3 py-3 text-xs", children: [
|
|
1465
|
+
language && /* @__PURE__ */ jsx10("span", { className: "font-regular text-muted-foreground dark:text-white", children: language }),
|
|
1466
|
+
/* @__PURE__ */ jsxs4(
|
|
1467
|
+
"button",
|
|
1468
|
+
{
|
|
1469
|
+
className: cn(
|
|
1470
|
+
"px-2 gap-0.5 text-xs flex items-center cursor-pointer text-muted-foreground dark:text-white"
|
|
1471
|
+
),
|
|
1472
|
+
onClick: copyToClipboard,
|
|
1473
|
+
title: copied ? labels.assistantMessageToolbarCopyCodeCopiedLabel : `${labels.assistantMessageToolbarCopyCodeLabel} code`,
|
|
1474
|
+
children: [
|
|
1475
|
+
copied ? /* @__PURE__ */ jsx10(Check2, { className: "h-[10px]! w-[10px]!" }) : /* @__PURE__ */ jsx10(Copy, { className: "h-[10px]! w-[10px]!" }),
|
|
1476
|
+
/* @__PURE__ */ jsx10("span", { className: "text-[11px]", children: copied ? labels.assistantMessageToolbarCopyCodeCopiedLabel : labels.assistantMessageToolbarCopyCodeLabel })
|
|
1477
|
+
]
|
|
1478
|
+
}
|
|
1479
|
+
)
|
|
1480
|
+
] }),
|
|
1481
|
+
/* @__PURE__ */ jsx10(
|
|
1482
|
+
"pre",
|
|
1483
|
+
{
|
|
1484
|
+
className: cn(
|
|
1485
|
+
className,
|
|
1486
|
+
"rounded-2xl bg-transparent border-t-0 my-1!"
|
|
1487
|
+
),
|
|
1488
|
+
...props,
|
|
1489
|
+
children
|
|
1490
|
+
}
|
|
1491
|
+
)
|
|
1492
|
+
] });
|
|
1493
|
+
};
|
|
1494
|
+
CopilotChatAssistantMessage2.MarkdownRenderer = ({ content, className }) => /* @__PURE__ */ jsx10("div", { className, children: /* @__PURE__ */ jsx10(
|
|
1495
|
+
MarkdownHooks,
|
|
1496
|
+
{
|
|
1497
|
+
remarkPlugins: [remarkGfm, remarkMath],
|
|
1498
|
+
rehypePlugins: [
|
|
1499
|
+
[
|
|
1500
|
+
rehypePrettyCode,
|
|
1501
|
+
{
|
|
1502
|
+
keepBackground: false,
|
|
1503
|
+
theme: {
|
|
1504
|
+
dark: "one-dark-pro",
|
|
1505
|
+
light: "one-light"
|
|
1506
|
+
},
|
|
1507
|
+
bypassInlineCode: true
|
|
1508
|
+
}
|
|
1509
|
+
],
|
|
1510
|
+
rehypeKatex
|
|
1511
|
+
],
|
|
1512
|
+
components: {
|
|
1513
|
+
pre: CodeBlock,
|
|
1514
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1515
|
+
code: ({ className: className2, children, ...props }) => {
|
|
1516
|
+
if (typeof children === "string") {
|
|
1517
|
+
return /* @__PURE__ */ jsx10(InlineCode, { ...props, children });
|
|
1518
|
+
}
|
|
1519
|
+
return /* @__PURE__ */ jsx10("code", { className: className2, ...props, children });
|
|
1520
|
+
}
|
|
1521
|
+
},
|
|
1522
|
+
children: completePartialMarkdown(content || "")
|
|
1523
|
+
}
|
|
1524
|
+
) });
|
|
1525
|
+
CopilotChatAssistantMessage2.Toolbar = ({
|
|
1526
|
+
className,
|
|
1527
|
+
...props
|
|
1528
|
+
}) => /* @__PURE__ */ jsx10(
|
|
1529
|
+
"div",
|
|
1530
|
+
{
|
|
1531
|
+
className: twMerge4(
|
|
1532
|
+
"w-full bg-transparent flex items-center -ml-[5px] -mt-[0px]",
|
|
1533
|
+
className
|
|
1534
|
+
),
|
|
1535
|
+
...props
|
|
1536
|
+
}
|
|
1537
|
+
);
|
|
1538
|
+
CopilotChatAssistantMessage2.ToolbarButton = ({ title, children, ...props }) => {
|
|
1539
|
+
return /* @__PURE__ */ jsxs4(Tooltip, { children: [
|
|
1540
|
+
/* @__PURE__ */ jsx10(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx10(
|
|
1541
|
+
Button,
|
|
1542
|
+
{
|
|
1543
|
+
type: "button",
|
|
1544
|
+
variant: "assistantMessageToolbarButton",
|
|
1545
|
+
"aria-label": title,
|
|
1546
|
+
...props,
|
|
1547
|
+
children
|
|
1548
|
+
}
|
|
1549
|
+
) }),
|
|
1550
|
+
/* @__PURE__ */ jsx10(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsx10("p", { children: title }) })
|
|
1551
|
+
] });
|
|
1552
|
+
};
|
|
1553
|
+
CopilotChatAssistantMessage2.CopyButton = ({ className, title, onClick, ...props }) => {
|
|
1554
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1555
|
+
const [copied, setCopied] = useState5(false);
|
|
1556
|
+
const handleClick = (event) => {
|
|
1557
|
+
setCopied(true);
|
|
1558
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
1559
|
+
if (onClick) {
|
|
1560
|
+
onClick(event);
|
|
1561
|
+
}
|
|
1562
|
+
};
|
|
1563
|
+
return /* @__PURE__ */ jsx10(
|
|
1564
|
+
CopilotChatAssistantMessage2.ToolbarButton,
|
|
1565
|
+
{
|
|
1566
|
+
title: title || labels.assistantMessageToolbarCopyMessageLabel,
|
|
1567
|
+
onClick: handleClick,
|
|
1568
|
+
className,
|
|
1569
|
+
...props,
|
|
1570
|
+
children: copied ? /* @__PURE__ */ jsx10(Check2, { className: "size-[18px]" }) : /* @__PURE__ */ jsx10(Copy, { className: "size-[18px]" })
|
|
1571
|
+
}
|
|
1572
|
+
);
|
|
1573
|
+
};
|
|
1574
|
+
CopilotChatAssistantMessage2.ThumbsUpButton = ({ title, ...props }) => {
|
|
1575
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1576
|
+
return /* @__PURE__ */ jsx10(
|
|
1577
|
+
CopilotChatAssistantMessage2.ToolbarButton,
|
|
1578
|
+
{
|
|
1579
|
+
title: title || labels.assistantMessageToolbarThumbsUpLabel,
|
|
1580
|
+
...props,
|
|
1581
|
+
children: /* @__PURE__ */ jsx10(ThumbsUp, { className: "size-[18px]" })
|
|
1582
|
+
}
|
|
1583
|
+
);
|
|
1584
|
+
};
|
|
1585
|
+
CopilotChatAssistantMessage2.ThumbsDownButton = ({ title, ...props }) => {
|
|
1586
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1587
|
+
return /* @__PURE__ */ jsx10(
|
|
1588
|
+
CopilotChatAssistantMessage2.ToolbarButton,
|
|
1589
|
+
{
|
|
1590
|
+
title: title || labels.assistantMessageToolbarThumbsDownLabel,
|
|
1591
|
+
...props,
|
|
1592
|
+
children: /* @__PURE__ */ jsx10(ThumbsDown, { className: "size-[18px]" })
|
|
1593
|
+
}
|
|
1594
|
+
);
|
|
1595
|
+
};
|
|
1596
|
+
CopilotChatAssistantMessage2.ReadAloudButton = ({ title, ...props }) => {
|
|
1597
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1598
|
+
return /* @__PURE__ */ jsx10(
|
|
1599
|
+
CopilotChatAssistantMessage2.ToolbarButton,
|
|
1600
|
+
{
|
|
1601
|
+
title: title || labels.assistantMessageToolbarReadAloudLabel,
|
|
1602
|
+
...props,
|
|
1603
|
+
children: /* @__PURE__ */ jsx10(Volume2, { className: "size-[20px]" })
|
|
1604
|
+
}
|
|
1605
|
+
);
|
|
1606
|
+
};
|
|
1607
|
+
CopilotChatAssistantMessage2.RegenerateButton = ({ title, ...props }) => {
|
|
1608
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1609
|
+
return /* @__PURE__ */ jsx10(
|
|
1610
|
+
CopilotChatAssistantMessage2.ToolbarButton,
|
|
1611
|
+
{
|
|
1612
|
+
title: title || labels.assistantMessageToolbarRegenerateLabel,
|
|
1613
|
+
...props,
|
|
1614
|
+
children: /* @__PURE__ */ jsx10(RefreshCw, { className: "size-[18px]" })
|
|
1615
|
+
}
|
|
1616
|
+
);
|
|
1617
|
+
};
|
|
1618
|
+
})(CopilotChatAssistantMessage || (CopilotChatAssistantMessage = {}));
|
|
1619
|
+
CopilotChatAssistantMessage.MarkdownRenderer.displayName = "CopilotChatAssistantMessage.MarkdownRenderer";
|
|
1620
|
+
CopilotChatAssistantMessage.Toolbar.displayName = "CopilotChatAssistantMessage.Toolbar";
|
|
1621
|
+
CopilotChatAssistantMessage.CopyButton.displayName = "CopilotChatAssistantMessage.CopyButton";
|
|
1622
|
+
CopilotChatAssistantMessage.ThumbsUpButton.displayName = "CopilotChatAssistantMessage.ThumbsUpButton";
|
|
1623
|
+
CopilotChatAssistantMessage.ThumbsDownButton.displayName = "CopilotChatAssistantMessage.ThumbsDownButton";
|
|
1624
|
+
CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantMessage.ReadAloudButton";
|
|
1625
|
+
CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
|
|
1626
|
+
var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
|
|
1627
|
+
|
|
1628
|
+
// src/components/chat/CopilotChatUserMessage.tsx
|
|
1629
|
+
import { useState as useState6 } from "react";
|
|
1630
|
+
import { Copy as Copy2, Check as Check3, Edit, ChevronLeft, ChevronRight } from "lucide-react";
|
|
1631
|
+
import { twMerge as twMerge5 } from "tailwind-merge";
|
|
1632
|
+
import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1633
|
+
function CopilotChatUserMessage({
|
|
1634
|
+
message,
|
|
1635
|
+
onEditMessage,
|
|
1636
|
+
branchIndex,
|
|
1637
|
+
numberOfBranches,
|
|
1638
|
+
onSwitchToBranch,
|
|
1639
|
+
additionalToolbarItems,
|
|
1640
|
+
messageRenderer,
|
|
1641
|
+
toolbar,
|
|
1642
|
+
copyButton,
|
|
1643
|
+
editButton,
|
|
1644
|
+
branchNavigation,
|
|
1645
|
+
children,
|
|
1646
|
+
className,
|
|
1647
|
+
...props
|
|
1648
|
+
}) {
|
|
1649
|
+
const BoundMessageRenderer = renderSlot(
|
|
1650
|
+
messageRenderer,
|
|
1651
|
+
CopilotChatUserMessage.MessageRenderer,
|
|
1652
|
+
{
|
|
1653
|
+
content: message.content || ""
|
|
1654
|
+
}
|
|
1655
|
+
);
|
|
1656
|
+
const BoundCopyButton = renderSlot(
|
|
1657
|
+
copyButton,
|
|
1658
|
+
CopilotChatUserMessage.CopyButton,
|
|
1659
|
+
{
|
|
1660
|
+
onClick: async () => {
|
|
1661
|
+
if (message.content) {
|
|
1662
|
+
try {
|
|
1663
|
+
await navigator.clipboard.writeText(message.content);
|
|
1664
|
+
} catch (err) {
|
|
1665
|
+
console.error("Failed to copy message:", err);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
);
|
|
1671
|
+
const BoundEditButton = renderSlot(
|
|
1672
|
+
editButton,
|
|
1673
|
+
CopilotChatUserMessage.EditButton,
|
|
1674
|
+
{
|
|
1675
|
+
onClick: () => onEditMessage?.({ message })
|
|
1676
|
+
}
|
|
1677
|
+
);
|
|
1678
|
+
const BoundBranchNavigation = renderSlot(
|
|
1679
|
+
branchNavigation,
|
|
1680
|
+
CopilotChatUserMessage.BranchNavigation,
|
|
1681
|
+
{
|
|
1682
|
+
currentBranch: branchIndex,
|
|
1683
|
+
numberOfBranches,
|
|
1684
|
+
onSwitchToBranch,
|
|
1685
|
+
message
|
|
1686
|
+
}
|
|
1687
|
+
);
|
|
1688
|
+
const showBranchNavigation = numberOfBranches && numberOfBranches > 1 && onSwitchToBranch;
|
|
1689
|
+
const BoundToolbar = renderSlot(toolbar, CopilotChatUserMessage.Toolbar, {
|
|
1690
|
+
children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 justify-end", children: [
|
|
1691
|
+
additionalToolbarItems,
|
|
1692
|
+
BoundCopyButton,
|
|
1693
|
+
onEditMessage && BoundEditButton,
|
|
1694
|
+
showBranchNavigation && BoundBranchNavigation
|
|
1695
|
+
] })
|
|
1696
|
+
});
|
|
1697
|
+
if (children) {
|
|
1698
|
+
return /* @__PURE__ */ jsx11(Fragment4, { children: children({
|
|
1699
|
+
messageRenderer: BoundMessageRenderer,
|
|
1700
|
+
toolbar: BoundToolbar,
|
|
1701
|
+
copyButton: BoundCopyButton,
|
|
1702
|
+
editButton: BoundEditButton,
|
|
1703
|
+
branchNavigation: BoundBranchNavigation,
|
|
1704
|
+
message,
|
|
1705
|
+
branchIndex,
|
|
1706
|
+
numberOfBranches,
|
|
1707
|
+
additionalToolbarItems
|
|
1708
|
+
}) });
|
|
1709
|
+
}
|
|
1710
|
+
return /* @__PURE__ */ jsxs5(
|
|
1711
|
+
"div",
|
|
1712
|
+
{
|
|
1713
|
+
className: twMerge5("flex flex-col items-end group pt-10", className),
|
|
1714
|
+
"data-message-id": message.id,
|
|
1715
|
+
...props,
|
|
1716
|
+
children: [
|
|
1717
|
+
BoundMessageRenderer,
|
|
1718
|
+
BoundToolbar
|
|
1719
|
+
]
|
|
1720
|
+
}
|
|
1721
|
+
);
|
|
1722
|
+
}
|
|
1723
|
+
((CopilotChatUserMessage2) => {
|
|
1724
|
+
CopilotChatUserMessage2.Container = ({ children, className, ...props }) => /* @__PURE__ */ jsx11(
|
|
1725
|
+
"div",
|
|
1726
|
+
{
|
|
1727
|
+
className: twMerge5("flex flex-col items-end group", className),
|
|
1728
|
+
...props,
|
|
1729
|
+
children
|
|
1730
|
+
}
|
|
1731
|
+
);
|
|
1732
|
+
CopilotChatUserMessage2.MessageRenderer = ({ content, className }) => /* @__PURE__ */ jsx11(
|
|
1733
|
+
"div",
|
|
1734
|
+
{
|
|
1735
|
+
className: twMerge5(
|
|
1736
|
+
"prose dark:prose-invert bg-muted relative max-w-[80%] rounded-[18px] px-4 py-1.5 data-[multiline]:py-3 inline-block whitespace-pre-wrap",
|
|
1737
|
+
className
|
|
1738
|
+
),
|
|
1739
|
+
children: content
|
|
1740
|
+
}
|
|
1741
|
+
);
|
|
1742
|
+
CopilotChatUserMessage2.Toolbar = ({
|
|
1743
|
+
className,
|
|
1744
|
+
...props
|
|
1745
|
+
}) => /* @__PURE__ */ jsx11(
|
|
1746
|
+
"div",
|
|
1747
|
+
{
|
|
1748
|
+
className: twMerge5(
|
|
1749
|
+
"w-full bg-transparent flex items-center justify-end -mr-[5px] mt-[4px] invisible group-hover:visible",
|
|
1750
|
+
className
|
|
1751
|
+
),
|
|
1752
|
+
...props
|
|
1753
|
+
}
|
|
1754
|
+
);
|
|
1755
|
+
CopilotChatUserMessage2.ToolbarButton = ({ title, children, className, ...props }) => {
|
|
1756
|
+
return /* @__PURE__ */ jsxs5(Tooltip, { children: [
|
|
1757
|
+
/* @__PURE__ */ jsx11(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx11(
|
|
1758
|
+
Button,
|
|
1759
|
+
{
|
|
1760
|
+
type: "button",
|
|
1761
|
+
variant: "assistantMessageToolbarButton",
|
|
1762
|
+
"aria-label": title,
|
|
1763
|
+
className: twMerge5(className),
|
|
1764
|
+
...props,
|
|
1765
|
+
children
|
|
1766
|
+
}
|
|
1767
|
+
) }),
|
|
1768
|
+
/* @__PURE__ */ jsx11(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsx11("p", { children: title }) })
|
|
1769
|
+
] });
|
|
1770
|
+
};
|
|
1771
|
+
CopilotChatUserMessage2.CopyButton = ({ className, title, onClick, ...props }) => {
|
|
1772
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1773
|
+
const [copied, setCopied] = useState6(false);
|
|
1774
|
+
const handleClick = (event) => {
|
|
1775
|
+
setCopied(true);
|
|
1776
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
1777
|
+
if (onClick) {
|
|
1778
|
+
onClick(event);
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
return /* @__PURE__ */ jsx11(
|
|
1782
|
+
CopilotChatUserMessage2.ToolbarButton,
|
|
1783
|
+
{
|
|
1784
|
+
title: title || labels.userMessageToolbarCopyMessageLabel,
|
|
1785
|
+
onClick: handleClick,
|
|
1786
|
+
className,
|
|
1787
|
+
...props,
|
|
1788
|
+
children: copied ? /* @__PURE__ */ jsx11(Check3, { className: "size-[18px]" }) : /* @__PURE__ */ jsx11(Copy2, { className: "size-[18px]" })
|
|
1789
|
+
}
|
|
1790
|
+
);
|
|
1791
|
+
};
|
|
1792
|
+
CopilotChatUserMessage2.EditButton = ({ className, title, ...props }) => {
|
|
1793
|
+
const { labels } = useCopilotChatConfiguration();
|
|
1794
|
+
return /* @__PURE__ */ jsx11(
|
|
1795
|
+
CopilotChatUserMessage2.ToolbarButton,
|
|
1796
|
+
{
|
|
1797
|
+
title: title || labels.userMessageToolbarEditMessageLabel,
|
|
1798
|
+
className,
|
|
1799
|
+
...props,
|
|
1800
|
+
children: /* @__PURE__ */ jsx11(Edit, { className: "size-[18px]" })
|
|
1801
|
+
}
|
|
1802
|
+
);
|
|
1803
|
+
};
|
|
1804
|
+
CopilotChatUserMessage2.BranchNavigation = ({
|
|
1805
|
+
className,
|
|
1806
|
+
currentBranch = 0,
|
|
1807
|
+
numberOfBranches = 1,
|
|
1808
|
+
onSwitchToBranch,
|
|
1809
|
+
message,
|
|
1810
|
+
...props
|
|
1811
|
+
}) => {
|
|
1812
|
+
if (!numberOfBranches || numberOfBranches <= 1 || !onSwitchToBranch) {
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
const canGoPrev = currentBranch > 0;
|
|
1816
|
+
const canGoNext = currentBranch < numberOfBranches - 1;
|
|
1817
|
+
return /* @__PURE__ */ jsxs5("div", { className: twMerge5("flex items-center gap-1", className), ...props, children: [
|
|
1818
|
+
/* @__PURE__ */ jsx11(
|
|
1819
|
+
Button,
|
|
1820
|
+
{
|
|
1821
|
+
type: "button",
|
|
1822
|
+
variant: "assistantMessageToolbarButton",
|
|
1823
|
+
onClick: () => onSwitchToBranch?.({
|
|
1824
|
+
branchIndex: currentBranch - 1,
|
|
1825
|
+
numberOfBranches,
|
|
1826
|
+
message
|
|
1827
|
+
}),
|
|
1828
|
+
disabled: !canGoPrev,
|
|
1829
|
+
className: "h-6 w-6 p-0",
|
|
1830
|
+
children: /* @__PURE__ */ jsx11(ChevronLeft, { className: "size-[20px]" })
|
|
1831
|
+
}
|
|
1832
|
+
),
|
|
1833
|
+
/* @__PURE__ */ jsxs5("span", { className: "text-sm text-muted-foreground px-0 font-medium", children: [
|
|
1834
|
+
currentBranch + 1,
|
|
1835
|
+
"/",
|
|
1836
|
+
numberOfBranches
|
|
1837
|
+
] }),
|
|
1838
|
+
/* @__PURE__ */ jsx11(
|
|
1839
|
+
Button,
|
|
1840
|
+
{
|
|
1841
|
+
type: "button",
|
|
1842
|
+
variant: "assistantMessageToolbarButton",
|
|
1843
|
+
onClick: () => onSwitchToBranch?.({
|
|
1844
|
+
branchIndex: currentBranch + 1,
|
|
1845
|
+
numberOfBranches,
|
|
1846
|
+
message
|
|
1847
|
+
}),
|
|
1848
|
+
disabled: !canGoNext,
|
|
1849
|
+
className: "h-6 w-6 p-0",
|
|
1850
|
+
children: /* @__PURE__ */ jsx11(ChevronRight, { className: "size-[20px]" })
|
|
1851
|
+
}
|
|
1852
|
+
)
|
|
1853
|
+
] });
|
|
1854
|
+
};
|
|
1855
|
+
})(CopilotChatUserMessage || (CopilotChatUserMessage = {}));
|
|
1856
|
+
CopilotChatUserMessage.Container.displayName = "CopilotChatUserMessage.Container";
|
|
1857
|
+
CopilotChatUserMessage.MessageRenderer.displayName = "CopilotChatUserMessage.MessageRenderer";
|
|
1858
|
+
CopilotChatUserMessage.Toolbar.displayName = "CopilotChatUserMessage.Toolbar";
|
|
1859
|
+
CopilotChatUserMessage.ToolbarButton.displayName = "CopilotChatUserMessage.ToolbarButton";
|
|
1860
|
+
CopilotChatUserMessage.CopyButton.displayName = "CopilotChatUserMessage.CopyButton";
|
|
1861
|
+
CopilotChatUserMessage.EditButton.displayName = "CopilotChatUserMessage.EditButton";
|
|
1862
|
+
CopilotChatUserMessage.BranchNavigation.displayName = "CopilotChatUserMessage.BranchNavigation";
|
|
1863
|
+
var CopilotChatUserMessage_default = CopilotChatUserMessage;
|
|
1864
|
+
|
|
1865
|
+
// src/components/chat/CopilotChatMessageView.tsx
|
|
1866
|
+
import { twMerge as twMerge6 } from "tailwind-merge";
|
|
1867
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1868
|
+
function CopilotChatMessageView({
|
|
1869
|
+
messages = [],
|
|
1870
|
+
assistantMessage,
|
|
1871
|
+
userMessage,
|
|
1872
|
+
cursor,
|
|
1873
|
+
isLoading = false,
|
|
1874
|
+
children,
|
|
1875
|
+
className,
|
|
1876
|
+
...props
|
|
1877
|
+
}) {
|
|
1878
|
+
const messageElements = messages.map((message) => {
|
|
1879
|
+
if (message.role === "assistant") {
|
|
1880
|
+
return renderSlot(assistantMessage, CopilotChatAssistantMessage_default, {
|
|
1881
|
+
key: message.id,
|
|
1882
|
+
message,
|
|
1883
|
+
messages,
|
|
1884
|
+
isLoading
|
|
1885
|
+
});
|
|
1886
|
+
} else if (message.role === "user") {
|
|
1887
|
+
return renderSlot(userMessage, CopilotChatUserMessage_default, {
|
|
1888
|
+
key: message.id,
|
|
1889
|
+
message
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
return;
|
|
1893
|
+
}).filter(Boolean);
|
|
1894
|
+
if (children) {
|
|
1895
|
+
return children({ messageElements, messages, isLoading });
|
|
1896
|
+
}
|
|
1897
|
+
return /* @__PURE__ */ jsxs6("div", { className: twMerge6("flex flex-col", className), ...props, children: [
|
|
1898
|
+
messageElements,
|
|
1899
|
+
isLoading && renderSlot(cursor, CopilotChatMessageView.Cursor, {})
|
|
1900
|
+
] });
|
|
1901
|
+
}
|
|
1902
|
+
CopilotChatMessageView.Cursor = function Cursor({
|
|
1903
|
+
className,
|
|
1904
|
+
...props
|
|
1905
|
+
}) {
|
|
1906
|
+
return /* @__PURE__ */ jsx12(
|
|
1907
|
+
"div",
|
|
1908
|
+
{
|
|
1909
|
+
className: twMerge6(
|
|
1910
|
+
"w-[11px] h-[11px] rounded-full bg-foreground animate-pulse-cursor ml-1",
|
|
1911
|
+
className
|
|
1912
|
+
),
|
|
1913
|
+
...props
|
|
1914
|
+
}
|
|
1915
|
+
);
|
|
1916
|
+
};
|
|
1917
|
+
var CopilotChatMessageView_default = CopilotChatMessageView;
|
|
1918
|
+
|
|
1919
|
+
// src/components/chat/CopilotChatView.tsx
|
|
1920
|
+
import React8, { useRef as useRef5, useState as useState7, useEffect as useEffect7 } from "react";
|
|
1921
|
+
import { twMerge as twMerge7 } from "tailwind-merge";
|
|
1922
|
+
import { StickToBottom, useStickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
|
1923
|
+
import { ChevronDown } from "lucide-react";
|
|
1924
|
+
import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1925
|
+
function CopilotChatView({
|
|
1926
|
+
messageView,
|
|
1927
|
+
input,
|
|
1928
|
+
scrollView,
|
|
1929
|
+
scrollToBottomButton,
|
|
1930
|
+
feather,
|
|
1931
|
+
inputContainer,
|
|
1932
|
+
disclaimer,
|
|
1933
|
+
messages = [],
|
|
1934
|
+
autoScroll = true,
|
|
1935
|
+
children,
|
|
1936
|
+
className,
|
|
1937
|
+
...props
|
|
1938
|
+
}) {
|
|
1939
|
+
const inputContainerRef = useRef5(null);
|
|
1940
|
+
const [inputContainerHeight, setInputContainerHeight] = useState7(0);
|
|
1941
|
+
const [isResizing, setIsResizing] = useState7(false);
|
|
1942
|
+
const resizeTimeoutRef = useRef5(null);
|
|
1943
|
+
useEffect7(() => {
|
|
1944
|
+
const element = inputContainerRef.current;
|
|
1945
|
+
if (!element) return;
|
|
1946
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
1947
|
+
for (const entry of entries) {
|
|
1948
|
+
const newHeight = entry.contentRect.height;
|
|
1949
|
+
setInputContainerHeight((prevHeight) => {
|
|
1950
|
+
if (newHeight !== prevHeight) {
|
|
1951
|
+
setIsResizing(true);
|
|
1952
|
+
if (resizeTimeoutRef.current) {
|
|
1953
|
+
clearTimeout(resizeTimeoutRef.current);
|
|
1954
|
+
}
|
|
1955
|
+
resizeTimeoutRef.current = setTimeout(() => {
|
|
1956
|
+
setIsResizing(false);
|
|
1957
|
+
}, 250);
|
|
1958
|
+
return newHeight;
|
|
1959
|
+
}
|
|
1960
|
+
return prevHeight;
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
});
|
|
1964
|
+
resizeObserver.observe(element);
|
|
1965
|
+
setInputContainerHeight(element.offsetHeight);
|
|
1966
|
+
return () => {
|
|
1967
|
+
resizeObserver.disconnect();
|
|
1968
|
+
if (resizeTimeoutRef.current) {
|
|
1969
|
+
clearTimeout(resizeTimeoutRef.current);
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
}, []);
|
|
1973
|
+
const BoundMessageView = renderSlot(messageView, CopilotChatMessageView_default, {
|
|
1974
|
+
messages
|
|
1975
|
+
});
|
|
1976
|
+
const BoundInput = renderSlot(input, CopilotChatInput_default, {});
|
|
1977
|
+
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
1978
|
+
const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
|
|
1979
|
+
autoScroll,
|
|
1980
|
+
scrollToBottomButton,
|
|
1981
|
+
inputContainerHeight,
|
|
1982
|
+
isResizing,
|
|
1983
|
+
children: /* @__PURE__ */ jsx13("div", { style: { paddingBottom: `${inputContainerHeight + 32}px` }, children: /* @__PURE__ */ jsx13("div", { className: "max-w-3xl mx-auto", children: BoundMessageView }) })
|
|
1984
|
+
});
|
|
1985
|
+
const BoundScrollToBottomButton = renderSlot(
|
|
1986
|
+
scrollToBottomButton,
|
|
1987
|
+
CopilotChatView.ScrollToBottomButton,
|
|
1988
|
+
{}
|
|
1989
|
+
);
|
|
1990
|
+
const BoundDisclaimer = renderSlot(
|
|
1991
|
+
disclaimer,
|
|
1992
|
+
CopilotChatView.Disclaimer,
|
|
1993
|
+
{}
|
|
1994
|
+
);
|
|
1995
|
+
const BoundInputContainer = renderSlot(
|
|
1996
|
+
inputContainer,
|
|
1997
|
+
CopilotChatView.InputContainer,
|
|
1998
|
+
{
|
|
1999
|
+
ref: inputContainerRef,
|
|
2000
|
+
children: /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2001
|
+
/* @__PURE__ */ jsx13("div", { className: "max-w-3xl mx-auto py-0 px-4 sm:px-0", children: BoundInput }),
|
|
2002
|
+
BoundDisclaimer
|
|
2003
|
+
] })
|
|
2004
|
+
}
|
|
2005
|
+
);
|
|
2006
|
+
if (children) {
|
|
2007
|
+
return children({
|
|
2008
|
+
messageView: BoundMessageView,
|
|
2009
|
+
input: BoundInput,
|
|
2010
|
+
scrollView: BoundScrollView,
|
|
2011
|
+
scrollToBottomButton: BoundScrollToBottomButton,
|
|
2012
|
+
feather: BoundFeather,
|
|
2013
|
+
inputContainer: BoundInputContainer,
|
|
2014
|
+
disclaimer: BoundDisclaimer
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
2017
|
+
return /* @__PURE__ */ jsxs7("div", { className: twMerge7("relative h-full", className), ...props, children: [
|
|
2018
|
+
BoundScrollView,
|
|
2019
|
+
BoundFeather,
|
|
2020
|
+
BoundInputContainer
|
|
2021
|
+
] });
|
|
2022
|
+
}
|
|
2023
|
+
((CopilotChatView2) => {
|
|
2024
|
+
const ScrollContent = ({ children, scrollToBottomButton, inputContainerHeight, isResizing }) => {
|
|
2025
|
+
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
|
2026
|
+
return /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2027
|
+
/* @__PURE__ */ jsx13(StickToBottom.Content, { className: "overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx13("div", { className: "px-4 sm:px-0", children }) }),
|
|
2028
|
+
!isAtBottom && !isResizing && /* @__PURE__ */ jsx13(
|
|
2029
|
+
"div",
|
|
2030
|
+
{
|
|
2031
|
+
className: "absolute inset-x-0 flex justify-center z-10",
|
|
2032
|
+
style: {
|
|
2033
|
+
bottom: `${inputContainerHeight + 16}px`
|
|
2034
|
+
},
|
|
2035
|
+
children: renderSlot(
|
|
2036
|
+
scrollToBottomButton,
|
|
2037
|
+
CopilotChatView2.ScrollToBottomButton,
|
|
2038
|
+
{
|
|
2039
|
+
onClick: () => scrollToBottom()
|
|
2040
|
+
}
|
|
2041
|
+
)
|
|
2042
|
+
}
|
|
2043
|
+
)
|
|
2044
|
+
] });
|
|
2045
|
+
};
|
|
2046
|
+
CopilotChatView2.ScrollView = ({
|
|
2047
|
+
children,
|
|
2048
|
+
autoScroll = true,
|
|
2049
|
+
scrollToBottomButton,
|
|
2050
|
+
inputContainerHeight = 0,
|
|
2051
|
+
isResizing = false,
|
|
2052
|
+
className,
|
|
2053
|
+
...props
|
|
2054
|
+
}) => {
|
|
2055
|
+
const [hasMounted, setHasMounted] = useState7(false);
|
|
2056
|
+
const { scrollRef, contentRef, scrollToBottom } = useStickToBottom();
|
|
2057
|
+
const [showScrollButton, setShowScrollButton] = useState7(false);
|
|
2058
|
+
useEffect7(() => {
|
|
2059
|
+
setHasMounted(true);
|
|
2060
|
+
}, []);
|
|
2061
|
+
useEffect7(() => {
|
|
2062
|
+
if (autoScroll) return;
|
|
2063
|
+
const scrollElement = scrollRef.current;
|
|
2064
|
+
if (!scrollElement) return;
|
|
2065
|
+
const checkScroll = () => {
|
|
2066
|
+
const atBottom = scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight < 10;
|
|
2067
|
+
setShowScrollButton(!atBottom);
|
|
2068
|
+
};
|
|
2069
|
+
checkScroll();
|
|
2070
|
+
scrollElement.addEventListener("scroll", checkScroll);
|
|
2071
|
+
const resizeObserver = new ResizeObserver(checkScroll);
|
|
2072
|
+
resizeObserver.observe(scrollElement);
|
|
2073
|
+
return () => {
|
|
2074
|
+
scrollElement.removeEventListener("scroll", checkScroll);
|
|
2075
|
+
resizeObserver.disconnect();
|
|
2076
|
+
};
|
|
2077
|
+
}, [scrollRef, autoScroll]);
|
|
2078
|
+
if (!hasMounted) {
|
|
2079
|
+
return /* @__PURE__ */ jsx13("div", { className: "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx13("div", { className: "px-4 sm:px-0", children }) });
|
|
2080
|
+
}
|
|
2081
|
+
if (!autoScroll) {
|
|
2082
|
+
return /* @__PURE__ */ jsxs7(
|
|
2083
|
+
"div",
|
|
2084
|
+
{
|
|
2085
|
+
ref: scrollRef,
|
|
2086
|
+
className: cn("h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden relative", className),
|
|
2087
|
+
...props,
|
|
2088
|
+
children: [
|
|
2089
|
+
/* @__PURE__ */ jsx13("div", { ref: contentRef, className: "px-4 sm:px-0", children }),
|
|
2090
|
+
showScrollButton && !isResizing && /* @__PURE__ */ jsx13(
|
|
2091
|
+
"div",
|
|
2092
|
+
{
|
|
2093
|
+
className: "absolute inset-x-0 flex justify-center z-10",
|
|
2094
|
+
style: {
|
|
2095
|
+
bottom: `${inputContainerHeight + 16}px`
|
|
2096
|
+
},
|
|
2097
|
+
children: renderSlot(
|
|
2098
|
+
scrollToBottomButton,
|
|
2099
|
+
CopilotChatView2.ScrollToBottomButton,
|
|
2100
|
+
{
|
|
2101
|
+
onClick: () => scrollToBottom()
|
|
2102
|
+
}
|
|
2103
|
+
)
|
|
2104
|
+
}
|
|
2105
|
+
)
|
|
2106
|
+
]
|
|
2107
|
+
}
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
return /* @__PURE__ */ jsx13(
|
|
2111
|
+
StickToBottom,
|
|
2112
|
+
{
|
|
2113
|
+
className: cn("h-full max-h-full flex flex-col min-h-0 relative", className),
|
|
2114
|
+
resize: "smooth",
|
|
2115
|
+
initial: "smooth",
|
|
2116
|
+
...props,
|
|
2117
|
+
children: /* @__PURE__ */ jsx13(
|
|
2118
|
+
ScrollContent,
|
|
2119
|
+
{
|
|
2120
|
+
scrollToBottomButton,
|
|
2121
|
+
inputContainerHeight,
|
|
2122
|
+
isResizing,
|
|
2123
|
+
children
|
|
2124
|
+
}
|
|
2125
|
+
)
|
|
2126
|
+
}
|
|
2127
|
+
);
|
|
2128
|
+
};
|
|
2129
|
+
CopilotChatView2.ScrollToBottomButton = ({ className, ...props }) => /* @__PURE__ */ jsx13(
|
|
2130
|
+
Button,
|
|
2131
|
+
{
|
|
2132
|
+
variant: "outline",
|
|
2133
|
+
size: "sm",
|
|
2134
|
+
className: twMerge7(
|
|
2135
|
+
"rounded-full w-10 h-10 p-0",
|
|
2136
|
+
"bg-white dark:bg-gray-900",
|
|
2137
|
+
"shadow-lg border border-gray-200 dark:border-gray-700",
|
|
2138
|
+
"hover:bg-gray-50 dark:hover:bg-gray-800",
|
|
2139
|
+
"flex items-center justify-center cursor-pointer",
|
|
2140
|
+
className
|
|
2141
|
+
),
|
|
2142
|
+
...props,
|
|
2143
|
+
children: /* @__PURE__ */ jsx13(ChevronDown, { className: "w-4 h-4 text-gray-600 dark:text-white" })
|
|
2144
|
+
}
|
|
2145
|
+
);
|
|
2146
|
+
CopilotChatView2.Feather = ({
|
|
2147
|
+
className,
|
|
2148
|
+
style,
|
|
2149
|
+
...props
|
|
2150
|
+
}) => /* @__PURE__ */ jsx13(
|
|
2151
|
+
"div",
|
|
2152
|
+
{
|
|
2153
|
+
className: cn(
|
|
2154
|
+
"absolute bottom-0 left-0 right-4 h-24 pointer-events-none z-10 bg-gradient-to-t",
|
|
2155
|
+
"from-white via-white to-transparent",
|
|
2156
|
+
"dark:from-[rgb(33,33,33)] dark:via-[rgb(33,33,33)]",
|
|
2157
|
+
className
|
|
2158
|
+
),
|
|
2159
|
+
style,
|
|
2160
|
+
...props
|
|
2161
|
+
}
|
|
2162
|
+
);
|
|
2163
|
+
CopilotChatView2.InputContainer = React8.forwardRef(({ children, className, ...props }, ref) => /* @__PURE__ */ jsx13(
|
|
2164
|
+
"div",
|
|
2165
|
+
{
|
|
2166
|
+
ref,
|
|
2167
|
+
className: cn("absolute bottom-0 left-0 right-0 z-20", className),
|
|
2168
|
+
...props,
|
|
2169
|
+
children
|
|
2170
|
+
}
|
|
2171
|
+
));
|
|
2172
|
+
CopilotChatView2.InputContainer.displayName = "CopilotChatView.InputContainer";
|
|
2173
|
+
CopilotChatView2.Disclaimer = ({
|
|
2174
|
+
className,
|
|
2175
|
+
...props
|
|
2176
|
+
}) => {
|
|
2177
|
+
const { labels } = useCopilotChatConfiguration();
|
|
2178
|
+
return /* @__PURE__ */ jsx13(
|
|
2179
|
+
"div",
|
|
2180
|
+
{
|
|
2181
|
+
className: cn(
|
|
2182
|
+
"text-center text-xs text-muted-foreground py-3 px-4 max-w-3xl mx-auto",
|
|
2183
|
+
className
|
|
2184
|
+
),
|
|
2185
|
+
...props,
|
|
2186
|
+
children: labels.chatDisclaimerText
|
|
2187
|
+
}
|
|
2188
|
+
);
|
|
2189
|
+
};
|
|
2190
|
+
})(CopilotChatView || (CopilotChatView = {}));
|
|
2191
|
+
var CopilotChatView_default = CopilotChatView;
|
|
2192
|
+
|
|
2193
|
+
// src/components/chat/CopilotChat.tsx
|
|
2194
|
+
import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID2, randomUUID } from "@copilotkitnext/shared";
|
|
2195
|
+
import { useCallback as useCallback3, useState as useState8, useEffect as useEffect8, useMemo as useMemo3 } from "react";
|
|
2196
|
+
import { merge } from "ts-deepmerge";
|
|
2197
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
2198
|
+
function CopilotChat({
|
|
2199
|
+
agentId = DEFAULT_AGENT_ID2,
|
|
2200
|
+
threadId,
|
|
2201
|
+
...props
|
|
2202
|
+
}) {
|
|
2203
|
+
const { agent } = useAgent({ agentId });
|
|
2204
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
2205
|
+
threadId = threadId ?? useMemo3(() => randomUUID(), []);
|
|
2206
|
+
const subscriber = {
|
|
2207
|
+
onTextMessageStartEvent: () => setIsLoading(false),
|
|
2208
|
+
onToolCallStartEvent: () => setIsLoading(false)
|
|
2209
|
+
};
|
|
2210
|
+
useEffect8(() => {
|
|
2211
|
+
const connect = async () => {
|
|
2212
|
+
setIsLoading(true);
|
|
2213
|
+
await agent?.runAgent(
|
|
2214
|
+
{
|
|
2215
|
+
forwardedProps: { __copilotkitConnect: true }
|
|
2216
|
+
},
|
|
2217
|
+
subscriber
|
|
2218
|
+
);
|
|
2219
|
+
setIsLoading(false);
|
|
2220
|
+
};
|
|
2221
|
+
if (agent) {
|
|
2222
|
+
agent.threadId = threadId;
|
|
2223
|
+
if ("isCopilotKitAgent" in agent) {
|
|
2224
|
+
connect();
|
|
2225
|
+
} else {
|
|
2226
|
+
setIsLoading(false);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
return () => {
|
|
2230
|
+
};
|
|
2231
|
+
}, [threadId, agent]);
|
|
2232
|
+
const [inputValue, setInputValue] = useState8("");
|
|
2233
|
+
const onSubmitInput = useCallback3(
|
|
2234
|
+
async (value) => {
|
|
2235
|
+
setInputValue("");
|
|
2236
|
+
agent?.addMessage({
|
|
2237
|
+
id: randomUUID(),
|
|
2238
|
+
role: "user",
|
|
2239
|
+
content: value
|
|
2240
|
+
});
|
|
2241
|
+
setIsLoading(true);
|
|
2242
|
+
await agent?.runAgent({}, subscriber);
|
|
2243
|
+
setIsLoading(false);
|
|
2244
|
+
},
|
|
2245
|
+
[agent]
|
|
2246
|
+
);
|
|
2247
|
+
const mergedProps = merge(
|
|
2248
|
+
{
|
|
2249
|
+
messageView: { isLoading }
|
|
2250
|
+
},
|
|
2251
|
+
{
|
|
2252
|
+
...props,
|
|
2253
|
+
...typeof props.messageView === "string" ? { messageView: { className: props.messageView } } : props.messageView !== void 0 ? { messageView: props.messageView } : {}
|
|
2254
|
+
}
|
|
2255
|
+
);
|
|
2256
|
+
return /* @__PURE__ */ jsx14(
|
|
2257
|
+
CopilotChatConfigurationProvider,
|
|
2258
|
+
{
|
|
2259
|
+
inputValue,
|
|
2260
|
+
onSubmitInput,
|
|
2261
|
+
onChangeInput: setInputValue,
|
|
2262
|
+
children: /* @__PURE__ */ jsx14(
|
|
2263
|
+
CopilotChatView,
|
|
2264
|
+
{
|
|
2265
|
+
...{ messages: agent?.messages ?? [], ...mergedProps }
|
|
2266
|
+
}
|
|
2267
|
+
)
|
|
2268
|
+
}
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
export {
|
|
2272
|
+
AudioRecorderError,
|
|
2273
|
+
CopilotChat,
|
|
2274
|
+
CopilotChatAssistantMessage_default as CopilotChatAssistantMessage,
|
|
2275
|
+
CopilotChatAudioRecorder,
|
|
2276
|
+
CopilotChatConfigurationProvider,
|
|
2277
|
+
CopilotChatInput_default as CopilotChatInput,
|
|
2278
|
+
CopilotChatMessageView_default as CopilotChatMessageView,
|
|
2279
|
+
CopilotChatToolCallsView_default as CopilotChatToolCallsView,
|
|
2280
|
+
CopilotChatUserMessage_default as CopilotChatUserMessage,
|
|
2281
|
+
CopilotChatView_default as CopilotChatView,
|
|
2282
|
+
CopilotKitProvider,
|
|
2283
|
+
useAgent,
|
|
2284
|
+
useAgentContext,
|
|
2285
|
+
useCopilotChatConfiguration,
|
|
2286
|
+
useCopilotKit,
|
|
2287
|
+
useFrontendTool,
|
|
2288
|
+
useHumanInTheLoop,
|
|
2289
|
+
useRenderToolCall
|
|
2290
|
+
};
|
|
2291
|
+
//# sourceMappingURL=index.mjs.map
|