@copilotkitnext/react 0.0.0-0.0.0-max-changeset-10101010101010-20260109191632

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/dist/index.mjs ADDED
@@ -0,0 +1,4527 @@
1
+ "use client";
2
+
3
+ // src/index.ts
4
+ export * from "@ag-ui/core";
5
+ export * from "@ag-ui/client";
6
+
7
+ // src/components/chat/CopilotChatInput.tsx
8
+ import {
9
+ useState as useState2,
10
+ useRef as useRef2,
11
+ useEffect as useEffect2,
12
+ useLayoutEffect,
13
+ forwardRef as forwardRef2,
14
+ useImperativeHandle as useImperativeHandle2,
15
+ useCallback,
16
+ useMemo as useMemo2
17
+ } from "react";
18
+ import { twMerge as twMerge3 } from "tailwind-merge";
19
+ import { Plus, Mic, ArrowUp, X, Check, Square } from "lucide-react";
20
+
21
+ // src/providers/CopilotChatConfigurationProvider.tsx
22
+ import { createContext, useContext, useMemo, useState } from "react";
23
+ import { DEFAULT_AGENT_ID, randomUUID } from "@copilotkitnext/shared";
24
+ import { jsx } from "react/jsx-runtime";
25
+ var CopilotChatDefaultLabels = {
26
+ chatInputPlaceholder: "Type a message...",
27
+ chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
28
+ chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
29
+ chatInputToolbarFinishTranscribeButtonLabel: "Finish",
30
+ chatInputToolbarAddButtonLabel: "Add photos or files",
31
+ chatInputToolbarToolsButtonLabel: "Tools",
32
+ assistantMessageToolbarCopyCodeLabel: "Copy",
33
+ assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
34
+ assistantMessageToolbarCopyMessageLabel: "Copy",
35
+ assistantMessageToolbarThumbsUpLabel: "Good response",
36
+ assistantMessageToolbarThumbsDownLabel: "Bad response",
37
+ assistantMessageToolbarReadAloudLabel: "Read aloud",
38
+ assistantMessageToolbarRegenerateLabel: "Regenerate",
39
+ userMessageToolbarCopyMessageLabel: "Copy",
40
+ userMessageToolbarEditMessageLabel: "Edit",
41
+ chatDisclaimerText: "AI can make mistakes. Please verify important information.",
42
+ chatToggleOpenLabel: "Open chat",
43
+ chatToggleCloseLabel: "Close chat",
44
+ modalHeaderTitle: "CopilotKit Chat"
45
+ };
46
+ var CopilotChatConfiguration = createContext(null);
47
+ var CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, isModalDefaultOpen }) => {
48
+ const parentConfig = useContext(CopilotChatConfiguration);
49
+ const mergedLabels = useMemo(
50
+ () => ({
51
+ ...CopilotChatDefaultLabels,
52
+ ...parentConfig?.labels ?? {},
53
+ ...labels ?? {}
54
+ }),
55
+ [labels, parentConfig?.labels]
56
+ );
57
+ const resolvedAgentId = agentId ?? parentConfig?.agentId ?? DEFAULT_AGENT_ID;
58
+ const resolvedThreadId = useMemo(() => {
59
+ if (threadId) {
60
+ return threadId;
61
+ }
62
+ if (parentConfig?.threadId) {
63
+ return parentConfig.threadId;
64
+ }
65
+ return randomUUID();
66
+ }, [threadId, parentConfig?.threadId]);
67
+ const resolvedDefaultOpen = isModalDefaultOpen ?? parentConfig?.isModalDefaultOpen ?? true;
68
+ const [internalModalOpen, setInternalModalOpen] = useState(
69
+ parentConfig?.isModalOpen ?? resolvedDefaultOpen
70
+ );
71
+ const resolvedIsModalOpen = parentConfig?.isModalOpen ?? internalModalOpen;
72
+ const resolvedSetModalOpen = parentConfig?.setModalOpen ?? setInternalModalOpen;
73
+ const configurationValue = useMemo(
74
+ () => ({
75
+ labels: mergedLabels,
76
+ agentId: resolvedAgentId,
77
+ threadId: resolvedThreadId,
78
+ isModalOpen: resolvedIsModalOpen,
79
+ setModalOpen: resolvedSetModalOpen,
80
+ isModalDefaultOpen: resolvedDefaultOpen
81
+ }),
82
+ [
83
+ mergedLabels,
84
+ resolvedAgentId,
85
+ resolvedThreadId,
86
+ resolvedIsModalOpen,
87
+ resolvedSetModalOpen,
88
+ resolvedDefaultOpen
89
+ ]
90
+ );
91
+ return /* @__PURE__ */ jsx(CopilotChatConfiguration.Provider, { value: configurationValue, children });
92
+ };
93
+ var useCopilotChatConfiguration = () => {
94
+ const configuration = useContext(CopilotChatConfiguration);
95
+ return configuration;
96
+ };
97
+
98
+ // src/components/ui/button.tsx
99
+ import { Slot } from "@radix-ui/react-slot";
100
+ import { cva } from "class-variance-authority";
101
+
102
+ // src/lib/utils.ts
103
+ import { clsx } from "clsx";
104
+ import { twMerge } from "tailwind-merge";
105
+ function cn(...inputs) {
106
+ return twMerge(clsx(inputs));
107
+ }
108
+
109
+ // src/components/ui/button.tsx
110
+ import { jsx as jsx2 } from "react/jsx-runtime";
111
+ var buttonVariants = cva(
112
+ "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",
113
+ {
114
+ variants: {
115
+ variant: {
116
+ default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
117
+ 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",
118
+ 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",
119
+ secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
120
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50 cursor-pointer",
121
+ link: "text-primary underline-offset-4 hover:underline",
122
+ assistantMessageToolbarButton: [
123
+ "cursor-pointer",
124
+ // Background and text
125
+ "p-0 text-[rgb(93,93,93)] hover:bg-[#E8E8E8]",
126
+ // Dark mode - lighter gray for better contrast
127
+ "dark:text-[rgb(243,243,243)] dark:hover:bg-[#303030]",
128
+ // Shape and sizing
129
+ "h-8 w-8",
130
+ // Interactions
131
+ "transition-colors",
132
+ // Hover states
133
+ "hover:text-[rgb(93,93,93)]",
134
+ "dark:hover:text-[rgb(243,243,243)]"
135
+ ],
136
+ chatInputToolbarPrimary: [
137
+ "cursor-pointer",
138
+ // Background and text
139
+ "bg-black text-white",
140
+ // Dark mode
141
+ "dark:bg-white dark:text-black dark:focus-visible:outline-white",
142
+ // Shape and sizing
143
+ "rounded-full",
144
+ // Interactions
145
+ "transition-colors",
146
+ // Focus states
147
+ "focus:outline-none",
148
+ // Hover states
149
+ "hover:opacity-70 disabled:hover:opacity-100",
150
+ // Disabled states
151
+ "disabled:cursor-not-allowed disabled:bg-[#00000014] disabled:text-[rgb(13,13,13)]",
152
+ "dark:disabled:bg-[#454545] dark:disabled:text-white "
153
+ ],
154
+ chatInputToolbarSecondary: [
155
+ "cursor-pointer",
156
+ // Background and text
157
+ "bg-transparent text-[#444444]",
158
+ // Dark mode
159
+ "dark:text-white dark:border-[#404040]",
160
+ // Shape and sizing
161
+ "rounded-full",
162
+ // Interactions
163
+ "transition-colors",
164
+ // Focus states
165
+ "focus:outline-none",
166
+ // Hover states
167
+ "hover:bg-[#f8f8f8] hover:text-[#333333]",
168
+ "dark:hover:bg-[#404040] dark:hover:text-[#FFFFFF]",
169
+ // Disabled states
170
+ "disabled:cursor-not-allowed disabled:opacity-50",
171
+ "disabled:hover:bg-transparent disabled:hover:text-[#444444]",
172
+ "dark:disabled:hover:bg-transparent dark:disabled:hover:text-[#CCCCCC]"
173
+ ]
174
+ },
175
+ size: {
176
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
177
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
178
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
179
+ icon: "size-9",
180
+ chatInputToolbarIcon: [
181
+ // Shape and sizing
182
+ "h-9 w-9 rounded-full"
183
+ ],
184
+ chatInputToolbarIconLabel: [
185
+ // Shape and sizing
186
+ "h-9 px-3 rounded-full",
187
+ // Layout
188
+ "gap-2",
189
+ // Typography
190
+ "font-normal"
191
+ ]
192
+ }
193
+ },
194
+ defaultVariants: {
195
+ variant: "default",
196
+ size: "default"
197
+ }
198
+ }
199
+ );
200
+ function Button({
201
+ className,
202
+ variant,
203
+ size,
204
+ asChild = false,
205
+ ...props
206
+ }) {
207
+ const Comp = asChild ? Slot : "button";
208
+ return /* @__PURE__ */ jsx2(
209
+ Comp,
210
+ {
211
+ "data-slot": "button",
212
+ className: cn(buttonVariants({ variant, size, className })),
213
+ ...props
214
+ }
215
+ );
216
+ }
217
+
218
+ // src/components/ui/tooltip.tsx
219
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
220
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
221
+ function TooltipProvider({
222
+ delayDuration = 0,
223
+ ...props
224
+ }) {
225
+ return /* @__PURE__ */ jsx3(
226
+ TooltipPrimitive.Provider,
227
+ {
228
+ "data-slot": "tooltip-provider",
229
+ delayDuration,
230
+ ...props
231
+ }
232
+ );
233
+ }
234
+ function Tooltip({
235
+ ...props
236
+ }) {
237
+ return /* @__PURE__ */ jsx3(TooltipProvider, { children: /* @__PURE__ */ jsx3(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
238
+ }
239
+ function TooltipTrigger({
240
+ ...props
241
+ }) {
242
+ return /* @__PURE__ */ jsx3(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
243
+ }
244
+ function TooltipContent({
245
+ className,
246
+ sideOffset = 0,
247
+ children,
248
+ ...props
249
+ }) {
250
+ return /* @__PURE__ */ jsx3(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
251
+ TooltipPrimitive.Content,
252
+ {
253
+ "data-slot": "tooltip-content",
254
+ sideOffset,
255
+ className: cn(
256
+ "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",
257
+ className
258
+ ),
259
+ ...props,
260
+ children: [
261
+ children,
262
+ /* @__PURE__ */ jsx3(TooltipPrimitive.Arrow, { className: "bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
263
+ ]
264
+ }
265
+ ) });
266
+ }
267
+
268
+ // src/components/ui/dropdown-menu.tsx
269
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
270
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
271
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
272
+ function DropdownMenu({
273
+ ...props
274
+ }) {
275
+ return /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
276
+ }
277
+ function DropdownMenuTrigger({
278
+ ...props
279
+ }) {
280
+ return /* @__PURE__ */ jsx4(
281
+ DropdownMenuPrimitive.Trigger,
282
+ {
283
+ "data-slot": "dropdown-menu-trigger",
284
+ ...props
285
+ }
286
+ );
287
+ }
288
+ function DropdownMenuContent({
289
+ className,
290
+ sideOffset = 4,
291
+ ...props
292
+ }) {
293
+ return /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx4(
294
+ DropdownMenuPrimitive.Content,
295
+ {
296
+ "data-slot": "dropdown-menu-content",
297
+ sideOffset,
298
+ className: cn(
299
+ "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",
300
+ className
301
+ ),
302
+ ...props
303
+ }
304
+ ) });
305
+ }
306
+ function DropdownMenuItem({
307
+ className,
308
+ inset,
309
+ variant = "default",
310
+ ...props
311
+ }) {
312
+ return /* @__PURE__ */ jsx4(
313
+ DropdownMenuPrimitive.Item,
314
+ {
315
+ "data-slot": "dropdown-menu-item",
316
+ "data-inset": inset,
317
+ "data-variant": variant,
318
+ className: cn(
319
+ "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",
320
+ className
321
+ ),
322
+ ...props
323
+ }
324
+ );
325
+ }
326
+ function DropdownMenuSeparator({
327
+ className,
328
+ ...props
329
+ }) {
330
+ return /* @__PURE__ */ jsx4(
331
+ DropdownMenuPrimitive.Separator,
332
+ {
333
+ "data-slot": "dropdown-menu-separator",
334
+ className: cn("bg-border -mx-1 my-1 h-px", className),
335
+ ...props
336
+ }
337
+ );
338
+ }
339
+ function DropdownMenuSub({
340
+ ...props
341
+ }) {
342
+ return /* @__PURE__ */ jsx4(DropdownMenuPrimitive.Sub, { "data-slot": "dropdown-menu-sub", ...props });
343
+ }
344
+ function DropdownMenuSubTrigger({
345
+ className,
346
+ inset,
347
+ children,
348
+ ...props
349
+ }) {
350
+ return /* @__PURE__ */ jsxs2(
351
+ DropdownMenuPrimitive.SubTrigger,
352
+ {
353
+ "data-slot": "dropdown-menu-sub-trigger",
354
+ "data-inset": inset,
355
+ className: cn(
356
+ "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",
357
+ className
358
+ ),
359
+ ...props,
360
+ children: [
361
+ children,
362
+ /* @__PURE__ */ jsx4(ChevronRightIcon, { className: "ml-auto size-4" })
363
+ ]
364
+ }
365
+ );
366
+ }
367
+ function DropdownMenuSubContent({
368
+ className,
369
+ ...props
370
+ }) {
371
+ return /* @__PURE__ */ jsx4(
372
+ DropdownMenuPrimitive.SubContent,
373
+ {
374
+ "data-slot": "dropdown-menu-sub-content",
375
+ className: cn(
376
+ "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",
377
+ className
378
+ ),
379
+ ...props
380
+ }
381
+ );
382
+ }
383
+
384
+ // src/components/chat/CopilotChatAudioRecorder.tsx
385
+ import { useRef, useEffect, useImperativeHandle, forwardRef } from "react";
386
+ import { twMerge as twMerge2 } from "tailwind-merge";
387
+ import { jsx as jsx5 } from "react/jsx-runtime";
388
+ var AudioRecorderError = class extends Error {
389
+ constructor(message) {
390
+ super(message);
391
+ this.name = "AudioRecorderError";
392
+ }
393
+ };
394
+ var CopilotChatAudioRecorder = forwardRef((props, ref) => {
395
+ const { className, ...divProps } = props;
396
+ const canvasRef = useRef(null);
397
+ const getLoudness = (n) => {
398
+ const elapsed = Date.now() / 1e3;
399
+ const samples = [];
400
+ for (let i = 0; i < n; i++) {
401
+ const position = i / n * 10 + elapsed * 0.5;
402
+ const wave1 = Math.sin(position * 2) * 0.3;
403
+ const wave2 = Math.sin(position * 5 + elapsed) * 0.2;
404
+ const wave3 = Math.sin(position * 0.5 + elapsed * 0.3) * 0.4;
405
+ const noise = (Math.random() - 0.5) * 0.1;
406
+ const envelope = Math.sin(elapsed * 0.7) * 0.5 + 0.5;
407
+ let amplitude = (wave1 + wave2 + wave3 + noise) * envelope;
408
+ amplitude = Math.max(0, Math.min(1, amplitude * 0.5 + 0.3));
409
+ samples.push(amplitude);
410
+ }
411
+ return samples;
412
+ };
413
+ useEffect(() => {
414
+ const canvas = canvasRef.current;
415
+ if (!canvas) return;
416
+ const ctx = canvas.getContext("2d");
417
+ if (!ctx) return;
418
+ let animationId;
419
+ const draw = () => {
420
+ const rect = canvas.getBoundingClientRect();
421
+ const dpr = window.devicePixelRatio || 1;
422
+ if (canvas.width !== rect.width * dpr || canvas.height !== rect.height * dpr) {
423
+ canvas.width = rect.width * dpr;
424
+ canvas.height = rect.height * dpr;
425
+ ctx.scale(dpr, dpr);
426
+ ctx.imageSmoothingEnabled = false;
427
+ }
428
+ const barWidth = 2;
429
+ const minHeight = 2;
430
+ const maxHeight = 20;
431
+ const gap = 2;
432
+ const numSamples = Math.ceil(rect.width / (barWidth + gap));
433
+ const loudnessData = getLoudness(numSamples);
434
+ ctx.clearRect(0, 0, rect.width, rect.height);
435
+ const computedStyle = getComputedStyle(canvas);
436
+ const currentForeground = computedStyle.color;
437
+ ctx.fillStyle = currentForeground;
438
+ const centerY = rect.height / 2;
439
+ for (let i = 0; i < loudnessData.length; i++) {
440
+ const sample = loudnessData[i] ?? 0;
441
+ const barHeight = Math.round(
442
+ sample * (maxHeight - minHeight) + minHeight
443
+ );
444
+ const x = Math.round(i * (barWidth + gap));
445
+ const y = Math.round(centerY - barHeight / 2);
446
+ ctx.fillRect(x, y, barWidth, barHeight);
447
+ }
448
+ animationId = requestAnimationFrame(draw);
449
+ };
450
+ draw();
451
+ return () => {
452
+ if (animationId) {
453
+ cancelAnimationFrame(animationId);
454
+ }
455
+ };
456
+ }, []);
457
+ useImperativeHandle(
458
+ ref,
459
+ () => ({
460
+ get state() {
461
+ return "idle";
462
+ },
463
+ start: async () => {
464
+ },
465
+ stop: () => new Promise((resolve) => {
466
+ const emptyBlob = new Blob([], { type: "audio/webm" });
467
+ resolve(emptyBlob);
468
+ }),
469
+ dispose: () => {
470
+ }
471
+ }),
472
+ []
473
+ );
474
+ return /* @__PURE__ */ jsx5("div", { className: twMerge2("h-[44px] w-full px-5", className), ...divProps, children: /* @__PURE__ */ jsx5(
475
+ "canvas",
476
+ {
477
+ ref: canvasRef,
478
+ className: "w-full h-full",
479
+ style: { imageRendering: "pixelated" }
480
+ }
481
+ ) });
482
+ });
483
+ CopilotChatAudioRecorder.displayName = "WebAudioRecorder";
484
+
485
+ // src/lib/slots.tsx
486
+ import React2 from "react";
487
+ function shallowEqual(obj1, obj2) {
488
+ const keys1 = Object.keys(obj1);
489
+ const keys2 = Object.keys(obj2);
490
+ if (keys1.length !== keys2.length) return false;
491
+ for (const key of keys1) {
492
+ if (obj1[key] !== obj2[key]) return false;
493
+ }
494
+ return true;
495
+ }
496
+ function renderSlotElement(slot, DefaultComponent, props) {
497
+ if (typeof slot === "string") {
498
+ return React2.createElement(DefaultComponent, {
499
+ ...props,
500
+ className: slot
501
+ });
502
+ }
503
+ if (typeof slot === "function") {
504
+ return React2.createElement(slot, props);
505
+ }
506
+ if (slot && typeof slot === "object" && !React2.isValidElement(slot)) {
507
+ return React2.createElement(DefaultComponent, {
508
+ ...props,
509
+ ...slot
510
+ });
511
+ }
512
+ return React2.createElement(DefaultComponent, props);
513
+ }
514
+ var MemoizedSlotWrapper = React2.memo(
515
+ React2.forwardRef(function MemoizedSlotWrapper2(props, ref) {
516
+ const { $slot, $component, ...rest } = props;
517
+ const propsWithRef = ref !== null ? { ...rest, ref } : rest;
518
+ return renderSlotElement($slot, $component, propsWithRef);
519
+ }),
520
+ (prev, next) => {
521
+ if (prev.$slot !== next.$slot) return false;
522
+ if (prev.$component !== next.$component) return false;
523
+ const { $slot: _ps, $component: _pc, ...prevRest } = prev;
524
+ const { $slot: _ns, $component: _nc, ...nextRest } = next;
525
+ return shallowEqual(
526
+ prevRest,
527
+ nextRest
528
+ );
529
+ }
530
+ );
531
+ function renderSlot(slot, DefaultComponent, props) {
532
+ return React2.createElement(MemoizedSlotWrapper, {
533
+ ...props,
534
+ $slot: slot,
535
+ $component: DefaultComponent
536
+ });
537
+ }
538
+
539
+ // src/components/chat/CopilotChatInput.tsx
540
+ import { Fragment, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
541
+ var SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
542
+ var SLASH_MENU_ITEM_HEIGHT_PX = 40;
543
+ function CopilotChatInput({
544
+ mode = "input",
545
+ onSubmitMessage,
546
+ onStop,
547
+ isRunning = false,
548
+ onStartTranscribe,
549
+ onCancelTranscribe,
550
+ onFinishTranscribe,
551
+ onAddFile,
552
+ onChange,
553
+ value,
554
+ toolsMenu,
555
+ autoFocus = true,
556
+ textArea,
557
+ sendButton,
558
+ startTranscribeButton,
559
+ cancelTranscribeButton,
560
+ finishTranscribeButton,
561
+ addMenuButton,
562
+ audioRecorder,
563
+ children,
564
+ className,
565
+ ...props
566
+ }) {
567
+ const isControlled = value !== void 0;
568
+ const [internalValue, setInternalValue] = useState2(() => value ?? "");
569
+ useEffect2(() => {
570
+ if (!isControlled && value !== void 0) {
571
+ setInternalValue(value);
572
+ }
573
+ }, [isControlled, value]);
574
+ const resolvedValue = isControlled ? value ?? "" : internalValue;
575
+ const [layout, setLayout] = useState2("compact");
576
+ const ignoreResizeRef = useRef2(false);
577
+ const resizeEvaluationRafRef = useRef2(null);
578
+ const isExpanded = mode === "input" && layout === "expanded";
579
+ const [commandQuery, setCommandQuery] = useState2(null);
580
+ const [slashHighlightIndex, setSlashHighlightIndex] = useState2(0);
581
+ const inputRef = useRef2(null);
582
+ const gridRef = useRef2(null);
583
+ const addButtonContainerRef = useRef2(null);
584
+ const actionsContainerRef = useRef2(null);
585
+ const audioRecorderRef = useRef2(null);
586
+ const slashMenuRef = useRef2(null);
587
+ const config = useCopilotChatConfiguration();
588
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
589
+ const previousModalStateRef = useRef2(void 0);
590
+ const measurementCanvasRef = useRef2(null);
591
+ const measurementsRef = useRef2({
592
+ singleLineHeight: 0,
593
+ maxHeight: 0,
594
+ paddingLeft: 0,
595
+ paddingRight: 0
596
+ });
597
+ const commandItems = useMemo2(() => {
598
+ const entries = [];
599
+ const seen = /* @__PURE__ */ new Set();
600
+ const pushItem = (item) => {
601
+ if (item === "-") {
602
+ return;
603
+ }
604
+ if (item.items && item.items.length > 0) {
605
+ for (const nested of item.items) {
606
+ pushItem(nested);
607
+ }
608
+ return;
609
+ }
610
+ if (!seen.has(item.label)) {
611
+ seen.add(item.label);
612
+ entries.push(item);
613
+ }
614
+ };
615
+ if (onAddFile) {
616
+ pushItem({
617
+ label: labels.chatInputToolbarAddButtonLabel,
618
+ action: onAddFile
619
+ });
620
+ }
621
+ if (toolsMenu && toolsMenu.length > 0) {
622
+ for (const item of toolsMenu) {
623
+ pushItem(item);
624
+ }
625
+ }
626
+ return entries;
627
+ }, [labels.chatInputToolbarAddButtonLabel, onAddFile, toolsMenu]);
628
+ const filteredCommands = useMemo2(() => {
629
+ if (commandQuery === null) {
630
+ return [];
631
+ }
632
+ if (commandItems.length === 0) {
633
+ return [];
634
+ }
635
+ const query = commandQuery.trim().toLowerCase();
636
+ if (query.length === 0) {
637
+ return commandItems;
638
+ }
639
+ const startsWith = [];
640
+ const contains = [];
641
+ for (const item of commandItems) {
642
+ const label = item.label.toLowerCase();
643
+ if (label.startsWith(query)) {
644
+ startsWith.push(item);
645
+ } else if (label.includes(query)) {
646
+ contains.push(item);
647
+ }
648
+ }
649
+ return [...startsWith, ...contains];
650
+ }, [commandItems, commandQuery]);
651
+ useEffect2(() => {
652
+ if (!autoFocus) {
653
+ previousModalStateRef.current = config?.isModalOpen;
654
+ return;
655
+ }
656
+ if (config?.isModalOpen && !previousModalStateRef.current) {
657
+ inputRef.current?.focus();
658
+ }
659
+ previousModalStateRef.current = config?.isModalOpen;
660
+ }, [config?.isModalOpen, autoFocus]);
661
+ useEffect2(() => {
662
+ if (commandItems.length === 0 && commandQuery !== null) {
663
+ setCommandQuery(null);
664
+ }
665
+ }, [commandItems.length, commandQuery]);
666
+ const previousCommandQueryRef = useRef2(null);
667
+ useEffect2(() => {
668
+ if (commandQuery !== null && commandQuery !== previousCommandQueryRef.current && filteredCommands.length > 0) {
669
+ setSlashHighlightIndex(0);
670
+ }
671
+ previousCommandQueryRef.current = commandQuery;
672
+ }, [commandQuery, filteredCommands.length]);
673
+ useEffect2(() => {
674
+ if (commandQuery === null) {
675
+ setSlashHighlightIndex(0);
676
+ return;
677
+ }
678
+ if (filteredCommands.length === 0) {
679
+ setSlashHighlightIndex(-1);
680
+ } else if (slashHighlightIndex < 0 || slashHighlightIndex >= filteredCommands.length) {
681
+ setSlashHighlightIndex(0);
682
+ }
683
+ }, [commandQuery, filteredCommands, slashHighlightIndex]);
684
+ useEffect2(() => {
685
+ const recorder = audioRecorderRef.current;
686
+ if (!recorder) {
687
+ return;
688
+ }
689
+ if (mode === "transcribe") {
690
+ recorder.start().catch(console.error);
691
+ } else {
692
+ if (recorder.state === "recording") {
693
+ recorder.stop().catch(console.error);
694
+ }
695
+ }
696
+ }, [mode]);
697
+ useEffect2(() => {
698
+ if (mode !== "input") {
699
+ setLayout("compact");
700
+ setCommandQuery(null);
701
+ }
702
+ }, [mode]);
703
+ const updateSlashState = useCallback(
704
+ (value2) => {
705
+ if (commandItems.length === 0) {
706
+ setCommandQuery((prev) => prev === null ? prev : null);
707
+ return;
708
+ }
709
+ if (value2.startsWith("/")) {
710
+ const firstLine = value2.split(/\r?\n/, 1)[0] ?? "";
711
+ const query = firstLine.slice(1);
712
+ setCommandQuery((prev) => prev === query ? prev : query);
713
+ } else {
714
+ setCommandQuery((prev) => prev === null ? prev : null);
715
+ }
716
+ },
717
+ [commandItems.length]
718
+ );
719
+ useEffect2(() => {
720
+ updateSlashState(resolvedValue);
721
+ }, [resolvedValue, updateSlashState]);
722
+ const handleChange = (e) => {
723
+ const nextValue = e.target.value;
724
+ if (!isControlled) {
725
+ setInternalValue(nextValue);
726
+ }
727
+ onChange?.(nextValue);
728
+ updateSlashState(nextValue);
729
+ };
730
+ const clearInputValue = useCallback(() => {
731
+ if (!isControlled) {
732
+ setInternalValue("");
733
+ }
734
+ if (onChange) {
735
+ onChange("");
736
+ }
737
+ }, [isControlled, onChange]);
738
+ const runCommand = useCallback(
739
+ (item) => {
740
+ clearInputValue();
741
+ item.action?.();
742
+ setCommandQuery(null);
743
+ setSlashHighlightIndex(0);
744
+ requestAnimationFrame(() => {
745
+ inputRef.current?.focus();
746
+ });
747
+ },
748
+ [clearInputValue]
749
+ );
750
+ const handleKeyDown = (e) => {
751
+ if (commandQuery !== null && mode === "input") {
752
+ if (e.key === "ArrowDown") {
753
+ if (filteredCommands.length > 0) {
754
+ e.preventDefault();
755
+ setSlashHighlightIndex((prev) => {
756
+ if (filteredCommands.length === 0) {
757
+ return prev;
758
+ }
759
+ const next = prev === -1 ? 0 : (prev + 1) % filteredCommands.length;
760
+ return next;
761
+ });
762
+ }
763
+ return;
764
+ }
765
+ if (e.key === "ArrowUp") {
766
+ if (filteredCommands.length > 0) {
767
+ e.preventDefault();
768
+ setSlashHighlightIndex((prev) => {
769
+ if (filteredCommands.length === 0) {
770
+ return prev;
771
+ }
772
+ if (prev === -1) {
773
+ return filteredCommands.length - 1;
774
+ }
775
+ return prev <= 0 ? filteredCommands.length - 1 : prev - 1;
776
+ });
777
+ }
778
+ return;
779
+ }
780
+ if (e.key === "Enter") {
781
+ const selected = slashHighlightIndex >= 0 ? filteredCommands[slashHighlightIndex] : void 0;
782
+ if (selected) {
783
+ e.preventDefault();
784
+ runCommand(selected);
785
+ return;
786
+ }
787
+ }
788
+ if (e.key === "Escape") {
789
+ e.preventDefault();
790
+ setCommandQuery(null);
791
+ return;
792
+ }
793
+ }
794
+ if (e.key === "Enter" && !e.shiftKey) {
795
+ e.preventDefault();
796
+ if (isProcessing) {
797
+ onStop?.();
798
+ } else {
799
+ send();
800
+ }
801
+ }
802
+ };
803
+ const send = () => {
804
+ if (!onSubmitMessage) {
805
+ return;
806
+ }
807
+ const trimmed = resolvedValue.trim();
808
+ if (!trimmed) {
809
+ return;
810
+ }
811
+ onSubmitMessage(trimmed);
812
+ if (!isControlled) {
813
+ setInternalValue("");
814
+ onChange?.("");
815
+ }
816
+ if (inputRef.current) {
817
+ inputRef.current.focus();
818
+ }
819
+ };
820
+ const BoundTextArea = renderSlot(textArea, CopilotChatInput.TextArea, {
821
+ ref: inputRef,
822
+ value: resolvedValue,
823
+ onChange: handleChange,
824
+ onKeyDown: handleKeyDown,
825
+ autoFocus,
826
+ className: twMerge3(
827
+ "w-full py-3",
828
+ isExpanded ? "px-5" : "pr-5"
829
+ )
830
+ });
831
+ const isProcessing = mode !== "transcribe" && isRunning;
832
+ const canSend = resolvedValue.trim().length > 0 && !!onSubmitMessage;
833
+ const canStop = !!onStop;
834
+ const handleSendButtonClick = () => {
835
+ if (isProcessing) {
836
+ onStop?.();
837
+ return;
838
+ }
839
+ send();
840
+ };
841
+ const BoundAudioRecorder = renderSlot(audioRecorder, CopilotChatAudioRecorder, {
842
+ ref: audioRecorderRef
843
+ });
844
+ const BoundSendButton = renderSlot(sendButton, CopilotChatInput.SendButton, {
845
+ onClick: handleSendButtonClick,
846
+ disabled: isProcessing ? !canStop : !canSend,
847
+ children: isProcessing && canStop ? /* @__PURE__ */ jsx6(Square, { className: "size-[18px] fill-current" }) : void 0
848
+ });
849
+ const BoundStartTranscribeButton = renderSlot(startTranscribeButton, CopilotChatInput.StartTranscribeButton, {
850
+ onClick: onStartTranscribe
851
+ });
852
+ const BoundCancelTranscribeButton = renderSlot(cancelTranscribeButton, CopilotChatInput.CancelTranscribeButton, {
853
+ onClick: onCancelTranscribe
854
+ });
855
+ const BoundFinishTranscribeButton = renderSlot(finishTranscribeButton, CopilotChatInput.FinishTranscribeButton, {
856
+ onClick: onFinishTranscribe
857
+ });
858
+ const BoundAddMenuButton = renderSlot(addMenuButton, CopilotChatInput.AddMenuButton, {
859
+ disabled: mode === "transcribe",
860
+ onAddFile,
861
+ toolsMenu
862
+ });
863
+ if (children) {
864
+ const childProps = {
865
+ textArea: BoundTextArea,
866
+ audioRecorder: BoundAudioRecorder,
867
+ sendButton: BoundSendButton,
868
+ startTranscribeButton: BoundStartTranscribeButton,
869
+ cancelTranscribeButton: BoundCancelTranscribeButton,
870
+ finishTranscribeButton: BoundFinishTranscribeButton,
871
+ addMenuButton: BoundAddMenuButton,
872
+ onSubmitMessage,
873
+ onStop,
874
+ isRunning,
875
+ onStartTranscribe,
876
+ onCancelTranscribe,
877
+ onFinishTranscribe,
878
+ onAddFile,
879
+ mode,
880
+ toolsMenu,
881
+ autoFocus
882
+ };
883
+ return /* @__PURE__ */ jsx6(Fragment, { children: children(childProps) });
884
+ }
885
+ const handleContainerClick = (e) => {
886
+ const target = e.target;
887
+ if (target.tagName !== "BUTTON" && !target.closest("button") && inputRef.current && mode === "input") {
888
+ inputRef.current.focus();
889
+ }
890
+ };
891
+ const ensureMeasurements = useCallback(() => {
892
+ const textarea = inputRef.current;
893
+ if (!textarea) {
894
+ return;
895
+ }
896
+ const previousValue = textarea.value;
897
+ const previousHeight = textarea.style.height;
898
+ textarea.style.height = "auto";
899
+ const computedStyle = window.getComputedStyle(textarea);
900
+ const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;
901
+ const paddingRight = parseFloat(computedStyle.paddingRight) || 0;
902
+ const paddingTop = parseFloat(computedStyle.paddingTop) || 0;
903
+ const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0;
904
+ textarea.value = "";
905
+ const singleLineHeight = textarea.scrollHeight;
906
+ textarea.value = previousValue;
907
+ const contentHeight = singleLineHeight - paddingTop - paddingBottom;
908
+ const maxHeight = contentHeight * 5 + paddingTop + paddingBottom;
909
+ measurementsRef.current = {
910
+ singleLineHeight,
911
+ maxHeight,
912
+ paddingLeft,
913
+ paddingRight
914
+ };
915
+ textarea.style.height = previousHeight;
916
+ textarea.style.maxHeight = `${maxHeight}px`;
917
+ }, []);
918
+ const adjustTextareaHeight = useCallback(() => {
919
+ const textarea = inputRef.current;
920
+ if (!textarea) {
921
+ return 0;
922
+ }
923
+ if (measurementsRef.current.singleLineHeight === 0) {
924
+ ensureMeasurements();
925
+ }
926
+ const { maxHeight } = measurementsRef.current;
927
+ if (maxHeight) {
928
+ textarea.style.maxHeight = `${maxHeight}px`;
929
+ }
930
+ textarea.style.height = "auto";
931
+ const scrollHeight = textarea.scrollHeight;
932
+ if (maxHeight) {
933
+ textarea.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
934
+ } else {
935
+ textarea.style.height = `${scrollHeight}px`;
936
+ }
937
+ return scrollHeight;
938
+ }, [ensureMeasurements]);
939
+ const updateLayout = useCallback((nextLayout) => {
940
+ setLayout((prev) => {
941
+ if (prev === nextLayout) {
942
+ return prev;
943
+ }
944
+ ignoreResizeRef.current = true;
945
+ return nextLayout;
946
+ });
947
+ }, []);
948
+ const evaluateLayout = useCallback(() => {
949
+ if (mode !== "input") {
950
+ updateLayout("compact");
951
+ return;
952
+ }
953
+ if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
954
+ const isMobileViewport = window.matchMedia("(max-width: 767px)").matches;
955
+ if (isMobileViewport) {
956
+ ensureMeasurements();
957
+ adjustTextareaHeight();
958
+ updateLayout("expanded");
959
+ return;
960
+ }
961
+ }
962
+ const textarea = inputRef.current;
963
+ const grid = gridRef.current;
964
+ const addContainer = addButtonContainerRef.current;
965
+ const actionsContainer = actionsContainerRef.current;
966
+ if (!textarea || !grid || !addContainer || !actionsContainer) {
967
+ return;
968
+ }
969
+ if (measurementsRef.current.singleLineHeight === 0) {
970
+ ensureMeasurements();
971
+ }
972
+ const scrollHeight = adjustTextareaHeight();
973
+ const baseline = measurementsRef.current.singleLineHeight;
974
+ const hasExplicitBreak = resolvedValue.includes("\n");
975
+ const renderedMultiline = baseline > 0 ? scrollHeight > baseline + 1 : false;
976
+ let shouldExpand = hasExplicitBreak || renderedMultiline;
977
+ if (!shouldExpand) {
978
+ const gridStyles = window.getComputedStyle(grid);
979
+ const paddingLeft = parseFloat(gridStyles.paddingLeft) || 0;
980
+ const paddingRight = parseFloat(gridStyles.paddingRight) || 0;
981
+ const columnGap = parseFloat(gridStyles.columnGap) || 0;
982
+ const gridAvailableWidth = grid.clientWidth - paddingLeft - paddingRight;
983
+ if (gridAvailableWidth > 0) {
984
+ const addWidth = addContainer.getBoundingClientRect().width;
985
+ const actionsWidth = actionsContainer.getBoundingClientRect().width;
986
+ const compactWidth = Math.max(gridAvailableWidth - addWidth - actionsWidth - columnGap * 2, 0);
987
+ const canvas = measurementCanvasRef.current ?? document.createElement("canvas");
988
+ if (!measurementCanvasRef.current) {
989
+ measurementCanvasRef.current = canvas;
990
+ }
991
+ const context = canvas.getContext("2d");
992
+ if (context) {
993
+ const textareaStyles = window.getComputedStyle(textarea);
994
+ const font = textareaStyles.font || `${textareaStyles.fontStyle} ${textareaStyles.fontVariant} ${textareaStyles.fontWeight} ${textareaStyles.fontSize}/${textareaStyles.lineHeight} ${textareaStyles.fontFamily}`;
995
+ context.font = font;
996
+ const compactInnerWidth = Math.max(
997
+ compactWidth - (measurementsRef.current.paddingLeft || 0) - (measurementsRef.current.paddingRight || 0),
998
+ 0
999
+ );
1000
+ if (compactInnerWidth > 0) {
1001
+ const lines = resolvedValue.length > 0 ? resolvedValue.split("\n") : [""];
1002
+ let longestWidth = 0;
1003
+ for (const line of lines) {
1004
+ const metrics = context.measureText(line || " ");
1005
+ if (metrics.width > longestWidth) {
1006
+ longestWidth = metrics.width;
1007
+ }
1008
+ }
1009
+ if (longestWidth > compactInnerWidth) {
1010
+ shouldExpand = true;
1011
+ }
1012
+ }
1013
+ }
1014
+ }
1015
+ }
1016
+ const nextLayout = shouldExpand ? "expanded" : "compact";
1017
+ updateLayout(nextLayout);
1018
+ }, [adjustTextareaHeight, ensureMeasurements, mode, resolvedValue, updateLayout]);
1019
+ useLayoutEffect(() => {
1020
+ evaluateLayout();
1021
+ }, [evaluateLayout]);
1022
+ useEffect2(() => {
1023
+ if (typeof ResizeObserver === "undefined") {
1024
+ return;
1025
+ }
1026
+ const textarea = inputRef.current;
1027
+ const grid = gridRef.current;
1028
+ const addContainer = addButtonContainerRef.current;
1029
+ const actionsContainer = actionsContainerRef.current;
1030
+ if (!textarea || !grid || !addContainer || !actionsContainer) {
1031
+ return;
1032
+ }
1033
+ const scheduleEvaluation = () => {
1034
+ if (ignoreResizeRef.current) {
1035
+ ignoreResizeRef.current = false;
1036
+ return;
1037
+ }
1038
+ if (typeof window === "undefined") {
1039
+ evaluateLayout();
1040
+ return;
1041
+ }
1042
+ if (resizeEvaluationRafRef.current !== null) {
1043
+ cancelAnimationFrame(resizeEvaluationRafRef.current);
1044
+ }
1045
+ resizeEvaluationRafRef.current = window.requestAnimationFrame(() => {
1046
+ resizeEvaluationRafRef.current = null;
1047
+ evaluateLayout();
1048
+ });
1049
+ };
1050
+ const observer = new ResizeObserver(() => {
1051
+ scheduleEvaluation();
1052
+ });
1053
+ observer.observe(grid);
1054
+ observer.observe(addContainer);
1055
+ observer.observe(actionsContainer);
1056
+ observer.observe(textarea);
1057
+ return () => {
1058
+ observer.disconnect();
1059
+ if (typeof window !== "undefined" && resizeEvaluationRafRef.current !== null) {
1060
+ cancelAnimationFrame(resizeEvaluationRafRef.current);
1061
+ resizeEvaluationRafRef.current = null;
1062
+ }
1063
+ };
1064
+ }, [evaluateLayout]);
1065
+ const slashMenuVisible = commandQuery !== null && commandItems.length > 0;
1066
+ useEffect2(() => {
1067
+ if (!slashMenuVisible || slashHighlightIndex < 0) {
1068
+ return;
1069
+ }
1070
+ const active = slashMenuRef.current?.querySelector(
1071
+ `[data-slash-index="${slashHighlightIndex}"]`
1072
+ );
1073
+ active?.scrollIntoView({ block: "nearest" });
1074
+ }, [slashMenuVisible, slashHighlightIndex]);
1075
+ const slashMenu = slashMenuVisible ? /* @__PURE__ */ jsx6(
1076
+ "div",
1077
+ {
1078
+ "data-testid": "copilot-slash-menu",
1079
+ role: "listbox",
1080
+ "aria-label": "Slash commands",
1081
+ ref: slashMenuRef,
1082
+ className: "absolute bottom-full left-0 right-0 z-30 mb-2 max-h-64 overflow-y-auto rounded-lg border border-border bg-white shadow-lg dark:border-[#3a3a3a] dark:bg-[#1f1f1f]",
1083
+ style: { maxHeight: `${SLASH_MENU_MAX_VISIBLE_ITEMS * SLASH_MENU_ITEM_HEIGHT_PX}px` },
1084
+ children: filteredCommands.length === 0 ? /* @__PURE__ */ jsx6("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "No commands found" }) : filteredCommands.map((item, index) => {
1085
+ const isActive = index === slashHighlightIndex;
1086
+ return /* @__PURE__ */ jsx6(
1087
+ "button",
1088
+ {
1089
+ type: "button",
1090
+ role: "option",
1091
+ "aria-selected": isActive,
1092
+ "data-active": isActive ? "true" : void 0,
1093
+ "data-slash-index": index,
1094
+ className: twMerge3(
1095
+ "w-full px-3 py-2 text-left text-sm transition-colors",
1096
+ "hover:bg-muted dark:hover:bg-[#2f2f2f]",
1097
+ isActive ? "bg-muted dark:bg-[#2f2f2f]" : "bg-transparent"
1098
+ ),
1099
+ onMouseEnter: () => setSlashHighlightIndex(index),
1100
+ onMouseDown: (event) => {
1101
+ event.preventDefault();
1102
+ runCommand(item);
1103
+ },
1104
+ children: item.label
1105
+ },
1106
+ `${item.label}-${index}`
1107
+ );
1108
+ })
1109
+ }
1110
+ ) : null;
1111
+ return /* @__PURE__ */ jsx6(
1112
+ "div",
1113
+ {
1114
+ className: twMerge3(
1115
+ // Layout
1116
+ "flex w-full flex-col items-center justify-center",
1117
+ // Interaction
1118
+ "cursor-text",
1119
+ // Overflow and clipping
1120
+ "overflow-visible bg-clip-padding contain-inline-size",
1121
+ // Background
1122
+ "bg-white dark:bg-[#303030]",
1123
+ // Visual effects
1124
+ "shadow-[0_4px_4px_0_#0000000a,0_0_1px_0_#0000009e] rounded-[28px]",
1125
+ className
1126
+ ),
1127
+ onClick: handleContainerClick,
1128
+ ...props,
1129
+ "data-layout": isExpanded ? "expanded" : "compact",
1130
+ children: /* @__PURE__ */ jsxs3(
1131
+ "div",
1132
+ {
1133
+ ref: gridRef,
1134
+ className: twMerge3(
1135
+ "grid w-full gap-x-3 gap-y-3 px-3 py-2",
1136
+ isExpanded ? "grid-cols-[auto_minmax(0,1fr)_auto] grid-rows-[auto_auto]" : "grid-cols-[auto_minmax(0,1fr)_auto] items-center"
1137
+ ),
1138
+ "data-layout": isExpanded ? "expanded" : "compact",
1139
+ children: [
1140
+ /* @__PURE__ */ jsx6(
1141
+ "div",
1142
+ {
1143
+ ref: addButtonContainerRef,
1144
+ className: twMerge3(
1145
+ "flex items-center",
1146
+ isExpanded ? "row-start-2" : "row-start-1",
1147
+ "col-start-1"
1148
+ ),
1149
+ children: BoundAddMenuButton
1150
+ }
1151
+ ),
1152
+ /* @__PURE__ */ jsx6(
1153
+ "div",
1154
+ {
1155
+ className: twMerge3(
1156
+ "relative flex min-w-0 flex-col",
1157
+ isExpanded ? "col-span-3 row-start-1" : "col-start-2 row-start-1"
1158
+ ),
1159
+ children: mode === "transcribe" ? BoundAudioRecorder : /* @__PURE__ */ jsxs3(Fragment, { children: [
1160
+ BoundTextArea,
1161
+ slashMenu
1162
+ ] })
1163
+ }
1164
+ ),
1165
+ /* @__PURE__ */ jsx6(
1166
+ "div",
1167
+ {
1168
+ ref: actionsContainerRef,
1169
+ className: twMerge3(
1170
+ "flex items-center justify-end gap-2",
1171
+ isExpanded ? "col-start-3 row-start-2" : "col-start-3 row-start-1"
1172
+ ),
1173
+ children: mode === "transcribe" ? /* @__PURE__ */ jsxs3(Fragment, { children: [
1174
+ onCancelTranscribe && BoundCancelTranscribeButton,
1175
+ onFinishTranscribe && BoundFinishTranscribeButton
1176
+ ] }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
1177
+ onStartTranscribe && BoundStartTranscribeButton,
1178
+ BoundSendButton
1179
+ ] })
1180
+ }
1181
+ )
1182
+ ]
1183
+ }
1184
+ )
1185
+ }
1186
+ );
1187
+ }
1188
+ ((CopilotChatInput2) => {
1189
+ CopilotChatInput2.SendButton = ({ className, children, ...props }) => /* @__PURE__ */ jsx6("div", { className: "mr-[10px]", children: /* @__PURE__ */ jsx6(
1190
+ Button,
1191
+ {
1192
+ type: "button",
1193
+ variant: "chatInputToolbarPrimary",
1194
+ size: "chatInputToolbarIcon",
1195
+ className,
1196
+ ...props,
1197
+ children: children ?? /* @__PURE__ */ jsx6(ArrowUp, { className: "size-[18px]" })
1198
+ }
1199
+ ) });
1200
+ CopilotChatInput2.ToolbarButton = ({ icon, labelKey, defaultClassName, className, ...props }) => {
1201
+ const config = useCopilotChatConfiguration();
1202
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
1203
+ return /* @__PURE__ */ jsxs3(Tooltip, { children: [
1204
+ /* @__PURE__ */ jsx6(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(
1205
+ Button,
1206
+ {
1207
+ type: "button",
1208
+ variant: "chatInputToolbarSecondary",
1209
+ size: "chatInputToolbarIcon",
1210
+ className: twMerge3(defaultClassName, className),
1211
+ ...props,
1212
+ children: icon
1213
+ }
1214
+ ) }),
1215
+ /* @__PURE__ */ jsx6(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsx6("p", { children: labels[labelKey] }) })
1216
+ ] });
1217
+ };
1218
+ CopilotChatInput2.StartTranscribeButton = (props) => /* @__PURE__ */ jsx6(
1219
+ CopilotChatInput2.ToolbarButton,
1220
+ {
1221
+ icon: /* @__PURE__ */ jsx6(Mic, { className: "size-[18px]" }),
1222
+ labelKey: "chatInputToolbarStartTranscribeButtonLabel",
1223
+ defaultClassName: "mr-2",
1224
+ ...props
1225
+ }
1226
+ );
1227
+ CopilotChatInput2.CancelTranscribeButton = (props) => /* @__PURE__ */ jsx6(
1228
+ CopilotChatInput2.ToolbarButton,
1229
+ {
1230
+ icon: /* @__PURE__ */ jsx6(X, { className: "size-[18px]" }),
1231
+ labelKey: "chatInputToolbarCancelTranscribeButtonLabel",
1232
+ defaultClassName: "mr-2",
1233
+ ...props
1234
+ }
1235
+ );
1236
+ CopilotChatInput2.FinishTranscribeButton = (props) => /* @__PURE__ */ jsx6(
1237
+ CopilotChatInput2.ToolbarButton,
1238
+ {
1239
+ icon: /* @__PURE__ */ jsx6(Check, { className: "size-[18px]" }),
1240
+ labelKey: "chatInputToolbarFinishTranscribeButtonLabel",
1241
+ defaultClassName: "mr-[10px]",
1242
+ ...props
1243
+ }
1244
+ );
1245
+ CopilotChatInput2.AddMenuButton = ({ className, toolsMenu, onAddFile, disabled, ...props }) => {
1246
+ const config = useCopilotChatConfiguration();
1247
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
1248
+ const menuItems = useMemo2(() => {
1249
+ const items = [];
1250
+ if (onAddFile) {
1251
+ items.push({
1252
+ label: labels.chatInputToolbarAddButtonLabel,
1253
+ action: onAddFile
1254
+ });
1255
+ }
1256
+ if (toolsMenu && toolsMenu.length > 0) {
1257
+ if (items.length > 0) {
1258
+ items.push("-");
1259
+ }
1260
+ for (const item of toolsMenu) {
1261
+ if (item === "-") {
1262
+ if (items.length === 0 || items[items.length - 1] === "-") {
1263
+ continue;
1264
+ }
1265
+ items.push(item);
1266
+ } else {
1267
+ items.push(item);
1268
+ }
1269
+ }
1270
+ while (items.length > 0 && items[items.length - 1] === "-") {
1271
+ items.pop();
1272
+ }
1273
+ }
1274
+ return items;
1275
+ }, [onAddFile, toolsMenu, labels.chatInputToolbarAddButtonLabel]);
1276
+ const renderMenuItems = useCallback(
1277
+ (items) => items.map((item, index) => {
1278
+ if (item === "-") {
1279
+ return /* @__PURE__ */ jsx6(DropdownMenuSeparator, {}, `separator-${index}`);
1280
+ }
1281
+ if (item.items && item.items.length > 0) {
1282
+ return /* @__PURE__ */ jsxs3(DropdownMenuSub, { children: [
1283
+ /* @__PURE__ */ jsx6(DropdownMenuSubTrigger, { children: item.label }),
1284
+ /* @__PURE__ */ jsx6(DropdownMenuSubContent, { children: renderMenuItems(item.items) })
1285
+ ] }, `group-${index}`);
1286
+ }
1287
+ return /* @__PURE__ */ jsx6(DropdownMenuItem, { onClick: item.action, children: item.label }, `item-${index}`);
1288
+ }),
1289
+ []
1290
+ );
1291
+ const hasMenuItems = menuItems.length > 0;
1292
+ const isDisabled = disabled || !hasMenuItems;
1293
+ return /* @__PURE__ */ jsxs3(DropdownMenu, { children: [
1294
+ /* @__PURE__ */ jsxs3(Tooltip, { children: [
1295
+ /* @__PURE__ */ jsx6(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx6(
1296
+ Button,
1297
+ {
1298
+ type: "button",
1299
+ variant: "chatInputToolbarSecondary",
1300
+ size: "chatInputToolbarIcon",
1301
+ className: twMerge3("ml-1", className),
1302
+ disabled: isDisabled,
1303
+ ...props,
1304
+ children: /* @__PURE__ */ jsx6(Plus, { className: "size-[20px]" })
1305
+ }
1306
+ ) }) }),
1307
+ /* @__PURE__ */ jsx6(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsxs3("p", { className: "flex items-center gap-1 text-xs font-medium", children: [
1308
+ /* @__PURE__ */ jsx6("span", { children: "Add files and more" }),
1309
+ /* @__PURE__ */ jsx6("code", { className: "rounded bg-[#4a4a4a] px-1 py-[1px] font-mono text-[11px] text-white dark:bg-[#e0e0e0] dark:text-black", children: "/" })
1310
+ ] }) })
1311
+ ] }),
1312
+ hasMenuItems && /* @__PURE__ */ jsx6(DropdownMenuContent, { side: "top", align: "start", children: renderMenuItems(menuItems) })
1313
+ ] });
1314
+ };
1315
+ CopilotChatInput2.TextArea = forwardRef2(function TextArea2({ style, className, autoFocus, ...props }, ref) {
1316
+ const internalTextareaRef = useRef2(null);
1317
+ const config = useCopilotChatConfiguration();
1318
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
1319
+ useImperativeHandle2(ref, () => internalTextareaRef.current);
1320
+ useEffect2(() => {
1321
+ const textarea = internalTextareaRef.current;
1322
+ if (!textarea) return;
1323
+ const handleFocus = () => {
1324
+ setTimeout(() => {
1325
+ textarea.scrollIntoView({ behavior: "smooth", block: "nearest" });
1326
+ }, 300);
1327
+ };
1328
+ textarea.addEventListener("focus", handleFocus);
1329
+ return () => textarea.removeEventListener("focus", handleFocus);
1330
+ }, []);
1331
+ useEffect2(() => {
1332
+ if (autoFocus) {
1333
+ internalTextareaRef.current?.focus();
1334
+ }
1335
+ }, [autoFocus]);
1336
+ return /* @__PURE__ */ jsx6(
1337
+ "textarea",
1338
+ {
1339
+ ref: internalTextareaRef,
1340
+ ...props,
1341
+ style: {
1342
+ overflow: "auto",
1343
+ resize: "none",
1344
+ ...style
1345
+ },
1346
+ placeholder: labels.chatInputPlaceholder,
1347
+ className: twMerge3(
1348
+ "bg-transparent outline-none antialiased font-regular leading-relaxed text-[16px] placeholder:text-[#00000077] dark:placeholder:text-[#fffc]",
1349
+ className
1350
+ ),
1351
+ rows: 1
1352
+ }
1353
+ );
1354
+ });
1355
+ CopilotChatInput2.AudioRecorder = CopilotChatAudioRecorder;
1356
+ })(CopilotChatInput || (CopilotChatInput = {}));
1357
+ CopilotChatInput.TextArea.displayName = "CopilotChatInput.TextArea";
1358
+ CopilotChatInput.SendButton.displayName = "CopilotChatInput.SendButton";
1359
+ CopilotChatInput.ToolbarButton.displayName = "CopilotChatInput.ToolbarButton";
1360
+ CopilotChatInput.StartTranscribeButton.displayName = "CopilotChatInput.StartTranscribeButton";
1361
+ CopilotChatInput.CancelTranscribeButton.displayName = "CopilotChatInput.CancelTranscribeButton";
1362
+ CopilotChatInput.FinishTranscribeButton.displayName = "CopilotChatInput.FinishTranscribeButton";
1363
+ CopilotChatInput.AddMenuButton.displayName = "CopilotChatInput.AddMenuButton";
1364
+ var CopilotChatInput_default = CopilotChatInput;
1365
+
1366
+ // src/components/chat/CopilotChatAssistantMessage.tsx
1367
+ import { useState as useState7 } from "react";
1368
+ import {
1369
+ Copy,
1370
+ Check as Check2,
1371
+ ThumbsUp,
1372
+ ThumbsDown,
1373
+ Volume2,
1374
+ RefreshCw
1375
+ } from "lucide-react";
1376
+ import { twMerge as twMerge4 } from "tailwind-merge";
1377
+ import "katex/dist/katex.min.css";
1378
+ import { Streamdown } from "streamdown";
1379
+
1380
+ // src/hooks/use-render-tool-call.tsx
1381
+ import React7, { useCallback as useCallback3, useMemo as useMemo4, useSyncExternalStore } from "react";
1382
+ import { ToolCallStatus } from "@copilotkitnext/core";
1383
+
1384
+ // src/providers/CopilotKitProvider.tsx
1385
+ import { createContext as createContext2, useContext as useContext2, useMemo as useMemo3, useEffect as useEffect5, useReducer, useRef as useRef4, useState as useState5 } from "react";
1386
+ import { z as z2 } from "zod";
1387
+
1388
+ // src/lib/react-core.ts
1389
+ import { CopilotKitCore } from "@copilotkitnext/core";
1390
+ var CopilotKitCoreReact = class extends CopilotKitCore {
1391
+ _renderToolCalls = [];
1392
+ _renderCustomMessages = [];
1393
+ _renderActivityMessages = [];
1394
+ constructor(config) {
1395
+ super(config);
1396
+ this._renderToolCalls = config.renderToolCalls ?? [];
1397
+ this._renderCustomMessages = config.renderCustomMessages ?? [];
1398
+ this._renderActivityMessages = config.renderActivityMessages ?? [];
1399
+ }
1400
+ get renderCustomMessages() {
1401
+ return this._renderCustomMessages;
1402
+ }
1403
+ get renderActivityMessages() {
1404
+ return this._renderActivityMessages;
1405
+ }
1406
+ get renderToolCalls() {
1407
+ return this._renderToolCalls;
1408
+ }
1409
+ setRenderToolCalls(renderToolCalls) {
1410
+ this._renderToolCalls = renderToolCalls;
1411
+ void this.notifySubscribers(
1412
+ (subscriber) => {
1413
+ const reactSubscriber = subscriber;
1414
+ if (reactSubscriber.onRenderToolCallsChanged) {
1415
+ reactSubscriber.onRenderToolCallsChanged({
1416
+ copilotkit: this,
1417
+ renderToolCalls: this.renderToolCalls
1418
+ });
1419
+ }
1420
+ },
1421
+ "Subscriber onRenderToolCallsChanged error:"
1422
+ );
1423
+ }
1424
+ // Override to accept React-specific subscriber type
1425
+ subscribe(subscriber) {
1426
+ return super.subscribe(subscriber);
1427
+ }
1428
+ };
1429
+
1430
+ // src/components/CopilotKitInspector.tsx
1431
+ import * as React4 from "react";
1432
+ import { createComponent } from "@lit-labs/react";
1433
+ import { jsx as jsx7 } from "react/jsx-runtime";
1434
+ var CopilotKitInspector = ({ core, ...rest }) => {
1435
+ const [InspectorComponent, setInspectorComponent] = React4.useState(null);
1436
+ React4.useEffect(() => {
1437
+ let mounted = true;
1438
+ import("@copilotkitnext/web-inspector").then((mod) => {
1439
+ mod.defineWebInspector?.();
1440
+ const Component = createComponent({
1441
+ tagName: mod.WEB_INSPECTOR_TAG,
1442
+ elementClass: mod.WebInspectorElement,
1443
+ react: React4
1444
+ });
1445
+ if (mounted) {
1446
+ setInspectorComponent(() => Component);
1447
+ }
1448
+ });
1449
+ return () => {
1450
+ mounted = false;
1451
+ };
1452
+ }, []);
1453
+ if (!InspectorComponent) return null;
1454
+ return /* @__PURE__ */ jsx7(InspectorComponent, { ...rest, core: core ?? null });
1455
+ };
1456
+ CopilotKitInspector.displayName = "CopilotKitInspector";
1457
+
1458
+ // src/components/MCPAppsActivityRenderer.tsx
1459
+ import { useEffect as useEffect4, useRef as useRef3, useState as useState4, useCallback as useCallback2 } from "react";
1460
+ import { z } from "zod";
1461
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1462
+ var PROTOCOL_VERSION = "2025-06-18";
1463
+ var MCPAppsActivityType = "mcp-apps";
1464
+ var MCPAppsActivityContentSchema = z.object({
1465
+ result: z.object({
1466
+ content: z.array(z.any()).optional(),
1467
+ structuredContent: z.any().optional(),
1468
+ isError: z.boolean().optional()
1469
+ }),
1470
+ resource: z.object({
1471
+ uri: z.string(),
1472
+ mimeType: z.string().optional(),
1473
+ text: z.string().optional(),
1474
+ blob: z.string().optional()
1475
+ }),
1476
+ // Server ID for proxying requests (MD5 hash of server config)
1477
+ serverId: z.string().optional(),
1478
+ // Original tool input arguments
1479
+ toolInput: z.record(z.unknown()).optional()
1480
+ });
1481
+ function isRequest(msg) {
1482
+ return "id" in msg && "method" in msg;
1483
+ }
1484
+ function isNotification(msg) {
1485
+ return !("id" in msg) && "method" in msg;
1486
+ }
1487
+ function extractHtmlFromResource(resource) {
1488
+ if (resource.text) {
1489
+ return resource.text;
1490
+ }
1491
+ if (resource.blob) {
1492
+ return atob(resource.blob);
1493
+ }
1494
+ throw new Error("Resource has no text or blob content");
1495
+ }
1496
+ var MCPAppsActivityRenderer = ({ content, agent }) => {
1497
+ const containerRef = useRef3(null);
1498
+ const iframeRef = useRef3(null);
1499
+ const [iframeReady, setIframeReady] = useState4(false);
1500
+ const [error, setError] = useState4(null);
1501
+ const [iframeSize, setIframeSize] = useState4({});
1502
+ const contentRef = useRef3(content);
1503
+ contentRef.current = content;
1504
+ const agentRef = useRef3(agent);
1505
+ agentRef.current = agent;
1506
+ const sendToIframe = useCallback2((msg) => {
1507
+ if (iframeRef.current?.contentWindow) {
1508
+ console.log("[MCPAppsRenderer] Sending to iframe:", msg);
1509
+ iframeRef.current.contentWindow.postMessage(msg, "*");
1510
+ }
1511
+ }, []);
1512
+ const sendResponse = useCallback2((id, result) => {
1513
+ sendToIframe({
1514
+ jsonrpc: "2.0",
1515
+ id,
1516
+ result
1517
+ });
1518
+ }, [sendToIframe]);
1519
+ const sendErrorResponse = useCallback2((id, code, message) => {
1520
+ sendToIframe({
1521
+ jsonrpc: "2.0",
1522
+ id,
1523
+ error: { code, message }
1524
+ });
1525
+ }, [sendToIframe]);
1526
+ const sendNotification = useCallback2((method, params) => {
1527
+ sendToIframe({
1528
+ jsonrpc: "2.0",
1529
+ method,
1530
+ params: params || {}
1531
+ });
1532
+ }, [sendToIframe]);
1533
+ useEffect4(() => {
1534
+ if (!containerRef.current) return;
1535
+ let mounted = true;
1536
+ let messageHandler = null;
1537
+ const setup = async () => {
1538
+ try {
1539
+ const iframe = document.createElement("iframe");
1540
+ iframe.style.width = "100%";
1541
+ iframe.style.height = "300px";
1542
+ iframe.style.border = "none";
1543
+ iframe.style.backgroundColor = "transparent";
1544
+ iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms");
1545
+ const sandboxReady = new Promise((resolve) => {
1546
+ const initialListener = (event) => {
1547
+ if (event.source === iframe.contentWindow) {
1548
+ if (event.data?.method === "ui/notifications/sandbox-proxy-ready") {
1549
+ window.removeEventListener("message", initialListener);
1550
+ resolve();
1551
+ }
1552
+ }
1553
+ };
1554
+ window.addEventListener("message", initialListener);
1555
+ });
1556
+ iframe.src = "/sandbox.html";
1557
+ iframeRef.current = iframe;
1558
+ containerRef.current?.appendChild(iframe);
1559
+ await sandboxReady;
1560
+ if (!mounted) return;
1561
+ console.log("[MCPAppsRenderer] Sandbox proxy ready");
1562
+ messageHandler = async (event) => {
1563
+ if (event.source !== iframe.contentWindow) return;
1564
+ const msg = event.data;
1565
+ if (!msg || typeof msg !== "object" || msg.jsonrpc !== "2.0") return;
1566
+ console.log("[MCPAppsRenderer] Received from iframe:", msg);
1567
+ if (isRequest(msg)) {
1568
+ switch (msg.method) {
1569
+ case "ui/initialize": {
1570
+ sendResponse(msg.id, {
1571
+ protocolVersion: PROTOCOL_VERSION,
1572
+ hostInfo: {
1573
+ name: "CopilotKit MCP Apps Host",
1574
+ version: "1.0.0"
1575
+ },
1576
+ hostCapabilities: {
1577
+ openLinks: {},
1578
+ logging: {}
1579
+ },
1580
+ hostContext: {
1581
+ theme: "light",
1582
+ platform: "web"
1583
+ }
1584
+ });
1585
+ break;
1586
+ }
1587
+ case "ui/message": {
1588
+ console.log("[MCPAppsRenderer] ui/message request:", msg.params);
1589
+ sendResponse(msg.id, { isError: false });
1590
+ break;
1591
+ }
1592
+ case "ui/open-link": {
1593
+ const url = msg.params?.url;
1594
+ if (url) {
1595
+ window.open(url, "_blank", "noopener,noreferrer");
1596
+ sendResponse(msg.id, { isError: false });
1597
+ } else {
1598
+ sendErrorResponse(msg.id, -32602, "Missing url parameter");
1599
+ }
1600
+ break;
1601
+ }
1602
+ case "tools/call": {
1603
+ const { serverId } = contentRef.current;
1604
+ const currentAgent = agentRef.current;
1605
+ if (!serverId) {
1606
+ sendErrorResponse(msg.id, -32603, "No server ID available for proxying");
1607
+ break;
1608
+ }
1609
+ if (!currentAgent) {
1610
+ sendErrorResponse(msg.id, -32603, "No agent available for proxying");
1611
+ break;
1612
+ }
1613
+ try {
1614
+ const runResult = await currentAgent.runAgent({
1615
+ forwardedProps: {
1616
+ __proxiedMCPRequest: {
1617
+ serverId,
1618
+ method: "tools/call",
1619
+ params: msg.params
1620
+ }
1621
+ }
1622
+ });
1623
+ sendResponse(msg.id, runResult.result || {});
1624
+ } catch (err) {
1625
+ console.error("[MCPAppsRenderer] tools/call error:", err);
1626
+ sendErrorResponse(msg.id, -32603, String(err));
1627
+ }
1628
+ break;
1629
+ }
1630
+ default:
1631
+ sendErrorResponse(msg.id, -32601, `Method not found: ${msg.method}`);
1632
+ }
1633
+ }
1634
+ if (isNotification(msg)) {
1635
+ switch (msg.method) {
1636
+ case "ui/notifications/initialized": {
1637
+ console.log("[MCPAppsRenderer] Inner iframe initialized");
1638
+ if (mounted) {
1639
+ setIframeReady(true);
1640
+ }
1641
+ break;
1642
+ }
1643
+ case "ui/notifications/size-change": {
1644
+ const { width, height } = msg.params || {};
1645
+ console.log("[MCPAppsRenderer] Size change:", { width, height });
1646
+ if (mounted) {
1647
+ setIframeSize({
1648
+ width: typeof width === "number" ? width : void 0,
1649
+ height: typeof height === "number" ? height : void 0
1650
+ });
1651
+ }
1652
+ break;
1653
+ }
1654
+ case "notifications/message": {
1655
+ console.log("[MCPAppsRenderer] App log:", msg.params);
1656
+ break;
1657
+ }
1658
+ }
1659
+ }
1660
+ };
1661
+ window.addEventListener("message", messageHandler);
1662
+ const html = extractHtmlFromResource(content.resource);
1663
+ sendNotification("ui/notifications/sandbox-resource-ready", { html });
1664
+ } catch (err) {
1665
+ console.error("[MCPAppsRenderer] Setup error:", err);
1666
+ if (mounted) {
1667
+ setError(err instanceof Error ? err : new Error(String(err)));
1668
+ }
1669
+ }
1670
+ };
1671
+ setup();
1672
+ return () => {
1673
+ mounted = false;
1674
+ if (messageHandler) {
1675
+ window.removeEventListener("message", messageHandler);
1676
+ }
1677
+ if (iframeRef.current && containerRef.current?.contains(iframeRef.current)) {
1678
+ containerRef.current.removeChild(iframeRef.current);
1679
+ }
1680
+ iframeRef.current = null;
1681
+ };
1682
+ }, [content.resource, sendNotification, sendResponse, sendErrorResponse]);
1683
+ useEffect4(() => {
1684
+ if (iframeRef.current) {
1685
+ if (iframeSize.width !== void 0) {
1686
+ iframeRef.current.style.width = `${iframeSize.width}px`;
1687
+ }
1688
+ if (iframeSize.height !== void 0) {
1689
+ iframeRef.current.style.height = `${iframeSize.height}px`;
1690
+ }
1691
+ }
1692
+ }, [iframeSize]);
1693
+ useEffect4(() => {
1694
+ if (iframeReady && content.toolInput) {
1695
+ console.log("[MCPAppsRenderer] Sending tool input:", content.toolInput);
1696
+ sendNotification("ui/notifications/tool-input", {
1697
+ arguments: content.toolInput
1698
+ });
1699
+ }
1700
+ }, [iframeReady, content.toolInput, sendNotification]);
1701
+ useEffect4(() => {
1702
+ if (iframeReady && content.result) {
1703
+ console.log("[MCPAppsRenderer] Sending tool result:", content.result);
1704
+ sendNotification("ui/notifications/tool-result", content.result);
1705
+ }
1706
+ }, [iframeReady, content.result, sendNotification]);
1707
+ return /* @__PURE__ */ jsx8(
1708
+ "div",
1709
+ {
1710
+ ref: containerRef,
1711
+ style: {
1712
+ width: "100%",
1713
+ minHeight: "100px",
1714
+ borderRadius: "8px",
1715
+ overflow: "hidden",
1716
+ backgroundColor: "#f9f9f9",
1717
+ border: "1px solid #e0e0e0"
1718
+ },
1719
+ children: error && /* @__PURE__ */ jsxs4("div", { style: { color: "red", padding: "1rem" }, children: [
1720
+ "Error: ",
1721
+ error.message
1722
+ ] })
1723
+ }
1724
+ );
1725
+ };
1726
+
1727
+ // src/providers/CopilotKitProvider.tsx
1728
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1729
+ var HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
1730
+ var COPILOT_CLOUD_CHAT_URL = "https://api.cloud.copilotkit.ai/copilotkit/v1";
1731
+ var EMPTY_SET = /* @__PURE__ */ new Set();
1732
+ var CopilotKitContext = createContext2({
1733
+ copilotkit: null,
1734
+ executingToolCallIds: EMPTY_SET
1735
+ });
1736
+ function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
1737
+ const empty = useMemo3(() => [], []);
1738
+ const value = prop ?? empty;
1739
+ const initial = useRef4(value);
1740
+ useEffect5(() => {
1741
+ if (warningMessage && value !== initial.current && (isMeaningfulChange ? isMeaningfulChange(initial.current, value) : true)) {
1742
+ console.error(warningMessage);
1743
+ }
1744
+ }, [value, warningMessage]);
1745
+ return value;
1746
+ }
1747
+ var CopilotKitProvider = ({
1748
+ children,
1749
+ runtimeUrl,
1750
+ headers = {},
1751
+ publicApiKey,
1752
+ publicLicenseKey,
1753
+ properties = {},
1754
+ agents__unsafe_dev_only: agents = {},
1755
+ renderToolCalls,
1756
+ renderActivityMessages,
1757
+ renderCustomMessages,
1758
+ frontendTools,
1759
+ humanInTheLoop,
1760
+ showDevConsole = false,
1761
+ useSingleEndpoint = false
1762
+ }) => {
1763
+ const [shouldRenderInspector, setShouldRenderInspector] = useState5(false);
1764
+ useEffect5(() => {
1765
+ if (typeof window === "undefined") {
1766
+ return;
1767
+ }
1768
+ if (showDevConsole === true) {
1769
+ setShouldRenderInspector(true);
1770
+ } else if (showDevConsole === "auto") {
1771
+ const localhostHosts = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
1772
+ if (localhostHosts.has(window.location.hostname)) {
1773
+ setShouldRenderInspector(true);
1774
+ } else {
1775
+ setShouldRenderInspector(false);
1776
+ }
1777
+ } else {
1778
+ setShouldRenderInspector(false);
1779
+ }
1780
+ }, [showDevConsole]);
1781
+ const renderToolCallsList = useStableArrayProp(
1782
+ renderToolCalls,
1783
+ "renderToolCalls must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead.",
1784
+ (initial, next) => {
1785
+ const key = (rc) => `${rc?.agentId ?? ""}:${rc?.name ?? ""}`;
1786
+ const setFrom = (arr) => new Set(arr.map(key));
1787
+ const a = setFrom(initial);
1788
+ const b = setFrom(next);
1789
+ if (a.size !== b.size) return true;
1790
+ for (const k of a) if (!b.has(k)) return true;
1791
+ return false;
1792
+ }
1793
+ );
1794
+ const renderCustomMessagesList = useStableArrayProp(
1795
+ renderCustomMessages,
1796
+ "renderCustomMessages must be a stable array."
1797
+ );
1798
+ const renderActivityMessagesList = useStableArrayProp(
1799
+ renderActivityMessages,
1800
+ "renderActivityMessages must be a stable array."
1801
+ );
1802
+ const builtInActivityRenderers = useMemo3(() => [
1803
+ {
1804
+ activityType: MCPAppsActivityType,
1805
+ content: MCPAppsActivityContentSchema,
1806
+ render: MCPAppsActivityRenderer
1807
+ }
1808
+ ], []);
1809
+ const allActivityRenderers = useMemo3(() => {
1810
+ return [...renderActivityMessagesList, ...builtInActivityRenderers];
1811
+ }, [renderActivityMessagesList, builtInActivityRenderers]);
1812
+ const resolvedPublicKey = publicApiKey ?? publicLicenseKey;
1813
+ const hasLocalAgents = agents && Object.keys(agents).length > 0;
1814
+ const mergedHeaders = useMemo3(() => {
1815
+ if (!resolvedPublicKey) return headers;
1816
+ if (headers[HEADER_NAME]) return headers;
1817
+ return {
1818
+ ...headers,
1819
+ [HEADER_NAME]: resolvedPublicKey
1820
+ };
1821
+ }, [headers, resolvedPublicKey]);
1822
+ if (!runtimeUrl && !resolvedPublicKey && !hasLocalAgents) {
1823
+ const message = "Missing required prop: 'runtimeUrl' or 'publicApiKey' or 'publicLicenseKey'";
1824
+ if (process.env.NODE_ENV === "production") {
1825
+ throw new Error(message);
1826
+ } else {
1827
+ console.warn(message);
1828
+ }
1829
+ }
1830
+ const chatApiEndpoint = runtimeUrl ?? (resolvedPublicKey ? COPILOT_CLOUD_CHAT_URL : void 0);
1831
+ const frontendToolsList = useStableArrayProp(
1832
+ frontendTools,
1833
+ "frontendTools must be a stable array. If you want to dynamically add or remove tools, use `useFrontendTool` instead."
1834
+ );
1835
+ const humanInTheLoopList = useStableArrayProp(
1836
+ humanInTheLoop,
1837
+ "humanInTheLoop must be a stable array. If you want to dynamically add or remove human-in-the-loop tools, use `useHumanInTheLoop` instead."
1838
+ );
1839
+ const processedHumanInTheLoopTools = useMemo3(() => {
1840
+ const processedTools = [];
1841
+ const processedRenderToolCalls = [];
1842
+ humanInTheLoopList.forEach((tool) => {
1843
+ const frontendTool = {
1844
+ name: tool.name,
1845
+ description: tool.description,
1846
+ parameters: tool.parameters,
1847
+ followUp: tool.followUp,
1848
+ ...tool.agentId && { agentId: tool.agentId },
1849
+ handler: async () => {
1850
+ return new Promise((resolve) => {
1851
+ console.warn(`Human-in-the-loop tool '${tool.name}' called but no interactive handler is set up.`);
1852
+ resolve(void 0);
1853
+ });
1854
+ }
1855
+ };
1856
+ processedTools.push(frontendTool);
1857
+ if (tool.render) {
1858
+ processedRenderToolCalls.push({
1859
+ name: tool.name,
1860
+ args: tool.parameters,
1861
+ render: tool.render,
1862
+ ...tool.agentId && { agentId: tool.agentId }
1863
+ });
1864
+ }
1865
+ });
1866
+ return { tools: processedTools, renderToolCalls: processedRenderToolCalls };
1867
+ }, [humanInTheLoopList]);
1868
+ const allTools = useMemo3(() => {
1869
+ const tools = [];
1870
+ tools.push(...frontendToolsList);
1871
+ tools.push(...processedHumanInTheLoopTools.tools);
1872
+ return tools;
1873
+ }, [frontendToolsList, processedHumanInTheLoopTools]);
1874
+ const allRenderToolCalls = useMemo3(() => {
1875
+ const combined = [...renderToolCallsList];
1876
+ frontendToolsList.forEach((tool) => {
1877
+ if (tool.render) {
1878
+ const args = tool.parameters || (tool.name === "*" ? z2.any() : void 0);
1879
+ if (args) {
1880
+ combined.push({
1881
+ name: tool.name,
1882
+ args,
1883
+ render: tool.render
1884
+ });
1885
+ }
1886
+ }
1887
+ });
1888
+ combined.push(...processedHumanInTheLoopTools.renderToolCalls);
1889
+ return combined;
1890
+ }, [renderToolCallsList, frontendToolsList, processedHumanInTheLoopTools]);
1891
+ const copilotkit = useMemo3(() => {
1892
+ const copilotkit2 = new CopilotKitCoreReact({
1893
+ runtimeUrl: chatApiEndpoint,
1894
+ runtimeTransport: useSingleEndpoint ? "single" : "rest",
1895
+ headers: mergedHeaders,
1896
+ properties,
1897
+ agents__unsafe_dev_only: agents,
1898
+ tools: allTools,
1899
+ renderToolCalls: allRenderToolCalls,
1900
+ renderActivityMessages: allActivityRenderers,
1901
+ renderCustomMessages: renderCustomMessagesList
1902
+ });
1903
+ return copilotkit2;
1904
+ }, [allTools, allRenderToolCalls, allActivityRenderers, renderCustomMessagesList, useSingleEndpoint]);
1905
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
1906
+ useEffect5(() => {
1907
+ const subscription = copilotkit.subscribe({
1908
+ onRenderToolCallsChanged: () => {
1909
+ forceUpdate();
1910
+ }
1911
+ });
1912
+ return () => {
1913
+ subscription.unsubscribe();
1914
+ };
1915
+ }, [copilotkit]);
1916
+ const [executingToolCallIds, setExecutingToolCallIds] = useState5(() => /* @__PURE__ */ new Set());
1917
+ useEffect5(() => {
1918
+ const subscription = copilotkit.subscribe({
1919
+ onToolExecutionStart: ({ toolCallId }) => {
1920
+ setExecutingToolCallIds((prev) => {
1921
+ if (prev.has(toolCallId)) return prev;
1922
+ const next = new Set(prev);
1923
+ next.add(toolCallId);
1924
+ return next;
1925
+ });
1926
+ },
1927
+ onToolExecutionEnd: ({ toolCallId }) => {
1928
+ setExecutingToolCallIds((prev) => {
1929
+ if (!prev.has(toolCallId)) return prev;
1930
+ const next = new Set(prev);
1931
+ next.delete(toolCallId);
1932
+ return next;
1933
+ });
1934
+ }
1935
+ });
1936
+ return () => {
1937
+ subscription.unsubscribe();
1938
+ };
1939
+ }, [copilotkit]);
1940
+ useEffect5(() => {
1941
+ copilotkit.setRuntimeUrl(chatApiEndpoint);
1942
+ copilotkit.setRuntimeTransport(useSingleEndpoint ? "single" : "rest");
1943
+ copilotkit.setHeaders(mergedHeaders);
1944
+ copilotkit.setProperties(properties);
1945
+ copilotkit.setAgents__unsafe_dev_only(agents);
1946
+ }, [chatApiEndpoint, mergedHeaders, properties, agents, useSingleEndpoint]);
1947
+ return /* @__PURE__ */ jsxs5(
1948
+ CopilotKitContext.Provider,
1949
+ {
1950
+ value: {
1951
+ copilotkit,
1952
+ executingToolCallIds
1953
+ },
1954
+ children: [
1955
+ children,
1956
+ shouldRenderInspector ? /* @__PURE__ */ jsx9(CopilotKitInspector, { core: copilotkit }) : null
1957
+ ]
1958
+ }
1959
+ );
1960
+ };
1961
+ var useCopilotKit = () => {
1962
+ const context = useContext2(CopilotKitContext);
1963
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
1964
+ if (!context) {
1965
+ throw new Error("useCopilotKit must be used within CopilotKitProvider");
1966
+ }
1967
+ useEffect5(() => {
1968
+ const subscription = context.copilotkit.subscribe({
1969
+ onRuntimeConnectionStatusChanged: () => {
1970
+ forceUpdate();
1971
+ }
1972
+ });
1973
+ return () => {
1974
+ subscription.unsubscribe();
1975
+ };
1976
+ }, []);
1977
+ return context;
1978
+ };
1979
+
1980
+ // src/hooks/use-render-tool-call.tsx
1981
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID2 } from "@copilotkitnext/shared";
1982
+ import { partialJSONParse } from "@copilotkitnext/shared";
1983
+ import { jsx as jsx10 } from "react/jsx-runtime";
1984
+ var ToolCallRenderer = React7.memo(
1985
+ function ToolCallRenderer2({
1986
+ toolCall,
1987
+ toolMessage,
1988
+ RenderComponent,
1989
+ isExecuting
1990
+ }) {
1991
+ const args = useMemo4(
1992
+ () => partialJSONParse(toolCall.function.arguments),
1993
+ [toolCall.function.arguments]
1994
+ );
1995
+ const toolName = toolCall.function.name;
1996
+ if (toolMessage) {
1997
+ return /* @__PURE__ */ jsx10(
1998
+ RenderComponent,
1999
+ {
2000
+ name: toolName,
2001
+ args,
2002
+ status: ToolCallStatus.Complete,
2003
+ result: toolMessage.content
2004
+ }
2005
+ );
2006
+ } else if (isExecuting) {
2007
+ return /* @__PURE__ */ jsx10(
2008
+ RenderComponent,
2009
+ {
2010
+ name: toolName,
2011
+ args,
2012
+ status: ToolCallStatus.Executing,
2013
+ result: void 0
2014
+ }
2015
+ );
2016
+ } else {
2017
+ return /* @__PURE__ */ jsx10(
2018
+ RenderComponent,
2019
+ {
2020
+ name: toolName,
2021
+ args,
2022
+ status: ToolCallStatus.InProgress,
2023
+ result: void 0
2024
+ }
2025
+ );
2026
+ }
2027
+ },
2028
+ // Custom comparison function to prevent re-renders when tool call data hasn't changed
2029
+ (prevProps, nextProps) => {
2030
+ if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
2031
+ if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
2032
+ if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
2033
+ const prevResult = prevProps.toolMessage?.content;
2034
+ const nextResult = nextProps.toolMessage?.content;
2035
+ if (prevResult !== nextResult) return false;
2036
+ if (prevProps.isExecuting !== nextProps.isExecuting) return false;
2037
+ if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
2038
+ return true;
2039
+ }
2040
+ );
2041
+ function useRenderToolCall() {
2042
+ const { copilotkit, executingToolCallIds } = useCopilotKit();
2043
+ const config = useCopilotChatConfiguration();
2044
+ const agentId = config?.agentId ?? DEFAULT_AGENT_ID2;
2045
+ const renderToolCalls = useSyncExternalStore(
2046
+ (callback) => {
2047
+ return copilotkit.subscribe({
2048
+ onRenderToolCallsChanged: callback
2049
+ }).unsubscribe;
2050
+ },
2051
+ () => copilotkit.renderToolCalls,
2052
+ () => copilotkit.renderToolCalls
2053
+ );
2054
+ const renderToolCall = useCallback3(
2055
+ ({
2056
+ toolCall,
2057
+ toolMessage
2058
+ }) => {
2059
+ const exactMatches = renderToolCalls.filter(
2060
+ (rc) => rc.name === toolCall.function.name
2061
+ );
2062
+ const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
2063
+ if (!renderConfig) {
2064
+ return null;
2065
+ }
2066
+ const RenderComponent = renderConfig.render;
2067
+ const isExecuting = executingToolCallIds.has(toolCall.id);
2068
+ return /* @__PURE__ */ jsx10(
2069
+ ToolCallRenderer,
2070
+ {
2071
+ toolCall,
2072
+ toolMessage,
2073
+ RenderComponent,
2074
+ isExecuting
2075
+ },
2076
+ toolCall.id
2077
+ );
2078
+ },
2079
+ [renderToolCalls, executingToolCallIds, agentId]
2080
+ );
2081
+ return renderToolCall;
2082
+ }
2083
+
2084
+ // src/hooks/use-render-custom-messages.tsx
2085
+ import { jsx as jsx11 } from "react/jsx-runtime";
2086
+ function useRenderCustomMessages() {
2087
+ const { copilotkit } = useCopilotKit();
2088
+ const config = useCopilotChatConfiguration();
2089
+ if (!config) {
2090
+ return null;
2091
+ }
2092
+ const { agentId, threadId } = config;
2093
+ const customMessageRenderers = copilotkit.renderCustomMessages.filter((renderer) => renderer.agentId === void 0 || renderer.agentId === agentId).sort((a, b) => {
2094
+ const aHasAgent = a.agentId !== void 0;
2095
+ const bHasAgent = b.agentId !== void 0;
2096
+ if (aHasAgent === bHasAgent) return 0;
2097
+ return aHasAgent ? -1 : 1;
2098
+ });
2099
+ return function(params) {
2100
+ if (!customMessageRenderers.length) {
2101
+ return null;
2102
+ }
2103
+ const { message, position } = params;
2104
+ const runId = copilotkit.getRunIdForMessage(agentId, threadId, message.id);
2105
+ const agent = copilotkit.getAgent(agentId);
2106
+ if (!agent) {
2107
+ throw new Error("Agent not found");
2108
+ }
2109
+ const messagesIdsInRun = agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === runId).map((msg) => msg.id);
2110
+ const messageIndex = agent.messages.findIndex((msg) => msg.id === message.id) ?? 0;
2111
+ const messageIndexInRun = Math.min(messagesIdsInRun.indexOf(message.id), 0);
2112
+ const numberOfMessagesInRun = messagesIdsInRun.length;
2113
+ const stateSnapshot = copilotkit.getStateByRun(agentId, threadId, runId);
2114
+ let result = null;
2115
+ for (const renderer of customMessageRenderers) {
2116
+ if (!renderer.render) {
2117
+ continue;
2118
+ }
2119
+ const Component = renderer.render;
2120
+ result = /* @__PURE__ */ jsx11(
2121
+ Component,
2122
+ {
2123
+ message,
2124
+ position,
2125
+ runId,
2126
+ messageIndex,
2127
+ messageIndexInRun,
2128
+ numberOfMessagesInRun,
2129
+ agentId,
2130
+ stateSnapshot
2131
+ },
2132
+ `${runId}-${message.id}-${position}`
2133
+ );
2134
+ if (result) {
2135
+ break;
2136
+ }
2137
+ }
2138
+ return result;
2139
+ };
2140
+ }
2141
+
2142
+ // src/hooks/use-render-activity-message.tsx
2143
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID3 } from "@copilotkitnext/shared";
2144
+ import { useCallback as useCallback4 } from "react";
2145
+ import { jsx as jsx12 } from "react/jsx-runtime";
2146
+ function useRenderActivityMessage() {
2147
+ const { copilotkit } = useCopilotKit();
2148
+ const config = useCopilotChatConfiguration();
2149
+ const agentId = config?.agentId ?? DEFAULT_AGENT_ID3;
2150
+ const renderers = copilotkit.renderActivityMessages;
2151
+ return useCallback4(
2152
+ (message) => {
2153
+ if (!renderers.length) {
2154
+ return null;
2155
+ }
2156
+ const matches = renderers.filter(
2157
+ (renderer2) => renderer2.activityType === message.activityType
2158
+ );
2159
+ const renderer = matches.find((candidate) => candidate.agentId === agentId) ?? matches.find((candidate) => candidate.agentId === void 0) ?? renderers.find((candidate) => candidate.activityType === "*");
2160
+ if (!renderer) {
2161
+ return null;
2162
+ }
2163
+ const parseResult = renderer.content.safeParse(message.content);
2164
+ if (!parseResult.success) {
2165
+ console.warn(
2166
+ `Failed to parse content for activity message '${message.activityType}':`,
2167
+ parseResult.error
2168
+ );
2169
+ return null;
2170
+ }
2171
+ const Component = renderer.render;
2172
+ const agent = copilotkit.getAgent(agentId);
2173
+ return /* @__PURE__ */ jsx12(
2174
+ Component,
2175
+ {
2176
+ activityType: message.activityType,
2177
+ content: parseResult.data,
2178
+ message,
2179
+ agent
2180
+ },
2181
+ message.id
2182
+ );
2183
+ },
2184
+ [agentId, copilotkit, renderers]
2185
+ );
2186
+ }
2187
+
2188
+ // src/hooks/use-frontend-tool.tsx
2189
+ import { useEffect as useEffect6 } from "react";
2190
+ var EMPTY_DEPS = [];
2191
+ function useFrontendTool(tool, deps) {
2192
+ const { copilotkit } = useCopilotKit();
2193
+ const extraDeps = deps ?? EMPTY_DEPS;
2194
+ useEffect6(() => {
2195
+ const name = tool.name;
2196
+ if (copilotkit.getTool({ toolName: name, agentId: tool.agentId })) {
2197
+ console.warn(
2198
+ `Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`
2199
+ );
2200
+ copilotkit.removeTool(name, tool.agentId);
2201
+ }
2202
+ copilotkit.addTool(tool);
2203
+ if (tool.render) {
2204
+ const keyOf = (rc) => `${rc.agentId ?? ""}:${rc.name}`;
2205
+ const currentRenderToolCalls = copilotkit.renderToolCalls;
2206
+ const mergedMap = /* @__PURE__ */ new Map();
2207
+ for (const rc of currentRenderToolCalls) {
2208
+ mergedMap.set(keyOf(rc), rc);
2209
+ }
2210
+ const newEntry = {
2211
+ name,
2212
+ args: tool.parameters,
2213
+ agentId: tool.agentId,
2214
+ render: tool.render
2215
+ };
2216
+ mergedMap.set(keyOf(newEntry), newEntry);
2217
+ copilotkit.setRenderToolCalls(Array.from(mergedMap.values()));
2218
+ }
2219
+ return () => {
2220
+ copilotkit.removeTool(name, tool.agentId);
2221
+ };
2222
+ }, [tool.name, copilotkit, extraDeps.length, ...extraDeps]);
2223
+ }
2224
+
2225
+ // src/hooks/use-human-in-the-loop.tsx
2226
+ import { useCallback as useCallback5, useRef as useRef5, useEffect as useEffect7 } from "react";
2227
+ import React8 from "react";
2228
+ function useHumanInTheLoop(tool, deps) {
2229
+ const { copilotkit } = useCopilotKit();
2230
+ const resolvePromiseRef = useRef5(null);
2231
+ const respond = useCallback5(async (result) => {
2232
+ if (resolvePromiseRef.current) {
2233
+ resolvePromiseRef.current(result);
2234
+ resolvePromiseRef.current = null;
2235
+ }
2236
+ }, []);
2237
+ const handler = useCallback5(async () => {
2238
+ return new Promise((resolve) => {
2239
+ resolvePromiseRef.current = resolve;
2240
+ });
2241
+ }, []);
2242
+ const RenderComponent = useCallback5(
2243
+ (props) => {
2244
+ const ToolComponent = tool.render;
2245
+ if (props.status === "inProgress") {
2246
+ const enhancedProps = {
2247
+ ...props,
2248
+ name: tool.name,
2249
+ description: tool.description || "",
2250
+ respond: void 0
2251
+ };
2252
+ return React8.createElement(ToolComponent, enhancedProps);
2253
+ } else if (props.status === "executing") {
2254
+ const enhancedProps = {
2255
+ ...props,
2256
+ name: tool.name,
2257
+ description: tool.description || "",
2258
+ respond
2259
+ };
2260
+ return React8.createElement(ToolComponent, enhancedProps);
2261
+ } else if (props.status === "complete") {
2262
+ const enhancedProps = {
2263
+ ...props,
2264
+ name: tool.name,
2265
+ description: tool.description || "",
2266
+ respond: void 0
2267
+ };
2268
+ return React8.createElement(ToolComponent, enhancedProps);
2269
+ }
2270
+ return React8.createElement(ToolComponent, props);
2271
+ },
2272
+ [tool.render, tool.name, tool.description, respond]
2273
+ );
2274
+ const frontendTool = {
2275
+ ...tool,
2276
+ handler,
2277
+ render: RenderComponent
2278
+ };
2279
+ useFrontendTool(frontendTool, deps);
2280
+ useEffect7(() => {
2281
+ return () => {
2282
+ const keyOf = (rc) => `${rc.agentId ?? ""}:${rc.name}`;
2283
+ const currentRenderToolCalls = copilotkit.renderToolCalls;
2284
+ const filtered = currentRenderToolCalls.filter(
2285
+ (rc) => keyOf(rc) !== keyOf({ name: tool.name, agentId: tool.agentId })
2286
+ );
2287
+ copilotkit.setRenderToolCalls(filtered);
2288
+ };
2289
+ }, [copilotkit, tool.name, tool.agentId]);
2290
+ }
2291
+
2292
+ // src/hooks/use-agent.tsx
2293
+ import { useMemo as useMemo5, useEffect as useEffect8, useReducer as useReducer2 } from "react";
2294
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID4 } from "@copilotkitnext/shared";
2295
+ import { ProxiedCopilotRuntimeAgent, CopilotKitCoreRuntimeConnectionStatus } from "@copilotkitnext/core";
2296
+ var UseAgentUpdate = /* @__PURE__ */ ((UseAgentUpdate2) => {
2297
+ UseAgentUpdate2["OnMessagesChanged"] = "OnMessagesChanged";
2298
+ UseAgentUpdate2["OnStateChanged"] = "OnStateChanged";
2299
+ UseAgentUpdate2["OnRunStatusChanged"] = "OnRunStatusChanged";
2300
+ return UseAgentUpdate2;
2301
+ })(UseAgentUpdate || {});
2302
+ var ALL_UPDATES = [
2303
+ "OnMessagesChanged" /* OnMessagesChanged */,
2304
+ "OnStateChanged" /* OnStateChanged */,
2305
+ "OnRunStatusChanged" /* OnRunStatusChanged */
2306
+ ];
2307
+ function useAgent({ agentId, updates } = {}) {
2308
+ agentId ??= DEFAULT_AGENT_ID4;
2309
+ const { copilotkit } = useCopilotKit();
2310
+ const [, forceUpdate] = useReducer2((x) => x + 1, 0);
2311
+ const updateFlags = useMemo5(
2312
+ () => updates ?? ALL_UPDATES,
2313
+ [JSON.stringify(updates)]
2314
+ );
2315
+ const agent = useMemo5(() => {
2316
+ const existing = copilotkit.getAgent(agentId);
2317
+ if (existing) {
2318
+ return existing;
2319
+ }
2320
+ const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
2321
+ const status = copilotkit.runtimeConnectionStatus;
2322
+ if (isRuntimeConfigured && (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
2323
+ const provisional = new ProxiedCopilotRuntimeAgent({
2324
+ runtimeUrl: copilotkit.runtimeUrl,
2325
+ agentId,
2326
+ transport: copilotkit.runtimeTransport
2327
+ });
2328
+ provisional.headers = { ...copilotkit.headers };
2329
+ return provisional;
2330
+ }
2331
+ const knownAgents = Object.keys(copilotkit.agents ?? {});
2332
+ const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
2333
+ throw new Error(
2334
+ `useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only."
2335
+ );
2336
+ }, [
2337
+ agentId,
2338
+ copilotkit.agents,
2339
+ copilotkit.runtimeConnectionStatus,
2340
+ copilotkit.runtimeUrl,
2341
+ copilotkit.runtimeTransport,
2342
+ JSON.stringify(copilotkit.headers),
2343
+ copilotkit
2344
+ ]);
2345
+ useEffect8(() => {
2346
+ if (updateFlags.length === 0) {
2347
+ return;
2348
+ }
2349
+ const handlers = {};
2350
+ if (updateFlags.includes("OnMessagesChanged" /* OnMessagesChanged */)) {
2351
+ handlers.onMessagesChanged = () => {
2352
+ forceUpdate();
2353
+ };
2354
+ }
2355
+ if (updateFlags.includes("OnStateChanged" /* OnStateChanged */)) {
2356
+ handlers.onStateChanged = () => {
2357
+ forceUpdate();
2358
+ };
2359
+ }
2360
+ if (updateFlags.includes("OnRunStatusChanged" /* OnRunStatusChanged */)) {
2361
+ handlers.onRunInitialized = () => {
2362
+ forceUpdate();
2363
+ };
2364
+ handlers.onRunFinalized = () => {
2365
+ forceUpdate();
2366
+ };
2367
+ handlers.onRunFailed = () => {
2368
+ forceUpdate();
2369
+ };
2370
+ }
2371
+ const subscription = agent.subscribe(handlers);
2372
+ return () => subscription.unsubscribe();
2373
+ }, [agent, forceUpdate, JSON.stringify(updateFlags)]);
2374
+ return {
2375
+ agent
2376
+ };
2377
+ }
2378
+
2379
+ // src/hooks/use-agent-context.tsx
2380
+ import { useEffect as useEffect9, useMemo as useMemo6 } from "react";
2381
+ function useAgentContext(context) {
2382
+ const { description, value } = context;
2383
+ const { copilotkit } = useCopilotKit();
2384
+ const stringValue = useMemo6(() => {
2385
+ if (typeof value === "string") {
2386
+ return value;
2387
+ }
2388
+ return JSON.stringify(value);
2389
+ }, [value]);
2390
+ useEffect9(() => {
2391
+ if (!copilotkit) return;
2392
+ const id = copilotkit.addContext({ description, value: stringValue });
2393
+ return () => {
2394
+ copilotkit.removeContext(id);
2395
+ };
2396
+ }, [description, stringValue, copilotkit]);
2397
+ }
2398
+
2399
+ // src/hooks/use-suggestions.tsx
2400
+ import { useCallback as useCallback6, useEffect as useEffect10, useMemo as useMemo7, useState as useState6 } from "react";
2401
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID5 } from "@copilotkitnext/shared";
2402
+ function useSuggestions({ agentId } = {}) {
2403
+ const { copilotkit } = useCopilotKit();
2404
+ const config = useCopilotChatConfiguration();
2405
+ const resolvedAgentId = useMemo7(() => agentId ?? config?.agentId ?? DEFAULT_AGENT_ID5, [agentId, config?.agentId]);
2406
+ const [suggestions, setSuggestions] = useState6(() => {
2407
+ const result = copilotkit.getSuggestions(resolvedAgentId);
2408
+ return result.suggestions;
2409
+ });
2410
+ const [isLoading, setIsLoading] = useState6(() => {
2411
+ const result = copilotkit.getSuggestions(resolvedAgentId);
2412
+ return result.isLoading;
2413
+ });
2414
+ useEffect10(() => {
2415
+ const result = copilotkit.getSuggestions(resolvedAgentId);
2416
+ setSuggestions(result.suggestions);
2417
+ setIsLoading(result.isLoading);
2418
+ }, [copilotkit, resolvedAgentId]);
2419
+ useEffect10(() => {
2420
+ const subscription = copilotkit.subscribe({
2421
+ onSuggestionsChanged: ({ agentId: changedAgentId, suggestions: suggestions2 }) => {
2422
+ if (changedAgentId !== resolvedAgentId) {
2423
+ return;
2424
+ }
2425
+ setSuggestions(suggestions2);
2426
+ },
2427
+ onSuggestionsStartedLoading: ({ agentId: changedAgentId }) => {
2428
+ if (changedAgentId !== resolvedAgentId) {
2429
+ return;
2430
+ }
2431
+ setIsLoading(true);
2432
+ },
2433
+ onSuggestionsFinishedLoading: ({ agentId: changedAgentId }) => {
2434
+ if (changedAgentId !== resolvedAgentId) {
2435
+ return;
2436
+ }
2437
+ setIsLoading(false);
2438
+ },
2439
+ onSuggestionsConfigChanged: () => {
2440
+ const result = copilotkit.getSuggestions(resolvedAgentId);
2441
+ setSuggestions(result.suggestions);
2442
+ setIsLoading(result.isLoading);
2443
+ }
2444
+ });
2445
+ return () => {
2446
+ subscription.unsubscribe();
2447
+ };
2448
+ }, [copilotkit, resolvedAgentId]);
2449
+ const reloadSuggestions = useCallback6(() => {
2450
+ copilotkit.reloadSuggestions(resolvedAgentId);
2451
+ }, [copilotkit, resolvedAgentId]);
2452
+ const clearSuggestions = useCallback6(() => {
2453
+ copilotkit.clearSuggestions(resolvedAgentId);
2454
+ }, [copilotkit, resolvedAgentId]);
2455
+ return {
2456
+ suggestions,
2457
+ reloadSuggestions,
2458
+ clearSuggestions,
2459
+ isLoading
2460
+ };
2461
+ }
2462
+
2463
+ // src/hooks/use-configure-suggestions.tsx
2464
+ import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo8, useRef as useRef6 } from "react";
2465
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID6 } from "@copilotkitnext/shared";
2466
+ function useConfigureSuggestions(config, deps) {
2467
+ const { copilotkit } = useCopilotKit();
2468
+ const chatConfig = useCopilotChatConfiguration();
2469
+ const extraDeps = deps ?? [];
2470
+ const resolvedConsumerAgentId = useMemo8(() => chatConfig?.agentId ?? DEFAULT_AGENT_ID6, [chatConfig?.agentId]);
2471
+ const rawConsumerAgentId = useMemo8(() => config ? config.consumerAgentId : void 0, [config]);
2472
+ const normalizationCacheRef = useRef6({
2473
+ serialized: null,
2474
+ config: null
2475
+ });
2476
+ const { normalizedConfig, serializedConfig } = useMemo8(() => {
2477
+ if (!config) {
2478
+ normalizationCacheRef.current = { serialized: null, config: null };
2479
+ return { normalizedConfig: null, serializedConfig: null };
2480
+ }
2481
+ if (config.available === "disabled") {
2482
+ normalizationCacheRef.current = { serialized: null, config: null };
2483
+ return { normalizedConfig: null, serializedConfig: null };
2484
+ }
2485
+ let built;
2486
+ if (isDynamicConfig(config)) {
2487
+ built = {
2488
+ ...config
2489
+ };
2490
+ } else {
2491
+ const normalizedSuggestions = normalizeStaticSuggestions(config.suggestions);
2492
+ const baseConfig = {
2493
+ ...config,
2494
+ suggestions: normalizedSuggestions
2495
+ };
2496
+ built = baseConfig;
2497
+ }
2498
+ const serialized = JSON.stringify(built);
2499
+ const cache = normalizationCacheRef.current;
2500
+ if (cache.serialized === serialized && cache.config) {
2501
+ return { normalizedConfig: cache.config, serializedConfig: serialized };
2502
+ }
2503
+ normalizationCacheRef.current = { serialized, config: built };
2504
+ return { normalizedConfig: built, serializedConfig: serialized };
2505
+ }, [config, resolvedConsumerAgentId, ...extraDeps]);
2506
+ const latestConfigRef = useRef6(null);
2507
+ latestConfigRef.current = normalizedConfig;
2508
+ const previousSerializedConfigRef = useRef6(null);
2509
+ const targetAgentId = useMemo8(() => {
2510
+ if (!normalizedConfig) {
2511
+ return resolvedConsumerAgentId;
2512
+ }
2513
+ const consumer = normalizedConfig.consumerAgentId;
2514
+ if (!consumer || consumer === "*") {
2515
+ return resolvedConsumerAgentId;
2516
+ }
2517
+ return consumer;
2518
+ }, [normalizedConfig, resolvedConsumerAgentId]);
2519
+ const isGlobalConfig = rawConsumerAgentId === void 0 || rawConsumerAgentId === "*";
2520
+ const requestReload = useCallback7(() => {
2521
+ if (!normalizedConfig) {
2522
+ return;
2523
+ }
2524
+ if (isGlobalConfig) {
2525
+ const agents = Object.values(copilotkit.agents ?? {});
2526
+ for (const entry of agents) {
2527
+ const agentId = entry.agentId;
2528
+ if (!agentId) {
2529
+ continue;
2530
+ }
2531
+ if (!entry.isRunning) {
2532
+ copilotkit.reloadSuggestions(agentId);
2533
+ }
2534
+ }
2535
+ return;
2536
+ }
2537
+ if (!targetAgentId) {
2538
+ return;
2539
+ }
2540
+ copilotkit.reloadSuggestions(targetAgentId);
2541
+ }, [copilotkit, isGlobalConfig, normalizedConfig, targetAgentId]);
2542
+ useEffect11(() => {
2543
+ if (!serializedConfig || !latestConfigRef.current) {
2544
+ return;
2545
+ }
2546
+ const id = copilotkit.addSuggestionsConfig(latestConfigRef.current);
2547
+ requestReload();
2548
+ return () => {
2549
+ copilotkit.removeSuggestionsConfig(id);
2550
+ };
2551
+ }, [copilotkit, serializedConfig, requestReload]);
2552
+ useEffect11(() => {
2553
+ if (!normalizedConfig) {
2554
+ previousSerializedConfigRef.current = null;
2555
+ return;
2556
+ }
2557
+ if (serializedConfig && previousSerializedConfigRef.current === serializedConfig) {
2558
+ return;
2559
+ }
2560
+ if (serializedConfig) {
2561
+ previousSerializedConfigRef.current = serializedConfig;
2562
+ }
2563
+ requestReload();
2564
+ }, [normalizedConfig, requestReload, serializedConfig]);
2565
+ useEffect11(() => {
2566
+ if (!normalizedConfig || extraDeps.length === 0) {
2567
+ return;
2568
+ }
2569
+ requestReload();
2570
+ }, [extraDeps.length, normalizedConfig, requestReload, ...extraDeps]);
2571
+ }
2572
+ function isDynamicConfig(config) {
2573
+ return "instructions" in config;
2574
+ }
2575
+ function normalizeStaticSuggestions(suggestions) {
2576
+ return suggestions.map((suggestion) => ({
2577
+ ...suggestion,
2578
+ isLoading: suggestion.isLoading ?? false
2579
+ }));
2580
+ }
2581
+
2582
+ // src/components/chat/CopilotChatToolCallsView.tsx
2583
+ import React9 from "react";
2584
+ import { Fragment as Fragment2, jsx as jsx13 } from "react/jsx-runtime";
2585
+ function CopilotChatToolCallsView({
2586
+ message,
2587
+ messages = []
2588
+ }) {
2589
+ const renderToolCall = useRenderToolCall();
2590
+ if (!message.toolCalls || message.toolCalls.length === 0) {
2591
+ return null;
2592
+ }
2593
+ return /* @__PURE__ */ jsx13(Fragment2, { children: message.toolCalls.map((toolCall) => {
2594
+ const toolMessage = messages.find(
2595
+ (m) => m.role === "tool" && m.toolCallId === toolCall.id
2596
+ );
2597
+ return /* @__PURE__ */ jsx13(React9.Fragment, { children: renderToolCall({
2598
+ toolCall,
2599
+ toolMessage
2600
+ }) }, toolCall.id);
2601
+ }) });
2602
+ }
2603
+ var CopilotChatToolCallsView_default = CopilotChatToolCallsView;
2604
+
2605
+ // src/components/chat/CopilotChatAssistantMessage.tsx
2606
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
2607
+ function CopilotChatAssistantMessage({
2608
+ message,
2609
+ messages,
2610
+ isRunning,
2611
+ onThumbsUp,
2612
+ onThumbsDown,
2613
+ onReadAloud,
2614
+ onRegenerate,
2615
+ additionalToolbarItems,
2616
+ toolbarVisible = true,
2617
+ markdownRenderer,
2618
+ toolbar,
2619
+ copyButton,
2620
+ thumbsUpButton,
2621
+ thumbsDownButton,
2622
+ readAloudButton,
2623
+ regenerateButton,
2624
+ toolCallsView,
2625
+ children,
2626
+ className,
2627
+ ...props
2628
+ }) {
2629
+ const boundMarkdownRenderer = renderSlot(
2630
+ markdownRenderer,
2631
+ CopilotChatAssistantMessage.MarkdownRenderer,
2632
+ {
2633
+ content: message.content || ""
2634
+ }
2635
+ );
2636
+ const boundCopyButton = renderSlot(
2637
+ copyButton,
2638
+ CopilotChatAssistantMessage.CopyButton,
2639
+ {
2640
+ onClick: async () => {
2641
+ if (message.content) {
2642
+ try {
2643
+ await navigator.clipboard.writeText(message.content);
2644
+ } catch (err) {
2645
+ console.error("Failed to copy message:", err);
2646
+ }
2647
+ }
2648
+ }
2649
+ }
2650
+ );
2651
+ const boundThumbsUpButton = renderSlot(
2652
+ thumbsUpButton,
2653
+ CopilotChatAssistantMessage.ThumbsUpButton,
2654
+ {
2655
+ onClick: onThumbsUp
2656
+ }
2657
+ );
2658
+ const boundThumbsDownButton = renderSlot(
2659
+ thumbsDownButton,
2660
+ CopilotChatAssistantMessage.ThumbsDownButton,
2661
+ {
2662
+ onClick: onThumbsDown
2663
+ }
2664
+ );
2665
+ const boundReadAloudButton = renderSlot(
2666
+ readAloudButton,
2667
+ CopilotChatAssistantMessage.ReadAloudButton,
2668
+ {
2669
+ onClick: onReadAloud
2670
+ }
2671
+ );
2672
+ const boundRegenerateButton = renderSlot(
2673
+ regenerateButton,
2674
+ CopilotChatAssistantMessage.RegenerateButton,
2675
+ {
2676
+ onClick: onRegenerate
2677
+ }
2678
+ );
2679
+ const boundToolbar = renderSlot(
2680
+ toolbar,
2681
+ CopilotChatAssistantMessage.Toolbar,
2682
+ {
2683
+ children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1", children: [
2684
+ boundCopyButton,
2685
+ (onThumbsUp || thumbsUpButton) && boundThumbsUpButton,
2686
+ (onThumbsDown || thumbsDownButton) && boundThumbsDownButton,
2687
+ (onReadAloud || readAloudButton) && boundReadAloudButton,
2688
+ (onRegenerate || regenerateButton) && boundRegenerateButton,
2689
+ additionalToolbarItems
2690
+ ] })
2691
+ }
2692
+ );
2693
+ const boundToolCallsView = renderSlot(
2694
+ toolCallsView,
2695
+ CopilotChatToolCallsView_default,
2696
+ {
2697
+ message,
2698
+ messages
2699
+ }
2700
+ );
2701
+ const hasContent = !!(message.content && message.content.trim().length > 0);
2702
+ const isLatestAssistantMessage = message.role === "assistant" && messages?.[messages.length - 1]?.id === message.id;
2703
+ const shouldShowToolbar = toolbarVisible && hasContent && !(isRunning && isLatestAssistantMessage);
2704
+ if (children) {
2705
+ return /* @__PURE__ */ jsx14(Fragment3, { children: children({
2706
+ markdownRenderer: boundMarkdownRenderer,
2707
+ toolbar: boundToolbar,
2708
+ toolCallsView: boundToolCallsView,
2709
+ copyButton: boundCopyButton,
2710
+ thumbsUpButton: boundThumbsUpButton,
2711
+ thumbsDownButton: boundThumbsDownButton,
2712
+ readAloudButton: boundReadAloudButton,
2713
+ regenerateButton: boundRegenerateButton,
2714
+ message,
2715
+ messages,
2716
+ isRunning,
2717
+ onThumbsUp,
2718
+ onThumbsDown,
2719
+ onReadAloud,
2720
+ onRegenerate,
2721
+ additionalToolbarItems,
2722
+ toolbarVisible: shouldShowToolbar
2723
+ }) });
2724
+ }
2725
+ return /* @__PURE__ */ jsxs6(
2726
+ "div",
2727
+ {
2728
+ className: twMerge4(
2729
+ "prose max-w-full break-words dark:prose-invert",
2730
+ className
2731
+ ),
2732
+ ...props,
2733
+ "data-message-id": message.id,
2734
+ children: [
2735
+ boundMarkdownRenderer,
2736
+ boundToolCallsView,
2737
+ shouldShowToolbar && boundToolbar
2738
+ ]
2739
+ }
2740
+ );
2741
+ }
2742
+ ((CopilotChatAssistantMessage2) => {
2743
+ CopilotChatAssistantMessage2.MarkdownRenderer = ({ content, className, ...props }) => /* @__PURE__ */ jsx14(Streamdown, { className, ...props, children: content ?? "" });
2744
+ CopilotChatAssistantMessage2.Toolbar = ({
2745
+ className,
2746
+ ...props
2747
+ }) => /* @__PURE__ */ jsx14(
2748
+ "div",
2749
+ {
2750
+ className: twMerge4(
2751
+ "w-full bg-transparent flex items-center -ml-[5px] -mt-[0px]",
2752
+ className
2753
+ ),
2754
+ ...props
2755
+ }
2756
+ );
2757
+ CopilotChatAssistantMessage2.ToolbarButton = ({ title, children, ...props }) => {
2758
+ return /* @__PURE__ */ jsxs6(Tooltip, { children: [
2759
+ /* @__PURE__ */ jsx14(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx14(
2760
+ Button,
2761
+ {
2762
+ type: "button",
2763
+ variant: "assistantMessageToolbarButton",
2764
+ "aria-label": title,
2765
+ ...props,
2766
+ children
2767
+ }
2768
+ ) }),
2769
+ /* @__PURE__ */ jsx14(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsx14("p", { children: title }) })
2770
+ ] });
2771
+ };
2772
+ CopilotChatAssistantMessage2.CopyButton = ({ className, title, onClick, ...props }) => {
2773
+ const config = useCopilotChatConfiguration();
2774
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
2775
+ const [copied, setCopied] = useState7(false);
2776
+ const handleClick = (event) => {
2777
+ setCopied(true);
2778
+ setTimeout(() => setCopied(false), 2e3);
2779
+ if (onClick) {
2780
+ onClick(event);
2781
+ }
2782
+ };
2783
+ return /* @__PURE__ */ jsx14(
2784
+ CopilotChatAssistantMessage2.ToolbarButton,
2785
+ {
2786
+ title: title || labels.assistantMessageToolbarCopyMessageLabel,
2787
+ onClick: handleClick,
2788
+ className,
2789
+ ...props,
2790
+ children: copied ? /* @__PURE__ */ jsx14(Check2, { className: "size-[18px]" }) : /* @__PURE__ */ jsx14(Copy, { className: "size-[18px]" })
2791
+ }
2792
+ );
2793
+ };
2794
+ CopilotChatAssistantMessage2.ThumbsUpButton = ({ title, ...props }) => {
2795
+ const config = useCopilotChatConfiguration();
2796
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
2797
+ return /* @__PURE__ */ jsx14(
2798
+ CopilotChatAssistantMessage2.ToolbarButton,
2799
+ {
2800
+ title: title || labels.assistantMessageToolbarThumbsUpLabel,
2801
+ ...props,
2802
+ children: /* @__PURE__ */ jsx14(ThumbsUp, { className: "size-[18px]" })
2803
+ }
2804
+ );
2805
+ };
2806
+ CopilotChatAssistantMessage2.ThumbsDownButton = ({ title, ...props }) => {
2807
+ const config = useCopilotChatConfiguration();
2808
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
2809
+ return /* @__PURE__ */ jsx14(
2810
+ CopilotChatAssistantMessage2.ToolbarButton,
2811
+ {
2812
+ title: title || labels.assistantMessageToolbarThumbsDownLabel,
2813
+ ...props,
2814
+ children: /* @__PURE__ */ jsx14(ThumbsDown, { className: "size-[18px]" })
2815
+ }
2816
+ );
2817
+ };
2818
+ CopilotChatAssistantMessage2.ReadAloudButton = ({ title, ...props }) => {
2819
+ const config = useCopilotChatConfiguration();
2820
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
2821
+ return /* @__PURE__ */ jsx14(
2822
+ CopilotChatAssistantMessage2.ToolbarButton,
2823
+ {
2824
+ title: title || labels.assistantMessageToolbarReadAloudLabel,
2825
+ ...props,
2826
+ children: /* @__PURE__ */ jsx14(Volume2, { className: "size-[20px]" })
2827
+ }
2828
+ );
2829
+ };
2830
+ CopilotChatAssistantMessage2.RegenerateButton = ({ title, ...props }) => {
2831
+ const config = useCopilotChatConfiguration();
2832
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
2833
+ return /* @__PURE__ */ jsx14(
2834
+ CopilotChatAssistantMessage2.ToolbarButton,
2835
+ {
2836
+ title: title || labels.assistantMessageToolbarRegenerateLabel,
2837
+ ...props,
2838
+ children: /* @__PURE__ */ jsx14(RefreshCw, { className: "size-[18px]" })
2839
+ }
2840
+ );
2841
+ };
2842
+ })(CopilotChatAssistantMessage || (CopilotChatAssistantMessage = {}));
2843
+ CopilotChatAssistantMessage.MarkdownRenderer.displayName = "CopilotChatAssistantMessage.MarkdownRenderer";
2844
+ CopilotChatAssistantMessage.Toolbar.displayName = "CopilotChatAssistantMessage.Toolbar";
2845
+ CopilotChatAssistantMessage.CopyButton.displayName = "CopilotChatAssistantMessage.CopyButton";
2846
+ CopilotChatAssistantMessage.ThumbsUpButton.displayName = "CopilotChatAssistantMessage.ThumbsUpButton";
2847
+ CopilotChatAssistantMessage.ThumbsDownButton.displayName = "CopilotChatAssistantMessage.ThumbsDownButton";
2848
+ CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantMessage.ReadAloudButton";
2849
+ CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
2850
+ var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
2851
+
2852
+ // src/components/chat/CopilotChatUserMessage.tsx
2853
+ import { useMemo as useMemo9, useState as useState8 } from "react";
2854
+ import { Copy as Copy2, Check as Check3, Edit, ChevronLeft, ChevronRight } from "lucide-react";
2855
+ import { twMerge as twMerge5 } from "tailwind-merge";
2856
+ import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
2857
+ function flattenUserMessageContent(content) {
2858
+ if (!content) {
2859
+ return "";
2860
+ }
2861
+ if (typeof content === "string") {
2862
+ return content;
2863
+ }
2864
+ return content.map((part) => {
2865
+ if (part && typeof part === "object" && "type" in part && part.type === "text" && typeof part.text === "string") {
2866
+ return part.text;
2867
+ }
2868
+ return "";
2869
+ }).filter((text) => text.length > 0).join("\n");
2870
+ }
2871
+ function CopilotChatUserMessage({
2872
+ message,
2873
+ onEditMessage,
2874
+ branchIndex,
2875
+ numberOfBranches,
2876
+ onSwitchToBranch,
2877
+ additionalToolbarItems,
2878
+ messageRenderer,
2879
+ toolbar,
2880
+ copyButton,
2881
+ editButton,
2882
+ branchNavigation,
2883
+ children,
2884
+ className,
2885
+ ...props
2886
+ }) {
2887
+ const flattenedContent = useMemo9(
2888
+ () => flattenUserMessageContent(message.content),
2889
+ [message.content]
2890
+ );
2891
+ const BoundMessageRenderer = renderSlot(
2892
+ messageRenderer,
2893
+ CopilotChatUserMessage.MessageRenderer,
2894
+ {
2895
+ content: flattenedContent
2896
+ }
2897
+ );
2898
+ const BoundCopyButton = renderSlot(
2899
+ copyButton,
2900
+ CopilotChatUserMessage.CopyButton,
2901
+ {
2902
+ onClick: async () => {
2903
+ if (flattenedContent) {
2904
+ try {
2905
+ await navigator.clipboard.writeText(flattenedContent);
2906
+ } catch (err) {
2907
+ console.error("Failed to copy message:", err);
2908
+ }
2909
+ }
2910
+ }
2911
+ }
2912
+ );
2913
+ const BoundEditButton = renderSlot(
2914
+ editButton,
2915
+ CopilotChatUserMessage.EditButton,
2916
+ {
2917
+ onClick: () => onEditMessage?.({ message })
2918
+ }
2919
+ );
2920
+ const BoundBranchNavigation = renderSlot(
2921
+ branchNavigation,
2922
+ CopilotChatUserMessage.BranchNavigation,
2923
+ {
2924
+ currentBranch: branchIndex,
2925
+ numberOfBranches,
2926
+ onSwitchToBranch,
2927
+ message
2928
+ }
2929
+ );
2930
+ const showBranchNavigation = numberOfBranches && numberOfBranches > 1 && onSwitchToBranch;
2931
+ const BoundToolbar = renderSlot(toolbar, CopilotChatUserMessage.Toolbar, {
2932
+ children: /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1 justify-end", children: [
2933
+ additionalToolbarItems,
2934
+ BoundCopyButton,
2935
+ onEditMessage && BoundEditButton,
2936
+ showBranchNavigation && BoundBranchNavigation
2937
+ ] })
2938
+ });
2939
+ if (children) {
2940
+ return /* @__PURE__ */ jsx15(Fragment4, { children: children({
2941
+ messageRenderer: BoundMessageRenderer,
2942
+ toolbar: BoundToolbar,
2943
+ copyButton: BoundCopyButton,
2944
+ editButton: BoundEditButton,
2945
+ branchNavigation: BoundBranchNavigation,
2946
+ message,
2947
+ branchIndex,
2948
+ numberOfBranches,
2949
+ additionalToolbarItems
2950
+ }) });
2951
+ }
2952
+ return /* @__PURE__ */ jsxs7(
2953
+ "div",
2954
+ {
2955
+ className: twMerge5("flex flex-col items-end group pt-10", className),
2956
+ "data-message-id": message.id,
2957
+ ...props,
2958
+ children: [
2959
+ BoundMessageRenderer,
2960
+ BoundToolbar
2961
+ ]
2962
+ }
2963
+ );
2964
+ }
2965
+ ((CopilotChatUserMessage2) => {
2966
+ CopilotChatUserMessage2.Container = ({ children, className, ...props }) => /* @__PURE__ */ jsx15(
2967
+ "div",
2968
+ {
2969
+ className: twMerge5("flex flex-col items-end group", className),
2970
+ ...props,
2971
+ children
2972
+ }
2973
+ );
2974
+ CopilotChatUserMessage2.MessageRenderer = ({ content, className }) => /* @__PURE__ */ jsx15(
2975
+ "div",
2976
+ {
2977
+ className: twMerge5(
2978
+ "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",
2979
+ className
2980
+ ),
2981
+ children: content
2982
+ }
2983
+ );
2984
+ CopilotChatUserMessage2.Toolbar = ({
2985
+ className,
2986
+ ...props
2987
+ }) => /* @__PURE__ */ jsx15(
2988
+ "div",
2989
+ {
2990
+ className: twMerge5(
2991
+ "w-full bg-transparent flex items-center justify-end -mr-[5px] mt-[4px] invisible group-hover:visible",
2992
+ className
2993
+ ),
2994
+ ...props
2995
+ }
2996
+ );
2997
+ CopilotChatUserMessage2.ToolbarButton = ({ title, children, className, ...props }) => {
2998
+ return /* @__PURE__ */ jsxs7(Tooltip, { children: [
2999
+ /* @__PURE__ */ jsx15(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx15(
3000
+ Button,
3001
+ {
3002
+ type: "button",
3003
+ variant: "assistantMessageToolbarButton",
3004
+ "aria-label": title,
3005
+ className: twMerge5(className),
3006
+ ...props,
3007
+ children
3008
+ }
3009
+ ) }),
3010
+ /* @__PURE__ */ jsx15(TooltipContent, { side: "bottom", children: /* @__PURE__ */ jsx15("p", { children: title }) })
3011
+ ] });
3012
+ };
3013
+ CopilotChatUserMessage2.CopyButton = ({ className, title, onClick, ...props }) => {
3014
+ const config = useCopilotChatConfiguration();
3015
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
3016
+ const [copied, setCopied] = useState8(false);
3017
+ const handleClick = (event) => {
3018
+ setCopied(true);
3019
+ setTimeout(() => setCopied(false), 2e3);
3020
+ if (onClick) {
3021
+ onClick(event);
3022
+ }
3023
+ };
3024
+ return /* @__PURE__ */ jsx15(
3025
+ CopilotChatUserMessage2.ToolbarButton,
3026
+ {
3027
+ title: title || labels.userMessageToolbarCopyMessageLabel,
3028
+ onClick: handleClick,
3029
+ className,
3030
+ ...props,
3031
+ children: copied ? /* @__PURE__ */ jsx15(Check3, { className: "size-[18px]" }) : /* @__PURE__ */ jsx15(Copy2, { className: "size-[18px]" })
3032
+ }
3033
+ );
3034
+ };
3035
+ CopilotChatUserMessage2.EditButton = ({ className, title, ...props }) => {
3036
+ const config = useCopilotChatConfiguration();
3037
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
3038
+ return /* @__PURE__ */ jsx15(
3039
+ CopilotChatUserMessage2.ToolbarButton,
3040
+ {
3041
+ title: title || labels.userMessageToolbarEditMessageLabel,
3042
+ className,
3043
+ ...props,
3044
+ children: /* @__PURE__ */ jsx15(Edit, { className: "size-[18px]" })
3045
+ }
3046
+ );
3047
+ };
3048
+ CopilotChatUserMessage2.BranchNavigation = ({
3049
+ className,
3050
+ currentBranch = 0,
3051
+ numberOfBranches = 1,
3052
+ onSwitchToBranch,
3053
+ message,
3054
+ ...props
3055
+ }) => {
3056
+ if (!numberOfBranches || numberOfBranches <= 1 || !onSwitchToBranch) {
3057
+ return null;
3058
+ }
3059
+ const canGoPrev = currentBranch > 0;
3060
+ const canGoNext = currentBranch < numberOfBranches - 1;
3061
+ return /* @__PURE__ */ jsxs7("div", { className: twMerge5("flex items-center gap-1", className), ...props, children: [
3062
+ /* @__PURE__ */ jsx15(
3063
+ Button,
3064
+ {
3065
+ type: "button",
3066
+ variant: "assistantMessageToolbarButton",
3067
+ onClick: () => onSwitchToBranch?.({
3068
+ branchIndex: currentBranch - 1,
3069
+ numberOfBranches,
3070
+ message
3071
+ }),
3072
+ disabled: !canGoPrev,
3073
+ className: "h-6 w-6 p-0",
3074
+ children: /* @__PURE__ */ jsx15(ChevronLeft, { className: "size-[20px]" })
3075
+ }
3076
+ ),
3077
+ /* @__PURE__ */ jsxs7("span", { className: "text-sm text-muted-foreground px-0 font-medium", children: [
3078
+ currentBranch + 1,
3079
+ "/",
3080
+ numberOfBranches
3081
+ ] }),
3082
+ /* @__PURE__ */ jsx15(
3083
+ Button,
3084
+ {
3085
+ type: "button",
3086
+ variant: "assistantMessageToolbarButton",
3087
+ onClick: () => onSwitchToBranch?.({
3088
+ branchIndex: currentBranch + 1,
3089
+ numberOfBranches,
3090
+ message
3091
+ }),
3092
+ disabled: !canGoNext,
3093
+ className: "h-6 w-6 p-0",
3094
+ children: /* @__PURE__ */ jsx15(ChevronRight, { className: "size-[20px]" })
3095
+ }
3096
+ )
3097
+ ] });
3098
+ };
3099
+ })(CopilotChatUserMessage || (CopilotChatUserMessage = {}));
3100
+ CopilotChatUserMessage.Container.displayName = "CopilotChatUserMessage.Container";
3101
+ CopilotChatUserMessage.MessageRenderer.displayName = "CopilotChatUserMessage.MessageRenderer";
3102
+ CopilotChatUserMessage.Toolbar.displayName = "CopilotChatUserMessage.Toolbar";
3103
+ CopilotChatUserMessage.ToolbarButton.displayName = "CopilotChatUserMessage.ToolbarButton";
3104
+ CopilotChatUserMessage.CopyButton.displayName = "CopilotChatUserMessage.CopyButton";
3105
+ CopilotChatUserMessage.EditButton.displayName = "CopilotChatUserMessage.EditButton";
3106
+ CopilotChatUserMessage.BranchNavigation.displayName = "CopilotChatUserMessage.BranchNavigation";
3107
+ var CopilotChatUserMessage_default = CopilotChatUserMessage;
3108
+
3109
+ // src/components/chat/CopilotChatSuggestionPill.tsx
3110
+ import React10 from "react";
3111
+ import { Loader2 } from "lucide-react";
3112
+ import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
3113
+ var baseClasses = "group inline-flex h-7 sm:h-8 items-center gap-1 sm:gap-1.5 rounded-full border border-border/60 bg-background px-2.5 sm:px-3 text-[11px] sm:text-xs leading-none text-foreground transition-colors cursor-pointer hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:text-muted-foreground disabled:hover:bg-background disabled:hover:text-muted-foreground pointer-events-auto";
3114
+ var labelClasses = "whitespace-nowrap font-medium leading-none";
3115
+ var CopilotChatSuggestionPill = React10.forwardRef(function CopilotChatSuggestionPill2({ className, children, icon, isLoading, type, ...props }, ref) {
3116
+ const showIcon = !isLoading && icon;
3117
+ return /* @__PURE__ */ jsxs8(
3118
+ "button",
3119
+ {
3120
+ ref,
3121
+ "data-slot": "suggestion-pill",
3122
+ className: cn(baseClasses, className),
3123
+ type: type ?? "button",
3124
+ "aria-busy": isLoading || void 0,
3125
+ disabled: isLoading || props.disabled,
3126
+ ...props,
3127
+ children: [
3128
+ isLoading ? /* @__PURE__ */ jsx16("span", { className: "flex h-3.5 sm:h-4 w-3.5 sm:w-4 items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx16(Loader2, { className: "h-3.5 sm:h-4 w-3.5 sm:w-4 animate-spin", "aria-hidden": "true" }) }) : showIcon && /* @__PURE__ */ jsx16("span", { className: "flex h-3.5 sm:h-4 w-3.5 sm:w-4 items-center justify-center text-muted-foreground", children: icon }),
3129
+ /* @__PURE__ */ jsx16("span", { className: labelClasses, children })
3130
+ ]
3131
+ }
3132
+ );
3133
+ });
3134
+ CopilotChatSuggestionPill.displayName = "CopilotChatSuggestionPill";
3135
+ var CopilotChatSuggestionPill_default = CopilotChatSuggestionPill;
3136
+
3137
+ // src/components/chat/CopilotChatSuggestionView.tsx
3138
+ import React11 from "react";
3139
+ import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
3140
+ var DefaultContainer = React11.forwardRef(function DefaultContainer2({ className, ...props }, ref) {
3141
+ return /* @__PURE__ */ jsx17(
3142
+ "div",
3143
+ {
3144
+ ref,
3145
+ className: cn(
3146
+ "flex flex-wrap items-center gap-1.5 sm:gap-2 pl-0 pr-4 sm:px-0 pointer-events-none",
3147
+ className
3148
+ ),
3149
+ ...props
3150
+ }
3151
+ );
3152
+ });
3153
+ var CopilotChatSuggestionView = React11.forwardRef(function CopilotChatSuggestionView2({
3154
+ suggestions,
3155
+ onSelectSuggestion,
3156
+ loadingIndexes,
3157
+ container,
3158
+ suggestion: suggestionSlot,
3159
+ className,
3160
+ children,
3161
+ ...restProps
3162
+ }, ref) {
3163
+ const loadingSet = React11.useMemo(() => {
3164
+ if (!loadingIndexes || loadingIndexes.length === 0) {
3165
+ return /* @__PURE__ */ new Set();
3166
+ }
3167
+ return new Set(loadingIndexes);
3168
+ }, [loadingIndexes]);
3169
+ const ContainerElement = renderSlot(container, DefaultContainer, {
3170
+ ref,
3171
+ className,
3172
+ ...restProps
3173
+ });
3174
+ const suggestionElements = suggestions.map((suggestion, index) => {
3175
+ const isLoading = loadingSet.has(index) || suggestion.isLoading === true;
3176
+ const pill = renderSlot(suggestionSlot, CopilotChatSuggestionPill_default, {
3177
+ children: suggestion.title,
3178
+ isLoading,
3179
+ type: "button",
3180
+ onClick: () => onSelectSuggestion?.(suggestion, index)
3181
+ });
3182
+ return React11.cloneElement(pill, {
3183
+ key: `${suggestion.title}-${index}`
3184
+ });
3185
+ });
3186
+ const boundContainer = React11.cloneElement(
3187
+ ContainerElement,
3188
+ void 0,
3189
+ suggestionElements
3190
+ );
3191
+ if (typeof children === "function") {
3192
+ const sampleSuggestion = renderSlot(suggestionSlot, CopilotChatSuggestionPill_default, {
3193
+ children: suggestions[0]?.title ?? "",
3194
+ isLoading: suggestions.length > 0 ? loadingSet.has(0) || suggestions[0]?.isLoading === true : false,
3195
+ type: "button"
3196
+ });
3197
+ return /* @__PURE__ */ jsx17(Fragment5, { children: children({
3198
+ container: boundContainer,
3199
+ suggestion: sampleSuggestion,
3200
+ suggestions,
3201
+ onSelectSuggestion,
3202
+ loadingIndexes,
3203
+ className,
3204
+ ...restProps
3205
+ }) });
3206
+ }
3207
+ if (children) {
3208
+ return /* @__PURE__ */ jsxs9(Fragment5, { children: [
3209
+ boundContainer,
3210
+ children
3211
+ ] });
3212
+ }
3213
+ return boundContainer;
3214
+ });
3215
+ CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
3216
+ var CopilotChatSuggestionView_default = CopilotChatSuggestionView;
3217
+
3218
+ // src/components/chat/CopilotChatMessageView.tsx
3219
+ import React12, { useEffect as useEffect12, useReducer as useReducer3 } from "react";
3220
+ import { twMerge as twMerge6 } from "tailwind-merge";
3221
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
3222
+ var MemoizedAssistantMessage = React12.memo(
3223
+ function MemoizedAssistantMessage2({
3224
+ message,
3225
+ messages,
3226
+ isRunning,
3227
+ AssistantMessageComponent
3228
+ }) {
3229
+ return /* @__PURE__ */ jsx18(
3230
+ AssistantMessageComponent,
3231
+ {
3232
+ message,
3233
+ messages,
3234
+ isRunning
3235
+ }
3236
+ );
3237
+ },
3238
+ (prevProps, nextProps) => {
3239
+ if (prevProps.message.id !== nextProps.message.id) return false;
3240
+ if (prevProps.message.content !== nextProps.message.content) return false;
3241
+ const prevToolCalls = prevProps.message.toolCalls;
3242
+ const nextToolCalls = nextProps.message.toolCalls;
3243
+ if (prevToolCalls?.length !== nextToolCalls?.length) return false;
3244
+ if (prevToolCalls && nextToolCalls) {
3245
+ for (let i = 0; i < prevToolCalls.length; i++) {
3246
+ const prevTc = prevToolCalls[i];
3247
+ const nextTc = nextToolCalls[i];
3248
+ if (!prevTc || !nextTc) return false;
3249
+ if (prevTc.id !== nextTc.id) return false;
3250
+ if (prevTc.function.arguments !== nextTc.function.arguments) return false;
3251
+ }
3252
+ }
3253
+ if (prevToolCalls && prevToolCalls.length > 0) {
3254
+ const toolCallIds = new Set(prevToolCalls.map((tc) => tc.id));
3255
+ const prevToolResults = prevProps.messages.filter(
3256
+ (m) => m.role === "tool" && toolCallIds.has(m.toolCallId)
3257
+ );
3258
+ const nextToolResults = nextProps.messages.filter(
3259
+ (m) => m.role === "tool" && toolCallIds.has(m.toolCallId)
3260
+ );
3261
+ if (prevToolResults.length !== nextToolResults.length) return false;
3262
+ for (let i = 0; i < prevToolResults.length; i++) {
3263
+ if (prevToolResults[i].content !== nextToolResults[i].content) return false;
3264
+ }
3265
+ }
3266
+ const nextIsLatest = nextProps.messages[nextProps.messages.length - 1]?.id === nextProps.message.id;
3267
+ if (nextIsLatest && prevProps.isRunning !== nextProps.isRunning) return false;
3268
+ if (prevProps.AssistantMessageComponent !== nextProps.AssistantMessageComponent) return false;
3269
+ return true;
3270
+ }
3271
+ );
3272
+ var MemoizedUserMessage = React12.memo(
3273
+ function MemoizedUserMessage2({
3274
+ message,
3275
+ UserMessageComponent
3276
+ }) {
3277
+ return /* @__PURE__ */ jsx18(UserMessageComponent, { message });
3278
+ },
3279
+ (prevProps, nextProps) => {
3280
+ if (prevProps.message.id !== nextProps.message.id) return false;
3281
+ if (prevProps.message.content !== nextProps.message.content) return false;
3282
+ if (prevProps.UserMessageComponent !== nextProps.UserMessageComponent) return false;
3283
+ return true;
3284
+ }
3285
+ );
3286
+ var MemoizedActivityMessage = React12.memo(
3287
+ function MemoizedActivityMessage2({
3288
+ message,
3289
+ renderActivityMessage
3290
+ }) {
3291
+ return renderActivityMessage(message);
3292
+ },
3293
+ (prevProps, nextProps) => {
3294
+ if (prevProps.message.id !== nextProps.message.id) return false;
3295
+ if (prevProps.message.activityType !== nextProps.message.activityType) return false;
3296
+ if (JSON.stringify(prevProps.message.content) !== JSON.stringify(nextProps.message.content)) return false;
3297
+ return true;
3298
+ }
3299
+ );
3300
+ var MemoizedCustomMessage = React12.memo(
3301
+ function MemoizedCustomMessage2({
3302
+ message,
3303
+ position,
3304
+ renderCustomMessage
3305
+ }) {
3306
+ return renderCustomMessage({ message, position });
3307
+ },
3308
+ (prevProps, nextProps) => {
3309
+ if (prevProps.message.id !== nextProps.message.id) return false;
3310
+ if (prevProps.position !== nextProps.position) return false;
3311
+ if (prevProps.message.content !== nextProps.message.content) return false;
3312
+ if (prevProps.message.role !== nextProps.message.role) return false;
3313
+ if (JSON.stringify(prevProps.stateSnapshot) !== JSON.stringify(nextProps.stateSnapshot)) return false;
3314
+ return true;
3315
+ }
3316
+ );
3317
+ function CopilotChatMessageView({
3318
+ messages = [],
3319
+ assistantMessage,
3320
+ userMessage,
3321
+ cursor,
3322
+ isRunning = false,
3323
+ children,
3324
+ className,
3325
+ ...props
3326
+ }) {
3327
+ const renderCustomMessage = useRenderCustomMessages();
3328
+ const renderActivityMessage = useRenderActivityMessage();
3329
+ const { copilotkit } = useCopilotKit();
3330
+ const config = useCopilotChatConfiguration();
3331
+ const [, forceUpdate] = useReducer3((x) => x + 1, 0);
3332
+ useEffect12(() => {
3333
+ if (!config?.agentId) return;
3334
+ const agent = copilotkit.getAgent(config.agentId);
3335
+ if (!agent) return;
3336
+ const subscription = agent.subscribe({
3337
+ onStateChanged: () => forceUpdate()
3338
+ });
3339
+ return () => subscription.unsubscribe();
3340
+ }, [config?.agentId, copilotkit]);
3341
+ const getStateSnapshotForMessage = (messageId) => {
3342
+ if (!config) return void 0;
3343
+ const runId = copilotkit.getRunIdForMessage(config.agentId, config.threadId, messageId);
3344
+ if (!runId) return void 0;
3345
+ return copilotkit.getStateByRun(config.agentId, config.threadId, runId);
3346
+ };
3347
+ const messageElements = messages.flatMap((message) => {
3348
+ const elements = [];
3349
+ const stateSnapshot = getStateSnapshotForMessage(message.id);
3350
+ if (renderCustomMessage) {
3351
+ elements.push(
3352
+ /* @__PURE__ */ jsx18(
3353
+ MemoizedCustomMessage,
3354
+ {
3355
+ message,
3356
+ position: "before",
3357
+ renderCustomMessage,
3358
+ stateSnapshot
3359
+ },
3360
+ `${message.id}-custom-before`
3361
+ )
3362
+ );
3363
+ }
3364
+ if (message.role === "assistant") {
3365
+ const AssistantComponent = typeof assistantMessage === "function" ? assistantMessage : CopilotChatAssistantMessage_default;
3366
+ elements.push(
3367
+ /* @__PURE__ */ jsx18(
3368
+ MemoizedAssistantMessage,
3369
+ {
3370
+ message,
3371
+ messages,
3372
+ isRunning,
3373
+ AssistantMessageComponent: AssistantComponent
3374
+ },
3375
+ message.id
3376
+ )
3377
+ );
3378
+ } else if (message.role === "user") {
3379
+ const UserComponent = typeof userMessage === "function" ? userMessage : CopilotChatUserMessage_default;
3380
+ elements.push(
3381
+ /* @__PURE__ */ jsx18(
3382
+ MemoizedUserMessage,
3383
+ {
3384
+ message,
3385
+ UserMessageComponent: UserComponent
3386
+ },
3387
+ message.id
3388
+ )
3389
+ );
3390
+ } else if (message.role === "activity") {
3391
+ elements.push(
3392
+ /* @__PURE__ */ jsx18(
3393
+ MemoizedActivityMessage,
3394
+ {
3395
+ message,
3396
+ renderActivityMessage
3397
+ },
3398
+ message.id
3399
+ )
3400
+ );
3401
+ }
3402
+ if (renderCustomMessage) {
3403
+ elements.push(
3404
+ /* @__PURE__ */ jsx18(
3405
+ MemoizedCustomMessage,
3406
+ {
3407
+ message,
3408
+ position: "after",
3409
+ renderCustomMessage,
3410
+ stateSnapshot
3411
+ },
3412
+ `${message.id}-custom-after`
3413
+ )
3414
+ );
3415
+ }
3416
+ return elements;
3417
+ }).filter(Boolean);
3418
+ if (children) {
3419
+ return children({ messageElements, messages, isRunning });
3420
+ }
3421
+ return /* @__PURE__ */ jsxs10("div", { className: twMerge6("flex flex-col", className), ...props, children: [
3422
+ messageElements,
3423
+ isRunning && renderSlot(cursor, CopilotChatMessageView.Cursor, {})
3424
+ ] });
3425
+ }
3426
+ CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
3427
+ return /* @__PURE__ */ jsx18(
3428
+ "div",
3429
+ {
3430
+ className: twMerge6("w-[11px] h-[11px] rounded-full bg-foreground animate-pulse-cursor ml-1", className),
3431
+ ...props
3432
+ }
3433
+ );
3434
+ };
3435
+ var CopilotChatMessageView_default = CopilotChatMessageView;
3436
+
3437
+ // src/components/chat/CopilotChatView.tsx
3438
+ import React13, { useRef as useRef7, useState as useState10, useEffect as useEffect14 } from "react";
3439
+ import { twMerge as twMerge7 } from "tailwind-merge";
3440
+ import { StickToBottom, useStickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
3441
+ import { ChevronDown } from "lucide-react";
3442
+
3443
+ // src/hooks/use-keyboard-height.tsx
3444
+ import { useState as useState9, useEffect as useEffect13 } from "react";
3445
+ function useKeyboardHeight() {
3446
+ const [keyboardState, setKeyboardState] = useState9({
3447
+ isKeyboardOpen: false,
3448
+ keyboardHeight: 0,
3449
+ availableHeight: typeof window !== "undefined" ? window.innerHeight : 0,
3450
+ viewportHeight: typeof window !== "undefined" ? window.innerHeight : 0
3451
+ });
3452
+ useEffect13(() => {
3453
+ if (typeof window === "undefined") {
3454
+ return;
3455
+ }
3456
+ const visualViewport = window.visualViewport;
3457
+ if (!visualViewport) {
3458
+ return;
3459
+ }
3460
+ const updateKeyboardState = () => {
3461
+ const layoutHeight = window.innerHeight;
3462
+ const visualHeight = visualViewport.height;
3463
+ const keyboardHeight = Math.max(0, layoutHeight - visualHeight);
3464
+ const isKeyboardOpen = keyboardHeight > 150;
3465
+ setKeyboardState({
3466
+ isKeyboardOpen,
3467
+ keyboardHeight,
3468
+ availableHeight: visualHeight,
3469
+ viewportHeight: layoutHeight
3470
+ });
3471
+ };
3472
+ updateKeyboardState();
3473
+ visualViewport.addEventListener("resize", updateKeyboardState);
3474
+ visualViewport.addEventListener("scroll", updateKeyboardState);
3475
+ return () => {
3476
+ visualViewport.removeEventListener("resize", updateKeyboardState);
3477
+ visualViewport.removeEventListener("scroll", updateKeyboardState);
3478
+ };
3479
+ }, []);
3480
+ return keyboardState;
3481
+ }
3482
+
3483
+ // src/components/chat/CopilotChatView.tsx
3484
+ import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
3485
+ function CopilotChatView({
3486
+ messageView,
3487
+ input,
3488
+ scrollView,
3489
+ scrollToBottomButton,
3490
+ feather,
3491
+ inputContainer,
3492
+ disclaimer,
3493
+ suggestionView,
3494
+ messages = [],
3495
+ autoScroll = true,
3496
+ inputProps,
3497
+ isRunning = false,
3498
+ suggestions,
3499
+ suggestionLoadingIndexes,
3500
+ onSelectSuggestion,
3501
+ children,
3502
+ className,
3503
+ ...props
3504
+ }) {
3505
+ const inputContainerRef = useRef7(null);
3506
+ const [inputContainerHeight, setInputContainerHeight] = useState10(0);
3507
+ const [isResizing, setIsResizing] = useState10(false);
3508
+ const resizeTimeoutRef = useRef7(null);
3509
+ const { isKeyboardOpen, keyboardHeight, availableHeight } = useKeyboardHeight();
3510
+ useEffect14(() => {
3511
+ const element = inputContainerRef.current;
3512
+ if (!element) return;
3513
+ const resizeObserver = new ResizeObserver((entries) => {
3514
+ for (const entry of entries) {
3515
+ const newHeight = entry.contentRect.height;
3516
+ setInputContainerHeight((prevHeight) => {
3517
+ if (newHeight !== prevHeight) {
3518
+ setIsResizing(true);
3519
+ if (resizeTimeoutRef.current) {
3520
+ clearTimeout(resizeTimeoutRef.current);
3521
+ }
3522
+ resizeTimeoutRef.current = setTimeout(() => {
3523
+ setIsResizing(false);
3524
+ }, 250);
3525
+ return newHeight;
3526
+ }
3527
+ return prevHeight;
3528
+ });
3529
+ }
3530
+ });
3531
+ resizeObserver.observe(element);
3532
+ setInputContainerHeight(element.offsetHeight);
3533
+ return () => {
3534
+ resizeObserver.disconnect();
3535
+ if (resizeTimeoutRef.current) {
3536
+ clearTimeout(resizeTimeoutRef.current);
3537
+ }
3538
+ };
3539
+ }, []);
3540
+ const BoundMessageView = renderSlot(messageView, CopilotChatMessageView_default, {
3541
+ messages,
3542
+ isRunning
3543
+ });
3544
+ const BoundInput = renderSlot(input, CopilotChatInput_default, inputProps ?? {});
3545
+ const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
3546
+ const BoundSuggestionView = hasSuggestions ? renderSlot(suggestionView, CopilotChatSuggestionView_default, {
3547
+ suggestions,
3548
+ loadingIndexes: suggestionLoadingIndexes,
3549
+ onSelectSuggestion,
3550
+ className: "mb-3 lg:ml-4 lg:mr-4 ml-0 mr-0"
3551
+ }) : null;
3552
+ const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
3553
+ const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
3554
+ autoScroll,
3555
+ scrollToBottomButton,
3556
+ inputContainerHeight,
3557
+ isResizing,
3558
+ children: /* @__PURE__ */ jsx19("div", { style: { paddingBottom: `${inputContainerHeight + (hasSuggestions ? 4 : 32)}px` }, children: /* @__PURE__ */ jsxs11("div", { className: "max-w-3xl mx-auto", children: [
3559
+ BoundMessageView,
3560
+ hasSuggestions ? /* @__PURE__ */ jsx19("div", { className: "pl-0 pr-4 sm:px-0 mt-4", children: BoundSuggestionView }) : null
3561
+ ] }) })
3562
+ });
3563
+ const BoundScrollToBottomButton = renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, {});
3564
+ const BoundDisclaimer = renderSlot(disclaimer, CopilotChatView.Disclaimer, {});
3565
+ const BoundInputContainer = renderSlot(inputContainer, CopilotChatView.InputContainer, {
3566
+ ref: inputContainerRef,
3567
+ keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
3568
+ children: /* @__PURE__ */ jsxs11(Fragment6, { children: [
3569
+ /* @__PURE__ */ jsx19("div", { className: "max-w-3xl mx-auto py-0 px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6 pointer-events-auto", children: BoundInput }),
3570
+ BoundDisclaimer
3571
+ ] })
3572
+ });
3573
+ if (children) {
3574
+ return children({
3575
+ messageView: BoundMessageView,
3576
+ input: BoundInput,
3577
+ scrollView: BoundScrollView,
3578
+ scrollToBottomButton: BoundScrollToBottomButton,
3579
+ feather: BoundFeather,
3580
+ inputContainer: BoundInputContainer,
3581
+ disclaimer: BoundDisclaimer,
3582
+ suggestionView: BoundSuggestionView ?? /* @__PURE__ */ jsx19(Fragment6, {})
3583
+ });
3584
+ }
3585
+ return /* @__PURE__ */ jsxs11("div", { className: twMerge7("relative h-full", className), ...props, children: [
3586
+ BoundScrollView,
3587
+ BoundFeather,
3588
+ BoundInputContainer
3589
+ ] });
3590
+ }
3591
+ ((CopilotChatView2) => {
3592
+ const ScrollContent = ({ children, scrollToBottomButton, inputContainerHeight, isResizing }) => {
3593
+ const { isAtBottom, scrollToBottom } = useStickToBottomContext();
3594
+ return /* @__PURE__ */ jsxs11(Fragment6, { children: [
3595
+ /* @__PURE__ */ jsx19(StickToBottom.Content, { className: "overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx19("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6", children }) }),
3596
+ !isAtBottom && !isResizing && /* @__PURE__ */ jsx19(
3597
+ "div",
3598
+ {
3599
+ className: "absolute inset-x-0 flex justify-center z-10 pointer-events-none",
3600
+ style: {
3601
+ bottom: `${inputContainerHeight + 16}px`
3602
+ },
3603
+ children: renderSlot(scrollToBottomButton, CopilotChatView2.ScrollToBottomButton, {
3604
+ onClick: () => scrollToBottom()
3605
+ })
3606
+ }
3607
+ )
3608
+ ] });
3609
+ };
3610
+ CopilotChatView2.ScrollView = ({
3611
+ children,
3612
+ autoScroll = true,
3613
+ scrollToBottomButton,
3614
+ inputContainerHeight = 0,
3615
+ isResizing = false,
3616
+ className,
3617
+ ...props
3618
+ }) => {
3619
+ const [hasMounted, setHasMounted] = useState10(false);
3620
+ const { scrollRef, contentRef, scrollToBottom } = useStickToBottom();
3621
+ const [showScrollButton, setShowScrollButton] = useState10(false);
3622
+ useEffect14(() => {
3623
+ setHasMounted(true);
3624
+ }, []);
3625
+ useEffect14(() => {
3626
+ if (autoScroll) return;
3627
+ const scrollElement = scrollRef.current;
3628
+ if (!scrollElement) return;
3629
+ const checkScroll = () => {
3630
+ const atBottom = scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight < 10;
3631
+ setShowScrollButton(!atBottom);
3632
+ };
3633
+ checkScroll();
3634
+ scrollElement.addEventListener("scroll", checkScroll);
3635
+ const resizeObserver = new ResizeObserver(checkScroll);
3636
+ resizeObserver.observe(scrollElement);
3637
+ return () => {
3638
+ scrollElement.removeEventListener("scroll", checkScroll);
3639
+ resizeObserver.disconnect();
3640
+ };
3641
+ }, [scrollRef, autoScroll]);
3642
+ if (!hasMounted) {
3643
+ return /* @__PURE__ */ jsx19("div", { className: "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden", children: /* @__PURE__ */ jsx19("div", { className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6", children }) });
3644
+ }
3645
+ if (!autoScroll) {
3646
+ return /* @__PURE__ */ jsxs11(
3647
+ "div",
3648
+ {
3649
+ ref: scrollRef,
3650
+ className: cn(
3651
+ "h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden relative",
3652
+ className
3653
+ ),
3654
+ ...props,
3655
+ children: [
3656
+ /* @__PURE__ */ jsx19("div", { ref: contentRef, className: "px-4 sm:px-0 [div[data-sidebar-chat]_&]:px-8 [div[data-popup-chat]_&]:px-6", children }),
3657
+ showScrollButton && !isResizing && /* @__PURE__ */ jsx19(
3658
+ "div",
3659
+ {
3660
+ className: "absolute inset-x-0 flex justify-center z-10 pointer-events-none",
3661
+ style: {
3662
+ bottom: `${inputContainerHeight + 16}px`
3663
+ },
3664
+ children: renderSlot(scrollToBottomButton, CopilotChatView2.ScrollToBottomButton, {
3665
+ onClick: () => scrollToBottom()
3666
+ })
3667
+ }
3668
+ )
3669
+ ]
3670
+ }
3671
+ );
3672
+ }
3673
+ return /* @__PURE__ */ jsx19(
3674
+ StickToBottom,
3675
+ {
3676
+ className: cn("h-full max-h-full flex flex-col min-h-0 relative", className),
3677
+ resize: "smooth",
3678
+ initial: "smooth",
3679
+ ...props,
3680
+ children: /* @__PURE__ */ jsx19(
3681
+ ScrollContent,
3682
+ {
3683
+ scrollToBottomButton,
3684
+ inputContainerHeight,
3685
+ isResizing,
3686
+ children
3687
+ }
3688
+ )
3689
+ }
3690
+ );
3691
+ };
3692
+ CopilotChatView2.ScrollToBottomButton = ({
3693
+ className,
3694
+ ...props
3695
+ }) => /* @__PURE__ */ jsx19(
3696
+ Button,
3697
+ {
3698
+ variant: "outline",
3699
+ size: "sm",
3700
+ className: twMerge7(
3701
+ "rounded-full w-10 h-10 p-0 pointer-events-auto",
3702
+ "bg-white dark:bg-gray-900",
3703
+ "shadow-lg border border-gray-200 dark:border-gray-700",
3704
+ "hover:bg-gray-50 dark:hover:bg-gray-800",
3705
+ "flex items-center justify-center cursor-pointer",
3706
+ className
3707
+ ),
3708
+ ...props,
3709
+ children: /* @__PURE__ */ jsx19(ChevronDown, { className: "w-4 h-4 text-gray-600 dark:text-white" })
3710
+ }
3711
+ );
3712
+ CopilotChatView2.Feather = ({ className, style, ...props }) => /* @__PURE__ */ jsx19(
3713
+ "div",
3714
+ {
3715
+ className: cn(
3716
+ "absolute bottom-0 left-0 right-4 h-24 pointer-events-none z-10 bg-gradient-to-t",
3717
+ "from-white via-white to-transparent",
3718
+ "dark:from-[rgb(33,33,33)] dark:via-[rgb(33,33,33)]",
3719
+ className
3720
+ ),
3721
+ style,
3722
+ ...props
3723
+ }
3724
+ );
3725
+ CopilotChatView2.InputContainer = React13.forwardRef(({ children, className, keyboardHeight = 0, ...props }, ref) => /* @__PURE__ */ jsx19(
3726
+ "div",
3727
+ {
3728
+ ref,
3729
+ className: cn("absolute bottom-0 left-0 right-0 z-20 pointer-events-none", className),
3730
+ style: {
3731
+ // Adjust position when keyboard is open to keep input visible
3732
+ transform: keyboardHeight > 0 ? `translateY(-${keyboardHeight}px)` : void 0,
3733
+ transition: "transform 0.2s ease-out"
3734
+ },
3735
+ ...props,
3736
+ children
3737
+ }
3738
+ ));
3739
+ CopilotChatView2.InputContainer.displayName = "CopilotChatView.InputContainer";
3740
+ CopilotChatView2.Disclaimer = ({ className, ...props }) => {
3741
+ const config = useCopilotChatConfiguration();
3742
+ const labels = config?.labels ?? CopilotChatDefaultLabels;
3743
+ return /* @__PURE__ */ jsx19(
3744
+ "div",
3745
+ {
3746
+ className: cn("text-center text-xs text-muted-foreground py-3 px-4 max-w-3xl mx-auto", className),
3747
+ ...props,
3748
+ children: labels.chatDisclaimerText
3749
+ }
3750
+ );
3751
+ };
3752
+ })(CopilotChatView || (CopilotChatView = {}));
3753
+ var CopilotChatView_default = CopilotChatView;
3754
+
3755
+ // src/components/chat/CopilotChat.tsx
3756
+ import { DEFAULT_AGENT_ID as DEFAULT_AGENT_ID7, randomUUID as randomUUID2 } from "@copilotkitnext/shared";
3757
+ import { useCallback as useCallback8, useEffect as useEffect15, useMemo as useMemo10 } from "react";
3758
+ import { merge } from "ts-deepmerge";
3759
+ import { AGUIConnectNotImplementedError } from "@ag-ui/client";
3760
+ import { jsx as jsx20 } from "react/jsx-runtime";
3761
+ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, ...props }) {
3762
+ const existingConfig = useCopilotChatConfiguration();
3763
+ const resolvedAgentId = agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID7;
3764
+ const resolvedThreadId = useMemo10(
3765
+ () => threadId ?? existingConfig?.threadId ?? randomUUID2(),
3766
+ [threadId, existingConfig?.threadId]
3767
+ );
3768
+ const { agent } = useAgent({ agentId: resolvedAgentId });
3769
+ const { copilotkit } = useCopilotKit();
3770
+ const { suggestions: autoSuggestions } = useSuggestions({ agentId: resolvedAgentId });
3771
+ const {
3772
+ inputProps: providedInputProps,
3773
+ messageView: providedMessageView,
3774
+ suggestionView: providedSuggestionView,
3775
+ ...restProps
3776
+ } = props;
3777
+ useEffect15(() => {
3778
+ const connect = async (agent2) => {
3779
+ try {
3780
+ await copilotkit.connectAgent({ agent: agent2 });
3781
+ } catch (error) {
3782
+ if (error instanceof AGUIConnectNotImplementedError) {
3783
+ } else {
3784
+ throw error;
3785
+ }
3786
+ }
3787
+ };
3788
+ agent.threadId = resolvedThreadId;
3789
+ connect(agent);
3790
+ return () => {
3791
+ };
3792
+ }, [resolvedThreadId, agent, copilotkit, resolvedAgentId]);
3793
+ const onSubmitInput = useCallback8(
3794
+ async (value) => {
3795
+ agent.addMessage({
3796
+ id: randomUUID2(),
3797
+ role: "user",
3798
+ content: value
3799
+ });
3800
+ try {
3801
+ await copilotkit.runAgent({ agent });
3802
+ } catch (error) {
3803
+ console.error("CopilotChat: runAgent failed", error);
3804
+ }
3805
+ },
3806
+ [agent, copilotkit]
3807
+ );
3808
+ const handleSelectSuggestion = useCallback8(
3809
+ async (suggestion) => {
3810
+ agent.addMessage({
3811
+ id: randomUUID2(),
3812
+ role: "user",
3813
+ content: suggestion.message
3814
+ });
3815
+ try {
3816
+ await copilotkit.runAgent({ agent });
3817
+ } catch (error) {
3818
+ console.error("CopilotChat: runAgent failed after selecting suggestion", error);
3819
+ }
3820
+ },
3821
+ [agent, copilotkit]
3822
+ );
3823
+ const stopCurrentRun = useCallback8(() => {
3824
+ try {
3825
+ copilotkit.stopAgent({ agent });
3826
+ } catch (error) {
3827
+ console.error("CopilotChat: stopAgent failed", error);
3828
+ try {
3829
+ agent.abortRun();
3830
+ } catch (abortError) {
3831
+ console.error("CopilotChat: abortRun fallback failed", abortError);
3832
+ }
3833
+ }
3834
+ }, [agent, copilotkit]);
3835
+ const mergedProps = merge(
3836
+ {
3837
+ isRunning: agent.isRunning,
3838
+ suggestions: autoSuggestions,
3839
+ onSelectSuggestion: handleSelectSuggestion,
3840
+ suggestionView: providedSuggestionView
3841
+ },
3842
+ {
3843
+ ...restProps,
3844
+ ...typeof providedMessageView === "string" ? { messageView: { className: providedMessageView } } : providedMessageView !== void 0 ? { messageView: providedMessageView } : {}
3845
+ }
3846
+ );
3847
+ const providedStopHandler = providedInputProps?.onStop;
3848
+ const hasMessages = agent.messages.length > 0;
3849
+ const shouldAllowStop = agent.isRunning && hasMessages;
3850
+ const effectiveStopHandler = shouldAllowStop ? providedStopHandler ?? stopCurrentRun : providedStopHandler;
3851
+ const finalInputProps = {
3852
+ ...providedInputProps,
3853
+ onSubmitMessage: onSubmitInput,
3854
+ onStop: effectiveStopHandler,
3855
+ isRunning: agent.isRunning
3856
+ };
3857
+ finalInputProps.mode = agent.isRunning ? "processing" : finalInputProps.mode ?? "input";
3858
+ const finalProps = merge(mergedProps, {
3859
+ messages: agent.messages,
3860
+ inputProps: finalInputProps
3861
+ });
3862
+ const RenderedChatView = renderSlot(chatView, CopilotChatView, finalProps);
3863
+ return /* @__PURE__ */ jsx20(
3864
+ CopilotChatConfigurationProvider,
3865
+ {
3866
+ agentId: resolvedAgentId,
3867
+ threadId: resolvedThreadId,
3868
+ labels,
3869
+ isModalDefaultOpen,
3870
+ children: RenderedChatView
3871
+ }
3872
+ );
3873
+ }
3874
+ ((CopilotChat2) => {
3875
+ CopilotChat2.View = CopilotChatView;
3876
+ })(CopilotChat || (CopilotChat = {}));
3877
+
3878
+ // src/components/chat/CopilotChatToggleButton.tsx
3879
+ import React14, { useState as useState11 } from "react";
3880
+ import { MessageCircle, X as X2 } from "lucide-react";
3881
+ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
3882
+ var DefaultOpenIcon = ({
3883
+ className,
3884
+ ...props
3885
+ }) => /* @__PURE__ */ jsx21(MessageCircle, { className: cn("h-6 w-6", className), strokeWidth: 1.75, fill: "currentColor", ...props });
3886
+ var DefaultCloseIcon = ({
3887
+ className,
3888
+ ...props
3889
+ }) => /* @__PURE__ */ jsx21(X2, { className: cn("h-6 w-6", className), strokeWidth: 1.75, ...props });
3890
+ DefaultOpenIcon.displayName = "CopilotChatToggleButton.OpenIcon";
3891
+ DefaultCloseIcon.displayName = "CopilotChatToggleButton.CloseIcon";
3892
+ var ICON_TRANSITION_STYLE = Object.freeze({
3893
+ transition: "opacity 120ms ease-out, transform 260ms cubic-bezier(0.22, 1, 0.36, 1)"
3894
+ });
3895
+ var ICON_WRAPPER_BASE = "pointer-events-none absolute inset-0 flex items-center justify-center will-change-transform";
3896
+ var BUTTON_BASE_CLASSES = cn(
3897
+ "fixed bottom-6 right-6 z-[1100] flex h-14 w-14 items-center justify-center",
3898
+ "rounded-full border border-primary bg-primary text-primary-foreground",
3899
+ "shadow-sm transition-all duration-200 ease-out",
3900
+ "hover:scale-[1.04] hover:shadow-md",
3901
+ "cursor-pointer",
3902
+ "active:scale-[0.96]",
3903
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
3904
+ "disabled:pointer-events-none disabled:opacity-60"
3905
+ );
3906
+ var CopilotChatToggleButton = React14.forwardRef(function CopilotChatToggleButton2({ openIcon, closeIcon, className, ...buttonProps }, ref) {
3907
+ const { onClick, type, disabled, ...restProps } = buttonProps;
3908
+ const configuration = useCopilotChatConfiguration();
3909
+ const labels = configuration?.labels ?? CopilotChatDefaultLabels;
3910
+ const [fallbackOpen, setFallbackOpen] = useState11(false);
3911
+ const isOpen = configuration?.isModalOpen ?? fallbackOpen;
3912
+ const setModalOpen = configuration?.setModalOpen ?? setFallbackOpen;
3913
+ const handleClick = (event) => {
3914
+ if (disabled) {
3915
+ return;
3916
+ }
3917
+ if (onClick) {
3918
+ onClick(event);
3919
+ }
3920
+ if (event.defaultPrevented) {
3921
+ return;
3922
+ }
3923
+ const nextOpen = !isOpen;
3924
+ setModalOpen(nextOpen);
3925
+ };
3926
+ const renderedOpenIcon = renderSlot(
3927
+ openIcon,
3928
+ DefaultOpenIcon,
3929
+ {
3930
+ className: "h-6 w-6",
3931
+ "aria-hidden": true,
3932
+ focusable: false
3933
+ }
3934
+ );
3935
+ const renderedCloseIcon = renderSlot(
3936
+ closeIcon,
3937
+ DefaultCloseIcon,
3938
+ {
3939
+ className: "h-6 w-6",
3940
+ "aria-hidden": true,
3941
+ focusable: false
3942
+ }
3943
+ );
3944
+ const openIconElement = /* @__PURE__ */ jsx21(
3945
+ "span",
3946
+ {
3947
+ "aria-hidden": "true",
3948
+ "data-slot": "chat-toggle-button-open-icon",
3949
+ className: ICON_WRAPPER_BASE,
3950
+ style: {
3951
+ ...ICON_TRANSITION_STYLE,
3952
+ opacity: isOpen ? 0 : 1,
3953
+ transform: `scale(${isOpen ? 0.75 : 1}) rotate(${isOpen ? 90 : 0}deg)`
3954
+ },
3955
+ children: renderedOpenIcon
3956
+ }
3957
+ );
3958
+ const closeIconElement = /* @__PURE__ */ jsx21(
3959
+ "span",
3960
+ {
3961
+ "aria-hidden": "true",
3962
+ "data-slot": "chat-toggle-button-close-icon",
3963
+ className: ICON_WRAPPER_BASE,
3964
+ style: {
3965
+ ...ICON_TRANSITION_STYLE,
3966
+ opacity: isOpen ? 1 : 0,
3967
+ transform: `scale(${isOpen ? 1 : 0.75}) rotate(${isOpen ? 0 : -90}deg)`
3968
+ },
3969
+ children: renderedCloseIcon
3970
+ }
3971
+ );
3972
+ return /* @__PURE__ */ jsxs12(
3973
+ "button",
3974
+ {
3975
+ ref,
3976
+ type: type ?? "button",
3977
+ "data-slot": "chat-toggle-button",
3978
+ "data-state": isOpen ? "open" : "closed",
3979
+ className: cn(BUTTON_BASE_CLASSES, className),
3980
+ "aria-label": isOpen ? labels.chatToggleCloseLabel : labels.chatToggleOpenLabel,
3981
+ "aria-pressed": isOpen,
3982
+ disabled,
3983
+ onClick: handleClick,
3984
+ ...restProps,
3985
+ children: [
3986
+ openIconElement,
3987
+ closeIconElement
3988
+ ]
3989
+ }
3990
+ );
3991
+ });
3992
+ CopilotChatToggleButton.displayName = "CopilotChatToggleButton";
3993
+ var CopilotChatToggleButton_default = CopilotChatToggleButton;
3994
+
3995
+ // src/components/chat/CopilotSidebarView.tsx
3996
+ import { useEffect as useEffect16, useRef as useRef8, useState as useState12 } from "react";
3997
+
3998
+ // src/components/chat/CopilotModalHeader.tsx
3999
+ import { useCallback as useCallback9 } from "react";
4000
+ import { X as X3 } from "lucide-react";
4001
+ import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
4002
+ function CopilotModalHeader({
4003
+ title,
4004
+ titleContent,
4005
+ closeButton,
4006
+ children,
4007
+ className,
4008
+ ...rest
4009
+ }) {
4010
+ const configuration = useCopilotChatConfiguration();
4011
+ const fallbackTitle = configuration?.labels.modalHeaderTitle ?? CopilotChatDefaultLabels.modalHeaderTitle;
4012
+ const resolvedTitle = title ?? fallbackTitle;
4013
+ const handleClose = useCallback9(() => {
4014
+ configuration?.setModalOpen(false);
4015
+ }, [configuration]);
4016
+ const BoundTitle = renderSlot(titleContent, CopilotModalHeader.Title, {
4017
+ children: resolvedTitle
4018
+ });
4019
+ const BoundCloseButton = renderSlot(closeButton, CopilotModalHeader.CloseButton, {
4020
+ onClick: handleClose
4021
+ });
4022
+ if (children) {
4023
+ return children({
4024
+ titleContent: BoundTitle,
4025
+ closeButton: BoundCloseButton,
4026
+ title: resolvedTitle,
4027
+ ...rest
4028
+ });
4029
+ }
4030
+ return /* @__PURE__ */ jsx22(
4031
+ "header",
4032
+ {
4033
+ "data-slot": "copilot-modal-header",
4034
+ className: cn(
4035
+ "flex items-center justify-between border-b border-border px-4 py-4",
4036
+ "bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80",
4037
+ className
4038
+ ),
4039
+ ...rest,
4040
+ children: /* @__PURE__ */ jsxs13("div", { className: "flex w-full items-center gap-2", children: [
4041
+ /* @__PURE__ */ jsx22("div", { className: "flex-1", "aria-hidden": "true" }),
4042
+ /* @__PURE__ */ jsx22("div", { className: "flex flex-1 justify-center text-center", children: BoundTitle }),
4043
+ /* @__PURE__ */ jsx22("div", { className: "flex flex-1 justify-end", children: BoundCloseButton })
4044
+ ] })
4045
+ }
4046
+ );
4047
+ }
4048
+ CopilotModalHeader.displayName = "CopilotModalHeader";
4049
+ ((CopilotModalHeader2) => {
4050
+ CopilotModalHeader2.Title = ({ children, className, ...props }) => /* @__PURE__ */ jsx22(
4051
+ "div",
4052
+ {
4053
+ className: cn(
4054
+ "w-full text-base font-medium leading-none tracking-tight text-foreground",
4055
+ className
4056
+ ),
4057
+ ...props,
4058
+ children
4059
+ }
4060
+ );
4061
+ CopilotModalHeader2.CloseButton = ({
4062
+ className,
4063
+ ...props
4064
+ }) => /* @__PURE__ */ jsx22(
4065
+ "button",
4066
+ {
4067
+ type: "button",
4068
+ className: cn(
4069
+ "inline-flex size-8 items-center justify-center rounded-full text-muted-foreground transition cursor-pointer",
4070
+ "hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
4071
+ className
4072
+ ),
4073
+ "aria-label": "Close",
4074
+ ...props,
4075
+ children: /* @__PURE__ */ jsx22(X3, { className: "h-4 w-4", "aria-hidden": "true" })
4076
+ }
4077
+ );
4078
+ })(CopilotModalHeader || (CopilotModalHeader = {}));
4079
+ CopilotModalHeader.Title.displayName = "CopilotModalHeader.Title";
4080
+ CopilotModalHeader.CloseButton.displayName = "CopilotModalHeader.CloseButton";
4081
+
4082
+ // src/components/chat/CopilotSidebarView.tsx
4083
+ import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
4084
+ var DEFAULT_SIDEBAR_WIDTH = 480;
4085
+ var SIDEBAR_TRANSITION_MS = 260;
4086
+ function CopilotSidebarView({ header, width, ...props }) {
4087
+ const configuration = useCopilotChatConfiguration();
4088
+ const isSidebarOpen = configuration?.isModalOpen ?? false;
4089
+ const sidebarRef = useRef8(null);
4090
+ const [sidebarWidth, setSidebarWidth] = useState12(width ?? DEFAULT_SIDEBAR_WIDTH);
4091
+ const widthToCss = (w) => {
4092
+ return typeof w === "number" ? `${w}px` : w;
4093
+ };
4094
+ const widthToMargin = (w) => {
4095
+ if (typeof w === "number") {
4096
+ return `${w}px`;
4097
+ }
4098
+ return w;
4099
+ };
4100
+ useEffect16(() => {
4101
+ if (width !== void 0) {
4102
+ return;
4103
+ }
4104
+ if (typeof window === "undefined") {
4105
+ return;
4106
+ }
4107
+ const element = sidebarRef.current;
4108
+ if (!element) {
4109
+ return;
4110
+ }
4111
+ const updateWidth = () => {
4112
+ const rect = element.getBoundingClientRect();
4113
+ if (rect.width > 0) {
4114
+ setSidebarWidth(rect.width);
4115
+ }
4116
+ };
4117
+ updateWidth();
4118
+ if (typeof ResizeObserver !== "undefined") {
4119
+ const observer = new ResizeObserver(() => updateWidth());
4120
+ observer.observe(element);
4121
+ return () => observer.disconnect();
4122
+ }
4123
+ window.addEventListener("resize", updateWidth);
4124
+ return () => window.removeEventListener("resize", updateWidth);
4125
+ }, [width]);
4126
+ const headerElement = renderSlot(header, CopilotModalHeader, {});
4127
+ return /* @__PURE__ */ jsxs14(Fragment7, { children: [
4128
+ isSidebarOpen && /* @__PURE__ */ jsx23(
4129
+ "style",
4130
+ {
4131
+ dangerouslySetInnerHTML: {
4132
+ __html: `
4133
+ @media (min-width: 768px) {
4134
+ body {
4135
+ margin-inline-end: ${widthToMargin(sidebarWidth)};
4136
+ transition: margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease;
4137
+ }
4138
+ }`
4139
+ }
4140
+ }
4141
+ ),
4142
+ /* @__PURE__ */ jsx23(CopilotChatToggleButton_default, {}),
4143
+ /* @__PURE__ */ jsx23(
4144
+ "aside",
4145
+ {
4146
+ ref: sidebarRef,
4147
+ "data-copilot-sidebar": true,
4148
+ className: cn(
4149
+ "fixed right-0 top-0 z-[1200] flex",
4150
+ // Height with dvh fallback and safe area support
4151
+ "h-[100vh] h-[100dvh] max-h-screen",
4152
+ // Responsive width: full on mobile, custom on desktop
4153
+ "w-full",
4154
+ "border-l border-border bg-background text-foreground shadow-xl",
4155
+ "transition-transform duration-300 ease-out",
4156
+ isSidebarOpen ? "translate-x-0" : "translate-x-full pointer-events-none"
4157
+ ),
4158
+ style: {
4159
+ // Use CSS custom property for responsive width
4160
+ ["--sidebar-width"]: widthToCss(sidebarWidth),
4161
+ // Safe area insets for iOS
4162
+ paddingTop: "env(safe-area-inset-top)",
4163
+ paddingBottom: "env(safe-area-inset-bottom)"
4164
+ },
4165
+ "aria-hidden": !isSidebarOpen,
4166
+ "aria-label": "Copilot chat sidebar",
4167
+ role: "complementary",
4168
+ children: /* @__PURE__ */ jsxs14("div", { className: "flex h-full w-full flex-col overflow-hidden", children: [
4169
+ headerElement,
4170
+ /* @__PURE__ */ jsx23("div", { className: "flex-1 overflow-hidden", "data-sidebar-chat": true, children: /* @__PURE__ */ jsx23(CopilotChatView_default, { ...props }) })
4171
+ ] })
4172
+ }
4173
+ )
4174
+ ] });
4175
+ }
4176
+ CopilotSidebarView.displayName = "CopilotSidebarView";
4177
+
4178
+ // src/components/chat/CopilotPopupView.tsx
4179
+ import { useEffect as useEffect17, useMemo as useMemo11, useRef as useRef9, useState as useState13 } from "react";
4180
+ import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs15 } from "react/jsx-runtime";
4181
+ var DEFAULT_POPUP_WIDTH = 420;
4182
+ var DEFAULT_POPUP_HEIGHT = 560;
4183
+ var dimensionToCss = (value, fallback) => {
4184
+ if (typeof value === "number" && Number.isFinite(value)) {
4185
+ return `${value}px`;
4186
+ }
4187
+ if (typeof value === "string" && value.trim().length > 0) {
4188
+ return value;
4189
+ }
4190
+ return `${fallback}px`;
4191
+ };
4192
+ function CopilotPopupView({
4193
+ header,
4194
+ width,
4195
+ height,
4196
+ clickOutsideToClose,
4197
+ className,
4198
+ ...restProps
4199
+ }) {
4200
+ const configuration = useCopilotChatConfiguration();
4201
+ const isPopupOpen = configuration?.isModalOpen ?? false;
4202
+ const setModalOpen = configuration?.setModalOpen;
4203
+ const labels = configuration?.labels ?? CopilotChatDefaultLabels;
4204
+ const containerRef = useRef9(null);
4205
+ const [isRendered, setIsRendered] = useState13(isPopupOpen);
4206
+ const [isAnimatingOut, setIsAnimatingOut] = useState13(false);
4207
+ useEffect17(() => {
4208
+ if (isPopupOpen) {
4209
+ setIsRendered(true);
4210
+ setIsAnimatingOut(false);
4211
+ return;
4212
+ }
4213
+ if (!isRendered) {
4214
+ return;
4215
+ }
4216
+ setIsAnimatingOut(true);
4217
+ const timeout = setTimeout(() => {
4218
+ setIsRendered(false);
4219
+ setIsAnimatingOut(false);
4220
+ }, 200);
4221
+ return () => clearTimeout(timeout);
4222
+ }, [isPopupOpen, isRendered]);
4223
+ useEffect17(() => {
4224
+ if (!isPopupOpen) {
4225
+ return;
4226
+ }
4227
+ if (typeof window === "undefined") {
4228
+ return;
4229
+ }
4230
+ const handleKeyDown = (event) => {
4231
+ if (event.key === "Escape") {
4232
+ event.preventDefault();
4233
+ setModalOpen?.(false);
4234
+ }
4235
+ };
4236
+ window.addEventListener("keydown", handleKeyDown);
4237
+ return () => window.removeEventListener("keydown", handleKeyDown);
4238
+ }, [isPopupOpen, setModalOpen]);
4239
+ useEffect17(() => {
4240
+ if (!isPopupOpen) {
4241
+ return;
4242
+ }
4243
+ const focusTimer = setTimeout(() => {
4244
+ containerRef.current?.focus({ preventScroll: true });
4245
+ }, 200);
4246
+ return () => clearTimeout(focusTimer);
4247
+ }, [isPopupOpen]);
4248
+ useEffect17(() => {
4249
+ if (!isPopupOpen || !clickOutsideToClose) {
4250
+ return;
4251
+ }
4252
+ if (typeof document === "undefined") {
4253
+ return;
4254
+ }
4255
+ const handlePointerDown = (event) => {
4256
+ const target = event.target;
4257
+ if (!target) {
4258
+ return;
4259
+ }
4260
+ const container = containerRef.current;
4261
+ if (container?.contains(target)) {
4262
+ return;
4263
+ }
4264
+ const toggleButton = document.querySelector("[data-slot='chat-toggle-button']");
4265
+ if (toggleButton && toggleButton.contains(target)) {
4266
+ return;
4267
+ }
4268
+ setModalOpen?.(false);
4269
+ };
4270
+ document.addEventListener("pointerdown", handlePointerDown);
4271
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
4272
+ }, [isPopupOpen, clickOutsideToClose, setModalOpen]);
4273
+ const headerElement = useMemo11(() => renderSlot(header, CopilotModalHeader, {}), [header]);
4274
+ const resolvedWidth = dimensionToCss(width, DEFAULT_POPUP_WIDTH);
4275
+ const resolvedHeight = dimensionToCss(height, DEFAULT_POPUP_HEIGHT);
4276
+ const popupStyle = useMemo11(
4277
+ () => ({
4278
+ "--copilot-popup-width": resolvedWidth,
4279
+ "--copilot-popup-height": resolvedHeight,
4280
+ "--copilot-popup-max-width": "calc(100vw - 3rem)",
4281
+ "--copilot-popup-max-height": "calc(100dvh - 7.5rem)",
4282
+ paddingTop: "env(safe-area-inset-top)",
4283
+ paddingBottom: "env(safe-area-inset-bottom)",
4284
+ paddingLeft: "env(safe-area-inset-left)",
4285
+ paddingRight: "env(safe-area-inset-right)"
4286
+ }),
4287
+ [resolvedHeight, resolvedWidth]
4288
+ );
4289
+ const popupAnimationClass = isPopupOpen && !isAnimatingOut ? "pointer-events-auto translate-y-0 opacity-100 md:scale-100" : "pointer-events-none translate-y-4 opacity-0 md:translate-y-5 md:scale-[0.95]";
4290
+ const popupContent = isRendered ? /* @__PURE__ */ jsx24(
4291
+ "div",
4292
+ {
4293
+ className: cn(
4294
+ "fixed inset-0 z-[1200] flex max-w-full flex-col items-stretch",
4295
+ "md:inset-auto md:bottom-24 md:right-6 md:items-end md:gap-4"
4296
+ ),
4297
+ children: /* @__PURE__ */ jsxs15(
4298
+ "div",
4299
+ {
4300
+ ref: containerRef,
4301
+ tabIndex: -1,
4302
+ role: "dialog",
4303
+ "aria-label": labels.modalHeaderTitle,
4304
+ "data-copilot-popup": true,
4305
+ className: cn(
4306
+ "relative flex h-full w-full flex-col overflow-hidden bg-background text-foreground",
4307
+ "origin-bottom focus:outline-none transform-gpu transition-transform transition-opacity duration-200 ease-out",
4308
+ "md:transition-transform md:transition-opacity",
4309
+ "rounded-none border border-border/0 shadow-none ring-0",
4310
+ "md:h-[var(--copilot-popup-height)] md:w-[var(--copilot-popup-width)]",
4311
+ "md:max-h-[var(--copilot-popup-max-height)] md:max-w-[var(--copilot-popup-max-width)]",
4312
+ "md:origin-bottom-right md:rounded-2xl md:border-border md:shadow-xl md:ring-1 md:ring-border/40",
4313
+ popupAnimationClass
4314
+ ),
4315
+ style: popupStyle,
4316
+ children: [
4317
+ headerElement,
4318
+ /* @__PURE__ */ jsx24("div", { className: "flex-1 overflow-hidden", "data-popup-chat": true, children: /* @__PURE__ */ jsx24(
4319
+ CopilotChatView_default,
4320
+ {
4321
+ ...restProps,
4322
+ className: cn("h-full min-h-0", className)
4323
+ }
4324
+ ) })
4325
+ ]
4326
+ }
4327
+ )
4328
+ }
4329
+ ) : null;
4330
+ return /* @__PURE__ */ jsxs15(Fragment8, { children: [
4331
+ /* @__PURE__ */ jsx24(CopilotChatToggleButton_default, {}),
4332
+ popupContent
4333
+ ] });
4334
+ }
4335
+ CopilotPopupView.displayName = "CopilotPopupView";
4336
+
4337
+ // src/components/chat/CopilotSidebar.tsx
4338
+ import { useMemo as useMemo12 } from "react";
4339
+ import { jsx as jsx25 } from "react/jsx-runtime";
4340
+ function CopilotSidebar({ header, defaultOpen, width, ...chatProps }) {
4341
+ const SidebarViewOverride = useMemo12(() => {
4342
+ const Component = (viewProps) => {
4343
+ const { header: viewHeader, width: viewWidth, ...restProps } = viewProps;
4344
+ return /* @__PURE__ */ jsx25(
4345
+ CopilotSidebarView,
4346
+ {
4347
+ ...restProps,
4348
+ header: header ?? viewHeader,
4349
+ width: width ?? viewWidth
4350
+ }
4351
+ );
4352
+ };
4353
+ return Object.assign(Component, CopilotChatView_default);
4354
+ }, [header, width]);
4355
+ return /* @__PURE__ */ jsx25(
4356
+ CopilotChat,
4357
+ {
4358
+ ...chatProps,
4359
+ chatView: SidebarViewOverride,
4360
+ isModalDefaultOpen: defaultOpen
4361
+ }
4362
+ );
4363
+ }
4364
+ CopilotSidebar.displayName = "CopilotSidebar";
4365
+
4366
+ // src/components/chat/CopilotPopup.tsx
4367
+ import { useMemo as useMemo13 } from "react";
4368
+ import { jsx as jsx26 } from "react/jsx-runtime";
4369
+ function CopilotPopup({
4370
+ header,
4371
+ defaultOpen,
4372
+ width,
4373
+ height,
4374
+ clickOutsideToClose,
4375
+ ...chatProps
4376
+ }) {
4377
+ const PopupViewOverride = useMemo13(() => {
4378
+ const Component = (viewProps) => {
4379
+ const {
4380
+ header: viewHeader,
4381
+ width: viewWidth,
4382
+ height: viewHeight,
4383
+ clickOutsideToClose: viewClickOutsideToClose,
4384
+ ...restProps
4385
+ } = viewProps;
4386
+ return /* @__PURE__ */ jsx26(
4387
+ CopilotPopupView,
4388
+ {
4389
+ ...restProps,
4390
+ header: header ?? viewHeader,
4391
+ width: width ?? viewWidth,
4392
+ height: height ?? viewHeight,
4393
+ clickOutsideToClose: clickOutsideToClose ?? viewClickOutsideToClose
4394
+ }
4395
+ );
4396
+ };
4397
+ return Object.assign(Component, CopilotChatView_default);
4398
+ }, [clickOutsideToClose, header, height, width]);
4399
+ return /* @__PURE__ */ jsx26(
4400
+ CopilotChat,
4401
+ {
4402
+ ...chatProps,
4403
+ chatView: PopupViewOverride,
4404
+ isModalDefaultOpen: defaultOpen
4405
+ }
4406
+ );
4407
+ }
4408
+ CopilotPopup.displayName = "CopilotPopup";
4409
+
4410
+ // src/types/defineToolCallRenderer.ts
4411
+ import { z as z3 } from "zod";
4412
+ function defineToolCallRenderer(def) {
4413
+ const argsSchema = def.name === "*" && !def.args ? z3.any() : def.args;
4414
+ return {
4415
+ name: def.name,
4416
+ args: argsSchema,
4417
+ render: def.render,
4418
+ ...def.agentId ? { agentId: def.agentId } : {}
4419
+ };
4420
+ }
4421
+
4422
+ // src/components/WildcardToolCallRender.tsx
4423
+ import { useState as useState14 } from "react";
4424
+ import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
4425
+ var WildcardToolCallRender = defineToolCallRenderer({
4426
+ name: "*",
4427
+ render: ({ args, result, name, status }) => {
4428
+ const [isExpanded, setIsExpanded] = useState14(false);
4429
+ const statusString = String(status);
4430
+ const isActive = statusString === "inProgress" || statusString === "executing";
4431
+ const isComplete = statusString === "complete";
4432
+ const statusStyles = isActive ? "bg-amber-100 text-amber-800 dark:bg-amber-500/15 dark:text-amber-400" : isComplete ? "bg-emerald-100 text-emerald-800 dark:bg-emerald-500/15 dark:text-emerald-400" : "bg-zinc-100 text-zinc-800 dark:bg-zinc-700/40 dark:text-zinc-300";
4433
+ return /* @__PURE__ */ jsx27("div", { className: "mt-2 pb-2", children: /* @__PURE__ */ jsxs16("div", { className: "rounded-xl border border-zinc-200/60 dark:border-zinc-800/60 bg-white/70 dark:bg-zinc-900/50 shadow-sm backdrop-blur p-4", children: [
4434
+ /* @__PURE__ */ jsxs16(
4435
+ "div",
4436
+ {
4437
+ className: "flex items-center justify-between gap-3 cursor-pointer",
4438
+ onClick: () => setIsExpanded(!isExpanded),
4439
+ children: [
4440
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 min-w-0", children: [
4441
+ /* @__PURE__ */ jsx27(
4442
+ "svg",
4443
+ {
4444
+ className: `h-4 w-4 text-zinc-500 dark:text-zinc-400 transition-transform ${isExpanded ? "rotate-90" : ""}`,
4445
+ fill: "none",
4446
+ viewBox: "0 0 24 24",
4447
+ strokeWidth: 2,
4448
+ stroke: "currentColor",
4449
+ children: /* @__PURE__ */ jsx27(
4450
+ "path",
4451
+ {
4452
+ strokeLinecap: "round",
4453
+ strokeLinejoin: "round",
4454
+ d: "M8.25 4.5l7.5 7.5-7.5 7.5"
4455
+ }
4456
+ )
4457
+ }
4458
+ ),
4459
+ /* @__PURE__ */ jsx27("span", { className: "inline-block h-2 w-2 rounded-full bg-blue-500" }),
4460
+ /* @__PURE__ */ jsx27("span", { className: "truncate text-sm font-medium text-zinc-900 dark:text-zinc-100", children: name })
4461
+ ] }),
4462
+ /* @__PURE__ */ jsx27(
4463
+ "span",
4464
+ {
4465
+ className: `inline-flex items-center rounded-full px-2 py-1 text-xs font-medium ${statusStyles}`,
4466
+ children: String(status)
4467
+ }
4468
+ )
4469
+ ]
4470
+ }
4471
+ ),
4472
+ isExpanded && /* @__PURE__ */ jsxs16("div", { className: "mt-3 grid gap-4", children: [
4473
+ /* @__PURE__ */ jsxs16("div", { children: [
4474
+ /* @__PURE__ */ jsx27("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Arguments" }),
4475
+ /* @__PURE__ */ jsx27("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: JSON.stringify(args ?? {}, null, 2) })
4476
+ ] }),
4477
+ result !== void 0 && /* @__PURE__ */ jsxs16("div", { children: [
4478
+ /* @__PURE__ */ jsx27("div", { className: "text-xs uppercase tracking-wide text-zinc-500 dark:text-zinc-400", children: "Result" }),
4479
+ /* @__PURE__ */ jsx27("pre", { className: "mt-2 max-h-64 overflow-auto rounded-md bg-zinc-50 dark:bg-zinc-800/60 p-3 text-xs leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap break-words", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
4480
+ ] })
4481
+ ] })
4482
+ ] }) });
4483
+ }
4484
+ });
4485
+ export {
4486
+ AudioRecorderError,
4487
+ CopilotChat,
4488
+ CopilotChatAssistantMessage_default as CopilotChatAssistantMessage,
4489
+ CopilotChatAudioRecorder,
4490
+ CopilotChatConfigurationProvider,
4491
+ CopilotChatInput_default as CopilotChatInput,
4492
+ CopilotChatMessageView_default as CopilotChatMessageView,
4493
+ CopilotChatSuggestionPill_default as CopilotChatSuggestionPill,
4494
+ CopilotChatSuggestionView_default as CopilotChatSuggestionView,
4495
+ CopilotChatToggleButton,
4496
+ DefaultCloseIcon as CopilotChatToggleButtonCloseIcon,
4497
+ DefaultOpenIcon as CopilotChatToggleButtonOpenIcon,
4498
+ CopilotChatToolCallsView_default as CopilotChatToolCallsView,
4499
+ CopilotChatUserMessage_default as CopilotChatUserMessage,
4500
+ CopilotChatView_default as CopilotChatView,
4501
+ CopilotKitCoreReact,
4502
+ CopilotKitInspector,
4503
+ CopilotKitProvider,
4504
+ CopilotModalHeader,
4505
+ CopilotPopup,
4506
+ CopilotPopupView,
4507
+ CopilotSidebar,
4508
+ CopilotSidebarView,
4509
+ MCPAppsActivityContentSchema,
4510
+ MCPAppsActivityRenderer,
4511
+ MCPAppsActivityType,
4512
+ UseAgentUpdate,
4513
+ WildcardToolCallRender,
4514
+ defineToolCallRenderer,
4515
+ useAgent,
4516
+ useAgentContext,
4517
+ useConfigureSuggestions,
4518
+ useCopilotChatConfiguration,
4519
+ useCopilotKit,
4520
+ useFrontendTool,
4521
+ useHumanInTheLoop,
4522
+ useRenderActivityMessage,
4523
+ useRenderCustomMessages,
4524
+ useRenderToolCall,
4525
+ useSuggestions
4526
+ };
4527
+ //# sourceMappingURL=index.mjs.map