@tinkrapp/widget 1.0.0

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/react.js ADDED
@@ -0,0 +1,4815 @@
1
+ import * as React from 'react';
2
+ import { forwardRef, memo, createContext, useRef, useState, useCallback, useImperativeHandle, useEffect, useMemo, useContext } from 'react';
3
+ import { makeAssistantToolUI, useComposerRuntime, ThreadPrimitive, AssistantIf, ComposerPrimitive, MessagePrimitive, ActionBarPrimitive, BranchPickerPrimitive, ThreadListPrimitive, ThreadListItemPrimitive, useAssistantState, unstable_useRemoteThreadListRuntime, AssistantRuntimeProvider, ErrorPrimitive, useMessage, useAssistantApi, AttachmentPrimitive } from '@assistant-ui/react';
4
+ import { AssistantChatTransport, useChatRuntime } from '@assistant-ui/react-ai-sdk';
5
+ import { CacheProvider, ThemeProvider } from '@emotion/react';
6
+ import { createAssistantStream } from 'assistant-stream';
7
+ import ReactMarkdown from 'react-markdown';
8
+ import remarkGfm from 'remark-gfm';
9
+ import { FileTextIcon, ChevronUpIcon, ChevronDownIcon, CheckIcon, CopyIcon, ExternalLinkIcon, Loader2Icon, XCircleIcon, BarChart3Icon, PresentationIcon, HelpCircleIcon, LayersIcon, NetworkIcon, VideoIcon, HeadphonesIcon, DownloadIcon, ArrowDownIcon, MessageSquareTextIcon, PodcastIcon, BadgeQuestionMarkIcon, WalletCardsIcon, AtSignIcon, GlobeIcon, ArrowUpIcon, SquareIcon, RefreshCwIcon, PencilIcon, ChevronLeftIcon, ChevronRightIcon, PlusIcon, MessageSquareIcon, ArchiveIcon, Trash2Icon, ArchiveRestoreIcon, EditIcon, LayoutIcon, Minimize2Icon, BotIcon, LoaderIcon, LinkIcon, FileIcon, XIcon, PaperclipIcon, PanelLeftIcon, Maximize2Icon, FileText } from 'lucide-react';
10
+ import { clsx } from 'clsx';
11
+ import { twMerge } from 'tailwind-merge';
12
+ import { Slot, Slottable } from '@radix-ui/react-slot';
13
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
14
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
+ import { cva } from 'class-variance-authority';
16
+ import styled from '@emotion/styled';
17
+ import { motion, AnimatePresence } from 'motion/react';
18
+ import { useShallow } from 'zustand/shallow';
19
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
20
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
21
+ import '@assistant-ui/react-markdown/styles/dot.css';
22
+ import { unstable_memoizeMarkdownComponents, useIsMarkdownCodeBlock, MarkdownTextPrimitive } from '@assistant-ui/react-markdown';
23
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
24
+
25
+ // src/react/provider.tsx
26
+
27
+ // src/core/events.ts
28
+ var TypedEventEmitter = class {
29
+ constructor() {
30
+ this.listeners = /* @__PURE__ */ new Map();
31
+ }
32
+ on(event, handler) {
33
+ if (!this.listeners.has(event)) {
34
+ this.listeners.set(event, /* @__PURE__ */ new Set());
35
+ }
36
+ this.listeners.get(event).add(handler);
37
+ return () => this.off(event, handler);
38
+ }
39
+ off(event, handler) {
40
+ this.listeners.get(event)?.delete(handler);
41
+ }
42
+ emit(event, payload) {
43
+ this.listeners.get(event)?.forEach((handler) => {
44
+ try {
45
+ handler(payload);
46
+ } catch (error) {
47
+ console.error(`Error in ${String(event)} handler:`, error);
48
+ }
49
+ });
50
+ }
51
+ clear() {
52
+ this.listeners.clear();
53
+ }
54
+ removeAllListeners(event) {
55
+ if (event) {
56
+ this.listeners.delete(event);
57
+ } else {
58
+ this.listeners.clear();
59
+ }
60
+ }
61
+ };
62
+
63
+ // src/core/api.ts
64
+ var WidgetAPI = class {
65
+ constructor(config) {
66
+ this.config = {
67
+ baseUrl: "http://localhost:3000",
68
+ userId: "",
69
+ debug: false,
70
+ assistantId: config.apiKey,
71
+ // Default to apiKey for backwards compatibility
72
+ ...config
73
+ };
74
+ }
75
+ async createSession() {
76
+ const response = await this.request("/sessions", {
77
+ method: "POST",
78
+ body: JSON.stringify({
79
+ // apiKey IS the assistantId
80
+ assistantId: this.config.apiKey,
81
+ userId: this.config.userId
82
+ })
83
+ });
84
+ return response;
85
+ }
86
+ async sendMessage(sessionId, content) {
87
+ const response = await this.request(`/sessions/${sessionId}/messages`, {
88
+ method: "POST",
89
+ body: JSON.stringify({ content })
90
+ });
91
+ return response;
92
+ }
93
+ async getHistory(sessionId) {
94
+ return this.request(`/sessions/${sessionId}/messages`);
95
+ }
96
+ async getSessions() {
97
+ return this.request("/sessions");
98
+ }
99
+ async getArtifacts() {
100
+ return this.request("/artifacts");
101
+ }
102
+ async getArtifact(id) {
103
+ return this.request(`/artifacts/${id}`);
104
+ }
105
+ async createArtifact(artifact) {
106
+ return this.request("/artifacts", {
107
+ method: "POST",
108
+ body: JSON.stringify(artifact)
109
+ });
110
+ }
111
+ async request(endpoint, options = {}) {
112
+ const url = `${this.config.baseUrl}${endpoint}`;
113
+ this.log("Request:", url, options);
114
+ const response = await fetch(url, {
115
+ ...options,
116
+ headers: {
117
+ "Content-Type": "application/json",
118
+ "Authorization": `Bearer ${this.config.apiKey}`,
119
+ ...options.headers
120
+ }
121
+ });
122
+ if (!response.ok) {
123
+ const error = await response.json().catch(() => ({}));
124
+ throw new Error(error.message || `HTTP ${response.status}`);
125
+ }
126
+ return response.json();
127
+ }
128
+ log(...args) {
129
+ if (this.config.debug) {
130
+ console.log("[CourseAI]", ...args);
131
+ }
132
+ }
133
+ };
134
+
135
+ // src/core/client.ts
136
+ var WidgetClient = class {
137
+ constructor(config) {
138
+ this.state = { status: "idle" };
139
+ this.events = new TypedEventEmitter();
140
+ this.config = config;
141
+ this.api = new WidgetAPI(config);
142
+ }
143
+ /**
144
+ * Initialize the widget and create a chat session
145
+ */
146
+ async initialize() {
147
+ if (this.state.status !== "idle") {
148
+ throw new Error("Widget already initialized");
149
+ }
150
+ this.setState({ status: "initializing" });
151
+ try {
152
+ const session = await this.api.createSession();
153
+ this.setState({ status: "ready", session });
154
+ this.events.emit("session:created", { session });
155
+ } catch (error) {
156
+ const widgetError = {
157
+ code: "INIT_FAILED",
158
+ message: error instanceof Error ? error.message : "Unknown error",
159
+ details: error
160
+ };
161
+ this.setState({ status: "error", error: widgetError });
162
+ this.events.emit("error", { error: widgetError });
163
+ throw error;
164
+ }
165
+ }
166
+ /**
167
+ * Send a message to the AI assistant
168
+ */
169
+ async sendMessage(content) {
170
+ if (this.state.status !== "ready") {
171
+ throw new Error("Widget not ready. Call initialize() first.");
172
+ }
173
+ const userMessage = {
174
+ id: crypto.randomUUID(),
175
+ role: "user",
176
+ content,
177
+ timestamp: Date.now()
178
+ };
179
+ const session = {
180
+ ...this.state.session,
181
+ messages: [...this.state.session.messages, userMessage]
182
+ };
183
+ this.setState({ status: "ready", session });
184
+ this.events.emit("message:sent", { message: userMessage });
185
+ this.setState({ status: "loading" });
186
+ try {
187
+ const assistantMessage = await this.api.sendMessage(
188
+ session.id,
189
+ content
190
+ );
191
+ const updatedSession = {
192
+ ...session,
193
+ messages: [...session.messages, assistantMessage]
194
+ };
195
+ this.setState({ status: "ready", session: updatedSession });
196
+ this.events.emit("message:received", { message: assistantMessage });
197
+ return assistantMessage;
198
+ } catch (error) {
199
+ const widgetError = {
200
+ code: "SEND_MESSAGE_FAILED",
201
+ message: error instanceof Error ? error.message : "Failed to send message",
202
+ details: error
203
+ };
204
+ this.setState({ status: "ready", session });
205
+ this.events.emit("error", { error: widgetError });
206
+ throw error;
207
+ }
208
+ }
209
+ /**
210
+ * Get current state
211
+ */
212
+ getState() {
213
+ return this.state;
214
+ }
215
+ /**
216
+ * Get the API instance for direct calls
217
+ */
218
+ getAPI() {
219
+ return this.api;
220
+ }
221
+ /**
222
+ * Get the widget configuration
223
+ */
224
+ getConfig() {
225
+ return this.config;
226
+ }
227
+ /**
228
+ * Subscribe to events
229
+ */
230
+ on(event, handler) {
231
+ return this.events.on(event, handler);
232
+ }
233
+ /**
234
+ * Unsubscribe from events
235
+ */
236
+ off(event, handler) {
237
+ this.events.off(event, handler);
238
+ }
239
+ /**
240
+ * Clean up resources
241
+ */
242
+ destroy() {
243
+ this.events.clear();
244
+ this.setState({ status: "idle" });
245
+ }
246
+ setState(newState) {
247
+ const previous = this.state;
248
+ this.state = newState;
249
+ this.events.emit("state:change", { previous, current: newState });
250
+ }
251
+ };
252
+ function cn(...inputs) {
253
+ return twMerge(clsx(inputs));
254
+ }
255
+ function TooltipProvider({
256
+ delayDuration = 0,
257
+ ...props
258
+ }) {
259
+ return /* @__PURE__ */ jsx(
260
+ TooltipPrimitive.Provider,
261
+ {
262
+ "data-slot": "tooltip-provider",
263
+ delayDuration,
264
+ ...props
265
+ }
266
+ );
267
+ }
268
+ function Tooltip({
269
+ ...props
270
+ }) {
271
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
272
+ }
273
+ function TooltipTrigger({
274
+ ...props
275
+ }) {
276
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
277
+ }
278
+ function TooltipContent({
279
+ className,
280
+ sideOffset = 0,
281
+ children,
282
+ ...props
283
+ }) {
284
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
285
+ TooltipPrimitive.Content,
286
+ {
287
+ "data-slot": "tooltip-content",
288
+ sideOffset,
289
+ className: cn(
290
+ "bg-foreground text-background 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",
291
+ className
292
+ ),
293
+ ...props,
294
+ children: [
295
+ children,
296
+ /* @__PURE__ */ jsx(TooltipPrimitive.Arrow, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
297
+ ]
298
+ }
299
+ ) });
300
+ }
301
+ var buttonVariants = cva(
302
+ "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",
303
+ {
304
+ variants: {
305
+ variant: {
306
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
307
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
308
+ 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",
309
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
310
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
311
+ link: "text-primary underline-offset-4 hover:underline"
312
+ },
313
+ size: {
314
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
315
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
316
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
317
+ icon: "size-9",
318
+ "icon-sm": "size-8",
319
+ "icon-lg": "size-10"
320
+ }
321
+ },
322
+ defaultVariants: {
323
+ variant: "default",
324
+ size: "default"
325
+ }
326
+ }
327
+ );
328
+ var Button = React.forwardRef(({ className, variant = "default", size = "default", asChild = false, ...props }, ref) => {
329
+ const Comp = asChild ? Slot : "button";
330
+ return /* @__PURE__ */ jsx(
331
+ Comp,
332
+ {
333
+ ref,
334
+ "data-slot": "button",
335
+ "data-variant": variant,
336
+ "data-size": size,
337
+ className: cn(buttonVariants({ variant, size, className })),
338
+ ...props
339
+ }
340
+ );
341
+ });
342
+ Button.displayName = "Button";
343
+ var TooltipIconButton = forwardRef(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
344
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
345
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "icon-sm", ...rest, ref, children: [
346
+ /* @__PURE__ */ jsx(Slottable, { children }),
347
+ /* @__PURE__ */ jsx("span", { className: "aui-sr-only sr-only", children: tooltip })
348
+ ] }) }),
349
+ /* @__PURE__ */ jsx(TooltipContent, { side, children: tooltip })
350
+ ] });
351
+ });
352
+ TooltipIconButton.displayName = "TooltipIconButton";
353
+ var ToolCard = ({
354
+ title,
355
+ subtitle,
356
+ isStreaming,
357
+ isError = false,
358
+ icon,
359
+ persistentContent,
360
+ children,
361
+ footer
362
+ }) => {
363
+ const [manualExpanded, setManualExpanded] = useState(null);
364
+ const prevStreamingRef = useRef(isStreaming);
365
+ const contentRef = useRef(null);
366
+ const isExpanded = manualExpanded ?? isStreaming;
367
+ useEffect(() => {
368
+ if (isStreaming && !prevStreamingRef.current) {
369
+ setManualExpanded(null);
370
+ }
371
+ prevStreamingRef.current = isStreaming;
372
+ }, [isStreaming]);
373
+ useEffect(() => {
374
+ if (isStreaming && contentRef.current) {
375
+ contentRef.current.scrollTop = contentRef.current.scrollHeight;
376
+ }
377
+ });
378
+ const renderIcon = () => {
379
+ if (icon) return icon;
380
+ const iconClass = cn("h-4 w-4", isStreaming && "animate-spin");
381
+ if (isStreaming) {
382
+ return /* @__PURE__ */ jsx(Loader2Icon, { className: iconClass });
383
+ }
384
+ if (isError) {
385
+ return /* @__PURE__ */ jsx(XCircleIcon, { className: "h-4 w-4 text-red-400" });
386
+ }
387
+ return /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4" });
388
+ };
389
+ const handleToggle = () => {
390
+ if (!isStreaming) {
391
+ setManualExpanded((prev2) => prev2 === null ? true : !prev2);
392
+ }
393
+ };
394
+ return /* @__PURE__ */ jsxs("div", { className: "my-2 overflow-hidden rounded-xl border border-border shadow-sm", children: [
395
+ /* @__PURE__ */ jsxs(
396
+ "div",
397
+ {
398
+ className: cn(
399
+ "flex items-center gap-2 p-2 cursor-pointer transition-colors text-white bg-primary-foreground",
400
+ !isStreaming && "hover:opacity-90"
401
+ ),
402
+ onClick: handleToggle,
403
+ children: [
404
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: renderIcon() }),
405
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
406
+ subtitle && /* @__PURE__ */ jsx("p", { className: "font-medium opacity-80 leading-tight text-xs text-muted-foreground", children: subtitle }),
407
+ /* @__PURE__ */ jsx("h4", { className: "truncate font-semibold leading-tight text-sm text-muted-foreground", children: title })
408
+ ] }),
409
+ /* @__PURE__ */ jsx(
410
+ "button",
411
+ {
412
+ className: "p-1 rounded hover:bg-white/20 transition-colors",
413
+ "aria-label": isExpanded ? "Collapse" : "Expand",
414
+ onClick: (e) => {
415
+ e.stopPropagation();
416
+ handleToggle();
417
+ },
418
+ children: isExpanded ? /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4" })
419
+ }
420
+ )
421
+ ]
422
+ }
423
+ ),
424
+ persistentContent,
425
+ isExpanded && /* @__PURE__ */ jsx(
426
+ "div",
427
+ {
428
+ ref: contentRef,
429
+ className: "p-2 max-h-[400px] overflow-y-auto bg-secondary",
430
+ children
431
+ }
432
+ ),
433
+ isExpanded && footer && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-2 border-t border-white/10 p-2 bg-primary-foreground/80", children: footer })
434
+ ] });
435
+ };
436
+ var useCopyToClipboard = ({
437
+ copiedDuration = 3e3
438
+ } = {}) => {
439
+ const [isCopied, setIsCopied] = useState(false);
440
+ const copyToClipboard = (value) => {
441
+ if (!value) return;
442
+ navigator.clipboard.writeText(value).then(() => {
443
+ setIsCopied(true);
444
+ setTimeout(() => setIsCopied(false), copiedDuration);
445
+ });
446
+ };
447
+ return { isCopied, copyToClipboard };
448
+ };
449
+ var MarkdownContent = memo(({ content }) => {
450
+ return /* @__PURE__ */ jsx("div", { className: "aui-md max-w-none text-white", children: /* @__PURE__ */ jsx(
451
+ ReactMarkdown,
452
+ {
453
+ remarkPlugins: [remarkGfm],
454
+ components: {
455
+ h1: ({ className, ...props }) => /* @__PURE__ */ jsx(
456
+ "h1",
457
+ {
458
+ className: cn(
459
+ "mb-2 font-extrabold tracking-tight last:mb-0 text-white",
460
+ className
461
+ ),
462
+ style: { fontSize: "12px" },
463
+ ...props
464
+ }
465
+ ),
466
+ h2: ({ className, ...props }) => /* @__PURE__ */ jsx(
467
+ "h2",
468
+ {
469
+ className: cn(
470
+ "mt-3 mb-1.5 font-semibold tracking-tight first:mt-0 last:mb-0 text-white",
471
+ className
472
+ ),
473
+ style: { fontSize: "10px" },
474
+ ...props
475
+ }
476
+ ),
477
+ h3: ({ className, ...props }) => /* @__PURE__ */ jsx(
478
+ "h3",
479
+ {
480
+ className: cn(
481
+ "mt-2 mb-1 font-semibold tracking-tight first:mt-0 last:mb-0 text-white",
482
+ className
483
+ ),
484
+ style: { fontSize: "9px" },
485
+ ...props
486
+ }
487
+ ),
488
+ p: ({ className, ...props }) => /* @__PURE__ */ jsx(
489
+ "p",
490
+ {
491
+ className: cn(
492
+ "mt-1.5 mb-1.5 leading-relaxed first:mt-0 last:mb-0 text-white/90",
493
+ className
494
+ ),
495
+ ...props
496
+ }
497
+ ),
498
+ ul: ({ className, ...props }) => /* @__PURE__ */ jsx(
499
+ "ul",
500
+ {
501
+ className: cn(
502
+ "my-1.5 ml-3 list-disc [&>li]:mt-0.5 text-white/90",
503
+ className
504
+ ),
505
+ ...props
506
+ }
507
+ ),
508
+ ol: ({ className, ...props }) => /* @__PURE__ */ jsx(
509
+ "ol",
510
+ {
511
+ className: cn(
512
+ "my-1.5 ml-3 list-decimal [&>li]:mt-0.5 text-white/90",
513
+ className
514
+ ),
515
+ ...props
516
+ }
517
+ ),
518
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ jsx(
519
+ "blockquote",
520
+ {
521
+ className: cn(
522
+ "border-l-2 border-white/30 pl-2 italic text-white/70",
523
+ className
524
+ ),
525
+ ...props
526
+ }
527
+ ),
528
+ pre: ({ className, ...props }) => /* @__PURE__ */ jsx(
529
+ "pre",
530
+ {
531
+ className: cn(
532
+ "overflow-x-auto rounded bg-black/30 p-1.5 text-white/90 my-1.5",
533
+ className
534
+ ),
535
+ ...props
536
+ }
537
+ ),
538
+ code: ({ className, ...props }) => {
539
+ const isInline = !className?.includes("language-");
540
+ return /* @__PURE__ */ jsx(
541
+ "code",
542
+ {
543
+ className: cn(
544
+ isInline && "rounded bg-black/30 px-0.5 py-0.5 font-mono text-white/90",
545
+ className
546
+ ),
547
+ ...props
548
+ }
549
+ );
550
+ },
551
+ a: ({ className, ...props }) => /* @__PURE__ */ jsx(
552
+ "a",
553
+ {
554
+ className: cn(
555
+ "font-medium text-blue-300 underline underline-offset-2",
556
+ className
557
+ ),
558
+ target: "_blank",
559
+ rel: "noopener noreferrer",
560
+ ...props
561
+ }
562
+ ),
563
+ hr: ({ className, ...props }) => /* @__PURE__ */ jsx(
564
+ "hr",
565
+ {
566
+ className: cn("my-2 border-b border-white/20", className),
567
+ ...props
568
+ }
569
+ )
570
+ },
571
+ children: content
572
+ }
573
+ ) });
574
+ });
575
+ MarkdownContent.displayName = "MarkdownContent";
576
+ var DetailedAnswerToolUI = makeAssistantToolUI({
577
+ toolName: "generateDetailedAnswer",
578
+ render: function DetailedAnswerUI({ args, result, status }) {
579
+ const { isCopied, copyToClipboard } = useCopyToClipboard();
580
+ const isStreaming = status.type === "running";
581
+ const isError = status.type === "incomplete";
582
+ const title = result?.title || args.title || "Generating...";
583
+ const content = result?.content || args.content || "";
584
+ const summary = result?.summary || args.summary || "";
585
+ const handleCopy = () => {
586
+ if (content) {
587
+ copyToClipboard(content);
588
+ }
589
+ };
590
+ const handleOpenFullScreen = () => {
591
+ const newWindow = window.open("", "_blank");
592
+ if (newWindow) {
593
+ newWindow.document.write(`
594
+ <!DOCTYPE html>
595
+ <html>
596
+ <head>
597
+ <title>${title}</title>
598
+ <meta charset="utf-8">
599
+ <meta name="viewport" content="width=device-width, initial-scale=1">
600
+ <style>
601
+ body {
602
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
603
+ max-width: 800px;
604
+ margin: 0 auto;
605
+ padding: 2rem;
606
+ line-height: 1.6;
607
+ color: #1a1a1a;
608
+ }
609
+ h1 { border-bottom: 1px solid #eee; padding-bottom: 0.5rem; }
610
+ pre { background: #f5f5f5; padding: 1rem; overflow-x: auto; border-radius: 4px; }
611
+ code { background: #f5f5f5; padding: 0.2em 0.4em; border-radius: 3px; font-size: 0.9em; }
612
+ pre code { background: none; padding: 0; }
613
+ blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 1rem; color: #666; }
614
+ </style>
615
+ </head>
616
+ <body>
617
+ <h1>${title}</h1>
618
+ <div id="content">${content.replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>
619
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
620
+ <script>
621
+ document.getElementById('content').innerHTML = marked.parse(${JSON.stringify(
622
+ content
623
+ )});
624
+ </script>
625
+ </body>
626
+ </html>
627
+ `);
628
+ newWindow.document.close();
629
+ }
630
+ };
631
+ const persistentSummary = summary ? /* @__PURE__ */ jsx("div", { className: "p-2 text-white/80 border-b border-white/10 bg-primary-foreground text-xs", children: summary }) : void 0;
632
+ const footerActions = content ? /* @__PURE__ */ jsxs(Fragment, { children: [
633
+ /* @__PURE__ */ jsx(
634
+ TooltipIconButton,
635
+ {
636
+ tooltip: isCopied ? "Copied!" : "Copy markdown",
637
+ onClick: handleCopy,
638
+ className: "flex items-center justify-center rounded-md p-1.5 text-white/70 hover:bg-white/10 transition-colors",
639
+ children: isCopied ? /* @__PURE__ */ jsx(CheckIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(CopyIcon, { className: "h-3.5 w-3.5" })
640
+ }
641
+ ),
642
+ /* @__PURE__ */ jsx(
643
+ TooltipIconButton,
644
+ {
645
+ tooltip: "Open in new window",
646
+ onClick: handleOpenFullScreen,
647
+ className: "flex items-center justify-center rounded-md p-1.5 text-white/70 hover:bg-white/10 transition-colors",
648
+ children: /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "h-3.5 w-3.5" })
649
+ }
650
+ )
651
+ ] }) : void 0;
652
+ return /* @__PURE__ */ jsx(
653
+ ToolCard,
654
+ {
655
+ title,
656
+ isStreaming,
657
+ isError,
658
+ icon: !isStreaming && !isError ? /* @__PURE__ */ jsx(FileTextIcon, { className: "h-4 w-4" }) : void 0,
659
+ persistentContent: persistentSummary,
660
+ footer: footerActions,
661
+ children: content ? /* @__PURE__ */ jsx(MarkdownContent, { content }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground italic", children: "Generating content..." })
662
+ }
663
+ );
664
+ }
665
+ });
666
+ var MessageContext = createContext(null);
667
+ function MessageContextProvider({ children }) {
668
+ const [selectedContext, setSelectedContext] = useState([]);
669
+ const addContextItem = useCallback((item) => {
670
+ console.log("[MessageContext] Adding context item:", item.id, item.title);
671
+ setSelectedContext((prev2) => {
672
+ if (prev2.some((i) => i.id === item.id)) {
673
+ console.log("[MessageContext] Item already exists, skipping");
674
+ return prev2;
675
+ }
676
+ console.log("[MessageContext] Context items count:", prev2.length + 1);
677
+ return [...prev2, item];
678
+ });
679
+ }, []);
680
+ const removeContextItem = useCallback((id) => {
681
+ setSelectedContext((prev2) => prev2.filter((item) => item.id !== id));
682
+ }, []);
683
+ const clearContext = useCallback(() => {
684
+ console.log("[MessageContext] Clearing context");
685
+ setSelectedContext([]);
686
+ }, []);
687
+ const setContext = useCallback((items) => {
688
+ setSelectedContext(items);
689
+ }, []);
690
+ const consumeContext = useCallback(() => {
691
+ const context = selectedContext;
692
+ console.log("[MessageContext] Consuming context:", context.length, "items");
693
+ return context;
694
+ }, [selectedContext]);
695
+ return /* @__PURE__ */ jsx(
696
+ MessageContext.Provider,
697
+ {
698
+ value: {
699
+ selectedContext,
700
+ addContextItem,
701
+ removeContextItem,
702
+ clearContext,
703
+ setContext,
704
+ consumeContext
705
+ },
706
+ children
707
+ }
708
+ );
709
+ }
710
+ function useMessageContext() {
711
+ const context = useContext(MessageContext);
712
+ if (!context) {
713
+ throw new Error(
714
+ "useMessageContext must be used within a MessageContextProvider"
715
+ );
716
+ }
717
+ return context;
718
+ }
719
+
720
+ // src/react/styles/theme.ts
721
+ var theme = {
722
+ colors: {
723
+ background: {
724
+ primary: "#1a1a1a",
725
+ secondary: "#2a2a2a",
726
+ tertiary: "#3a3a3a"
727
+ },
728
+ accent: {
729
+ primary: "#c9a227",
730
+ hover: "#d4af37",
731
+ muted: "rgba(201, 162, 39, 0.4)"
732
+ },
733
+ text: {
734
+ primary: "#ffffff",
735
+ secondary: "#888888",
736
+ tertiary: "#cccccc",
737
+ inverse: "#1a1a1a"
738
+ },
739
+ border: "#2a2a2a",
740
+ shadow: "rgba(0, 0, 0, 0.4)"
741
+ },
742
+ spacing: {
743
+ xs: "0.25rem",
744
+ sm: "0.5rem",
745
+ md: "1rem",
746
+ lg: "1.5rem",
747
+ xl: "2rem",
748
+ "2xl": "3rem"
749
+ },
750
+ radii: {
751
+ sm: "0.5rem",
752
+ md: "0.75rem",
753
+ lg: "1rem",
754
+ xl: "1.5rem",
755
+ full: "50%"
756
+ },
757
+ typography: {
758
+ fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
759
+ fontSize: {
760
+ xs: "0.75rem",
761
+ sm: "0.875rem",
762
+ md: "1rem",
763
+ lg: "1.125rem",
764
+ xl: "1.25rem",
765
+ "2xl": "1.5rem"
766
+ },
767
+ fontWeight: {
768
+ normal: 400,
769
+ medium: 500,
770
+ semibold: 600,
771
+ bold: 700
772
+ },
773
+ lineHeight: {
774
+ tight: 1.25,
775
+ normal: 1.5,
776
+ relaxed: 1.7
777
+ }
778
+ },
779
+ zIndex: {
780
+ widget: 9999,
781
+ overlay: 9998
782
+ },
783
+ shadows: {
784
+ sm: "0 2px 8px rgba(0, 0, 0, 0.2)",
785
+ md: "0 4px 16px rgba(0, 0, 0, 0.3)",
786
+ lg: "0 8px 32px rgba(0, 0, 0, 0.4)",
787
+ accent: "0 4px 16px rgba(201, 162, 39, 0.4)",
788
+ accentHover: "0 6px 20px rgba(201, 162, 39, 0.5)"
789
+ },
790
+ transitions: {
791
+ fast: "0.15s ease",
792
+ normal: "0.2s ease",
793
+ slow: "0.3s ease"
794
+ }
795
+ };
796
+ function sheetForTag(tag) {
797
+ if (tag.sheet) {
798
+ return tag.sheet;
799
+ }
800
+ for (var i = 0; i < document.styleSheets.length; i++) {
801
+ if (document.styleSheets[i].ownerNode === tag) {
802
+ return document.styleSheets[i];
803
+ }
804
+ }
805
+ return void 0;
806
+ }
807
+ function createStyleElement(options) {
808
+ var tag = document.createElement("style");
809
+ tag.setAttribute("data-emotion", options.key);
810
+ if (options.nonce !== void 0) {
811
+ tag.setAttribute("nonce", options.nonce);
812
+ }
813
+ tag.appendChild(document.createTextNode(""));
814
+ tag.setAttribute("data-s", "");
815
+ return tag;
816
+ }
817
+ var StyleSheet = /* @__PURE__ */ (function() {
818
+ function StyleSheet2(options) {
819
+ var _this = this;
820
+ this._insertTag = function(tag) {
821
+ var before;
822
+ if (_this.tags.length === 0) {
823
+ if (_this.insertionPoint) {
824
+ before = _this.insertionPoint.nextSibling;
825
+ } else if (_this.prepend) {
826
+ before = _this.container.firstChild;
827
+ } else {
828
+ before = _this.before;
829
+ }
830
+ } else {
831
+ before = _this.tags[_this.tags.length - 1].nextSibling;
832
+ }
833
+ _this.container.insertBefore(tag, before);
834
+ _this.tags.push(tag);
835
+ };
836
+ this.isSpeedy = options.speedy === void 0 ? true : options.speedy;
837
+ this.tags = [];
838
+ this.ctr = 0;
839
+ this.nonce = options.nonce;
840
+ this.key = options.key;
841
+ this.container = options.container;
842
+ this.prepend = options.prepend;
843
+ this.insertionPoint = options.insertionPoint;
844
+ this.before = null;
845
+ }
846
+ var _proto = StyleSheet2.prototype;
847
+ _proto.hydrate = function hydrate(nodes) {
848
+ nodes.forEach(this._insertTag);
849
+ };
850
+ _proto.insert = function insert(rule) {
851
+ if (this.ctr % (this.isSpeedy ? 65e3 : 1) === 0) {
852
+ this._insertTag(createStyleElement(this));
853
+ }
854
+ var tag = this.tags[this.tags.length - 1];
855
+ if (this.isSpeedy) {
856
+ var sheet = sheetForTag(tag);
857
+ try {
858
+ sheet.insertRule(rule, sheet.cssRules.length);
859
+ } catch (e) {
860
+ }
861
+ } else {
862
+ tag.appendChild(document.createTextNode(rule));
863
+ }
864
+ this.ctr++;
865
+ };
866
+ _proto.flush = function flush() {
867
+ this.tags.forEach(function(tag) {
868
+ var _tag$parentNode;
869
+ return (_tag$parentNode = tag.parentNode) == null ? void 0 : _tag$parentNode.removeChild(tag);
870
+ });
871
+ this.tags = [];
872
+ this.ctr = 0;
873
+ };
874
+ return StyleSheet2;
875
+ })();
876
+
877
+ // ../../node_modules/stylis/src/Enum.js
878
+ var MS = "-ms-";
879
+ var MOZ = "-moz-";
880
+ var WEBKIT = "-webkit-";
881
+ var COMMENT = "comm";
882
+ var RULESET = "rule";
883
+ var DECLARATION = "decl";
884
+ var IMPORT = "@import";
885
+ var KEYFRAMES = "@keyframes";
886
+ var LAYER = "@layer";
887
+
888
+ // ../../node_modules/stylis/src/Utility.js
889
+ var abs = Math.abs;
890
+ var from = String.fromCharCode;
891
+ var assign = Object.assign;
892
+ function hash(value, length2) {
893
+ return charat(value, 0) ^ 45 ? (((length2 << 2 ^ charat(value, 0)) << 2 ^ charat(value, 1)) << 2 ^ charat(value, 2)) << 2 ^ charat(value, 3) : 0;
894
+ }
895
+ function trim(value) {
896
+ return value.trim();
897
+ }
898
+ function match(value, pattern) {
899
+ return (value = pattern.exec(value)) ? value[0] : value;
900
+ }
901
+ function replace(value, pattern, replacement) {
902
+ return value.replace(pattern, replacement);
903
+ }
904
+ function indexof(value, search) {
905
+ return value.indexOf(search);
906
+ }
907
+ function charat(value, index) {
908
+ return value.charCodeAt(index) | 0;
909
+ }
910
+ function substr(value, begin, end) {
911
+ return value.slice(begin, end);
912
+ }
913
+ function strlen(value) {
914
+ return value.length;
915
+ }
916
+ function sizeof(value) {
917
+ return value.length;
918
+ }
919
+ function append(value, array) {
920
+ return array.push(value), value;
921
+ }
922
+ function combine(array, callback) {
923
+ return array.map(callback).join("");
924
+ }
925
+
926
+ // ../../node_modules/stylis/src/Tokenizer.js
927
+ var line = 1;
928
+ var column = 1;
929
+ var length = 0;
930
+ var position = 0;
931
+ var character = 0;
932
+ var characters = "";
933
+ function node(value, root, parent, type, props, children, length2) {
934
+ return { value, root, parent, type, props, children, line, column, length: length2, return: "" };
935
+ }
936
+ function copy(root, props) {
937
+ return assign(node("", null, null, "", null, null, 0), root, { length: -root.length }, props);
938
+ }
939
+ function char() {
940
+ return character;
941
+ }
942
+ function prev() {
943
+ character = position > 0 ? charat(characters, --position) : 0;
944
+ if (column--, character === 10)
945
+ column = 1, line--;
946
+ return character;
947
+ }
948
+ function next() {
949
+ character = position < length ? charat(characters, position++) : 0;
950
+ if (column++, character === 10)
951
+ column = 1, line++;
952
+ return character;
953
+ }
954
+ function peek() {
955
+ return charat(characters, position);
956
+ }
957
+ function caret() {
958
+ return position;
959
+ }
960
+ function slice(begin, end) {
961
+ return substr(characters, begin, end);
962
+ }
963
+ function token(type) {
964
+ switch (type) {
965
+ // \0 \t \n \r \s whitespace token
966
+ case 0:
967
+ case 9:
968
+ case 10:
969
+ case 13:
970
+ case 32:
971
+ return 5;
972
+ // ! + , / > @ ~ isolate token
973
+ case 33:
974
+ case 43:
975
+ case 44:
976
+ case 47:
977
+ case 62:
978
+ case 64:
979
+ case 126:
980
+ // ; { } breakpoint token
981
+ case 59:
982
+ case 123:
983
+ case 125:
984
+ return 4;
985
+ // : accompanied token
986
+ case 58:
987
+ return 3;
988
+ // " ' ( [ opening delimit token
989
+ case 34:
990
+ case 39:
991
+ case 40:
992
+ case 91:
993
+ return 2;
994
+ // ) ] closing delimit token
995
+ case 41:
996
+ case 93:
997
+ return 1;
998
+ }
999
+ return 0;
1000
+ }
1001
+ function alloc(value) {
1002
+ return line = column = 1, length = strlen(characters = value), position = 0, [];
1003
+ }
1004
+ function dealloc(value) {
1005
+ return characters = "", value;
1006
+ }
1007
+ function delimit(type) {
1008
+ return trim(slice(position - 1, delimiter(type === 91 ? type + 2 : type === 40 ? type + 1 : type)));
1009
+ }
1010
+ function whitespace(type) {
1011
+ while (character = peek())
1012
+ if (character < 33)
1013
+ next();
1014
+ else
1015
+ break;
1016
+ return token(type) > 2 || token(character) > 3 ? "" : " ";
1017
+ }
1018
+ function escaping(index, count) {
1019
+ while (--count && next())
1020
+ if (character < 48 || character > 102 || character > 57 && character < 65 || character > 70 && character < 97)
1021
+ break;
1022
+ return slice(index, caret() + (count < 6 && peek() == 32 && next() == 32));
1023
+ }
1024
+ function delimiter(type) {
1025
+ while (next())
1026
+ switch (character) {
1027
+ // ] ) " '
1028
+ case type:
1029
+ return position;
1030
+ // " '
1031
+ case 34:
1032
+ case 39:
1033
+ if (type !== 34 && type !== 39)
1034
+ delimiter(character);
1035
+ break;
1036
+ // (
1037
+ case 40:
1038
+ if (type === 41)
1039
+ delimiter(type);
1040
+ break;
1041
+ // \
1042
+ case 92:
1043
+ next();
1044
+ break;
1045
+ }
1046
+ return position;
1047
+ }
1048
+ function commenter(type, index) {
1049
+ while (next())
1050
+ if (type + character === 47 + 10)
1051
+ break;
1052
+ else if (type + character === 42 + 42 && peek() === 47)
1053
+ break;
1054
+ return "/*" + slice(index, position - 1) + "*" + from(type === 47 ? type : next());
1055
+ }
1056
+ function identifier(index) {
1057
+ while (!token(peek()))
1058
+ next();
1059
+ return slice(index, position);
1060
+ }
1061
+
1062
+ // ../../node_modules/stylis/src/Parser.js
1063
+ function compile(value) {
1064
+ return dealloc(parse("", null, null, null, [""], value = alloc(value), 0, [0], value));
1065
+ }
1066
+ function parse(value, root, parent, rule, rules, rulesets, pseudo, points, declarations) {
1067
+ var index = 0;
1068
+ var offset = 0;
1069
+ var length2 = pseudo;
1070
+ var atrule = 0;
1071
+ var property = 0;
1072
+ var previous = 0;
1073
+ var variable = 1;
1074
+ var scanning = 1;
1075
+ var ampersand = 1;
1076
+ var character2 = 0;
1077
+ var type = "";
1078
+ var props = rules;
1079
+ var children = rulesets;
1080
+ var reference = rule;
1081
+ var characters2 = type;
1082
+ while (scanning)
1083
+ switch (previous = character2, character2 = next()) {
1084
+ // (
1085
+ case 40:
1086
+ if (previous != 108 && charat(characters2, length2 - 1) == 58) {
1087
+ if (indexof(characters2 += replace(delimit(character2), "&", "&\f"), "&\f") != -1)
1088
+ ampersand = -1;
1089
+ break;
1090
+ }
1091
+ // " ' [
1092
+ case 34:
1093
+ case 39:
1094
+ case 91:
1095
+ characters2 += delimit(character2);
1096
+ break;
1097
+ // \t \n \r \s
1098
+ case 9:
1099
+ case 10:
1100
+ case 13:
1101
+ case 32:
1102
+ characters2 += whitespace(previous);
1103
+ break;
1104
+ // \
1105
+ case 92:
1106
+ characters2 += escaping(caret() - 1, 7);
1107
+ continue;
1108
+ // /
1109
+ case 47:
1110
+ switch (peek()) {
1111
+ case 42:
1112
+ case 47:
1113
+ append(comment(commenter(next(), caret()), root, parent), declarations);
1114
+ break;
1115
+ default:
1116
+ characters2 += "/";
1117
+ }
1118
+ break;
1119
+ // {
1120
+ case 123 * variable:
1121
+ points[index++] = strlen(characters2) * ampersand;
1122
+ // } ; \0
1123
+ case 125 * variable:
1124
+ case 59:
1125
+ case 0:
1126
+ switch (character2) {
1127
+ // \0 }
1128
+ case 0:
1129
+ case 125:
1130
+ scanning = 0;
1131
+ // ;
1132
+ case 59 + offset:
1133
+ if (ampersand == -1) characters2 = replace(characters2, /\f/g, "");
1134
+ if (property > 0 && strlen(characters2) - length2)
1135
+ append(property > 32 ? declaration(characters2 + ";", rule, parent, length2 - 1) : declaration(replace(characters2, " ", "") + ";", rule, parent, length2 - 2), declarations);
1136
+ break;
1137
+ // @ ;
1138
+ case 59:
1139
+ characters2 += ";";
1140
+ // { rule/at-rule
1141
+ default:
1142
+ append(reference = ruleset(characters2, root, parent, index, offset, rules, points, type, props = [], children = [], length2), rulesets);
1143
+ if (character2 === 123)
1144
+ if (offset === 0)
1145
+ parse(characters2, root, reference, reference, props, rulesets, length2, points, children);
1146
+ else
1147
+ switch (atrule === 99 && charat(characters2, 3) === 110 ? 100 : atrule) {
1148
+ // d l m s
1149
+ case 100:
1150
+ case 108:
1151
+ case 109:
1152
+ case 115:
1153
+ parse(value, reference, reference, rule && append(ruleset(value, reference, reference, 0, 0, rules, points, type, rules, props = [], length2), children), rules, children, length2, points, rule ? props : children);
1154
+ break;
1155
+ default:
1156
+ parse(characters2, reference, reference, reference, [""], children, 0, points, children);
1157
+ }
1158
+ }
1159
+ index = offset = property = 0, variable = ampersand = 1, type = characters2 = "", length2 = pseudo;
1160
+ break;
1161
+ // :
1162
+ case 58:
1163
+ length2 = 1 + strlen(characters2), property = previous;
1164
+ default:
1165
+ if (variable < 1) {
1166
+ if (character2 == 123)
1167
+ --variable;
1168
+ else if (character2 == 125 && variable++ == 0 && prev() == 125)
1169
+ continue;
1170
+ }
1171
+ switch (characters2 += from(character2), character2 * variable) {
1172
+ // &
1173
+ case 38:
1174
+ ampersand = offset > 0 ? 1 : (characters2 += "\f", -1);
1175
+ break;
1176
+ // ,
1177
+ case 44:
1178
+ points[index++] = (strlen(characters2) - 1) * ampersand, ampersand = 1;
1179
+ break;
1180
+ // @
1181
+ case 64:
1182
+ if (peek() === 45)
1183
+ characters2 += delimit(next());
1184
+ atrule = peek(), offset = length2 = strlen(type = characters2 += identifier(caret())), character2++;
1185
+ break;
1186
+ // -
1187
+ case 45:
1188
+ if (previous === 45 && strlen(characters2) == 2)
1189
+ variable = 0;
1190
+ }
1191
+ }
1192
+ return rulesets;
1193
+ }
1194
+ function ruleset(value, root, parent, index, offset, rules, points, type, props, children, length2) {
1195
+ var post = offset - 1;
1196
+ var rule = offset === 0 ? rules : [""];
1197
+ var size = sizeof(rule);
1198
+ for (var i = 0, j = 0, k = 0; i < index; ++i)
1199
+ for (var x = 0, y = substr(value, post + 1, post = abs(j = points[i])), z = value; x < size; ++x)
1200
+ if (z = trim(j > 0 ? rule[x] + " " + y : replace(y, /&\f/g, rule[x])))
1201
+ props[k++] = z;
1202
+ return node(value, root, parent, offset === 0 ? RULESET : type, props, children, length2);
1203
+ }
1204
+ function comment(value, root, parent) {
1205
+ return node(value, root, parent, COMMENT, from(char()), substr(value, 2, -2), 0);
1206
+ }
1207
+ function declaration(value, root, parent, length2) {
1208
+ return node(value, root, parent, DECLARATION, substr(value, 0, length2), substr(value, length2 + 1, -1), length2);
1209
+ }
1210
+
1211
+ // ../../node_modules/stylis/src/Serializer.js
1212
+ function serialize(children, callback) {
1213
+ var output = "";
1214
+ var length2 = sizeof(children);
1215
+ for (var i = 0; i < length2; i++)
1216
+ output += callback(children[i], i, children, callback) || "";
1217
+ return output;
1218
+ }
1219
+ function stringify(element, index, children, callback) {
1220
+ switch (element.type) {
1221
+ case LAYER:
1222
+ if (element.children.length) break;
1223
+ case IMPORT:
1224
+ case DECLARATION:
1225
+ return element.return = element.return || element.value;
1226
+ case COMMENT:
1227
+ return "";
1228
+ case KEYFRAMES:
1229
+ return element.return = element.value + "{" + serialize(element.children, callback) + "}";
1230
+ case RULESET:
1231
+ element.value = element.props.join(",");
1232
+ }
1233
+ return strlen(children = serialize(element.children, callback)) ? element.return = element.value + "{" + children + "}" : "";
1234
+ }
1235
+
1236
+ // ../../node_modules/stylis/src/Middleware.js
1237
+ function middleware(collection) {
1238
+ var length2 = sizeof(collection);
1239
+ return function(element, index, children, callback) {
1240
+ var output = "";
1241
+ for (var i = 0; i < length2; i++)
1242
+ output += collection[i](element, index, children, callback) || "";
1243
+ return output;
1244
+ };
1245
+ }
1246
+ function rulesheet(callback) {
1247
+ return function(element) {
1248
+ if (!element.root) {
1249
+ if (element = element.return)
1250
+ callback(element);
1251
+ }
1252
+ };
1253
+ }
1254
+
1255
+ // ../../node_modules/@emotion/weak-memoize/dist/emotion-weak-memoize.esm.js
1256
+ var weakMemoize = function weakMemoize2(func) {
1257
+ var cache = /* @__PURE__ */ new WeakMap();
1258
+ return function(arg) {
1259
+ if (cache.has(arg)) {
1260
+ return cache.get(arg);
1261
+ }
1262
+ var ret = func(arg);
1263
+ cache.set(arg, ret);
1264
+ return ret;
1265
+ };
1266
+ };
1267
+
1268
+ // ../../node_modules/@emotion/memoize/dist/emotion-memoize.esm.js
1269
+ function memoize(fn) {
1270
+ var cache = /* @__PURE__ */ Object.create(null);
1271
+ return function(arg) {
1272
+ if (cache[arg] === void 0) cache[arg] = fn(arg);
1273
+ return cache[arg];
1274
+ };
1275
+ }
1276
+
1277
+ // ../../node_modules/@emotion/cache/dist/emotion-cache.esm.js
1278
+ var isBrowser = typeof document !== "undefined";
1279
+ var identifierWithPointTracking = function identifierWithPointTracking2(begin, points, index) {
1280
+ var previous = 0;
1281
+ var character2 = 0;
1282
+ while (true) {
1283
+ previous = character2;
1284
+ character2 = peek();
1285
+ if (previous === 38 && character2 === 12) {
1286
+ points[index] = 1;
1287
+ }
1288
+ if (token(character2)) {
1289
+ break;
1290
+ }
1291
+ next();
1292
+ }
1293
+ return slice(begin, position);
1294
+ };
1295
+ var toRules = function toRules2(parsed, points) {
1296
+ var index = -1;
1297
+ var character2 = 44;
1298
+ do {
1299
+ switch (token(character2)) {
1300
+ case 0:
1301
+ if (character2 === 38 && peek() === 12) {
1302
+ points[index] = 1;
1303
+ }
1304
+ parsed[index] += identifierWithPointTracking(position - 1, points, index);
1305
+ break;
1306
+ case 2:
1307
+ parsed[index] += delimit(character2);
1308
+ break;
1309
+ case 4:
1310
+ if (character2 === 44) {
1311
+ parsed[++index] = peek() === 58 ? "&\f" : "";
1312
+ points[index] = parsed[index].length;
1313
+ break;
1314
+ }
1315
+ // fallthrough
1316
+ default:
1317
+ parsed[index] += from(character2);
1318
+ }
1319
+ } while (character2 = next());
1320
+ return parsed;
1321
+ };
1322
+ var getRules = function getRules2(value, points) {
1323
+ return dealloc(toRules(alloc(value), points));
1324
+ };
1325
+ var fixedElements = /* @__PURE__ */ new WeakMap();
1326
+ var compat = function compat2(element) {
1327
+ if (element.type !== "rule" || !element.parent || // positive .length indicates that this rule contains pseudo
1328
+ // negative .length indicates that this rule has been already prefixed
1329
+ element.length < 1) {
1330
+ return;
1331
+ }
1332
+ var value = element.value;
1333
+ var parent = element.parent;
1334
+ var isImplicitRule = element.column === parent.column && element.line === parent.line;
1335
+ while (parent.type !== "rule") {
1336
+ parent = parent.parent;
1337
+ if (!parent) return;
1338
+ }
1339
+ if (element.props.length === 1 && value.charCodeAt(0) !== 58 && !fixedElements.get(parent)) {
1340
+ return;
1341
+ }
1342
+ if (isImplicitRule) {
1343
+ return;
1344
+ }
1345
+ fixedElements.set(element, true);
1346
+ var points = [];
1347
+ var rules = getRules(value, points);
1348
+ var parentRules = parent.props;
1349
+ for (var i = 0, k = 0; i < rules.length; i++) {
1350
+ for (var j = 0; j < parentRules.length; j++, k++) {
1351
+ element.props[k] = points[i] ? rules[i].replace(/&\f/g, parentRules[j]) : parentRules[j] + " " + rules[i];
1352
+ }
1353
+ }
1354
+ };
1355
+ var removeLabel = function removeLabel2(element) {
1356
+ if (element.type === "decl") {
1357
+ var value = element.value;
1358
+ if (
1359
+ // charcode for l
1360
+ value.charCodeAt(0) === 108 && // charcode for b
1361
+ value.charCodeAt(2) === 98
1362
+ ) {
1363
+ element["return"] = "";
1364
+ element.value = "";
1365
+ }
1366
+ }
1367
+ };
1368
+ function prefix(value, length2) {
1369
+ switch (hash(value, length2)) {
1370
+ // color-adjust
1371
+ case 5103:
1372
+ return WEBKIT + "print-" + value + value;
1373
+ // animation, animation-(delay|direction|duration|fill-mode|iteration-count|name|play-state|timing-function)
1374
+ case 5737:
1375
+ case 4201:
1376
+ case 3177:
1377
+ case 3433:
1378
+ case 1641:
1379
+ case 4457:
1380
+ case 2921:
1381
+ // text-decoration, filter, clip-path, backface-visibility, column, box-decoration-break
1382
+ case 5572:
1383
+ case 6356:
1384
+ case 5844:
1385
+ case 3191:
1386
+ case 6645:
1387
+ case 3005:
1388
+ // mask, mask-image, mask-(mode|clip|size), mask-(repeat|origin), mask-position, mask-composite,
1389
+ case 6391:
1390
+ case 5879:
1391
+ case 5623:
1392
+ case 6135:
1393
+ case 4599:
1394
+ case 4855:
1395
+ // background-clip, columns, column-(count|fill|gap|rule|rule-color|rule-style|rule-width|span|width)
1396
+ case 4215:
1397
+ case 6389:
1398
+ case 5109:
1399
+ case 5365:
1400
+ case 5621:
1401
+ case 3829:
1402
+ return WEBKIT + value + value;
1403
+ // appearance, user-select, transform, hyphens, text-size-adjust
1404
+ case 5349:
1405
+ case 4246:
1406
+ case 4810:
1407
+ case 6968:
1408
+ case 2756:
1409
+ return WEBKIT + value + MOZ + value + MS + value + value;
1410
+ // flex, flex-direction
1411
+ case 6828:
1412
+ case 4268:
1413
+ return WEBKIT + value + MS + value + value;
1414
+ // order
1415
+ case 6165:
1416
+ return WEBKIT + value + MS + "flex-" + value + value;
1417
+ // align-items
1418
+ case 5187:
1419
+ return WEBKIT + value + replace(value, /(\w+).+(:[^]+)/, WEBKIT + "box-$1$2" + MS + "flex-$1$2") + value;
1420
+ // align-self
1421
+ case 5443:
1422
+ return WEBKIT + value + MS + "flex-item-" + replace(value, /flex-|-self/, "") + value;
1423
+ // align-content
1424
+ case 4675:
1425
+ return WEBKIT + value + MS + "flex-line-pack" + replace(value, /align-content|flex-|-self/, "") + value;
1426
+ // flex-shrink
1427
+ case 5548:
1428
+ return WEBKIT + value + MS + replace(value, "shrink", "negative") + value;
1429
+ // flex-basis
1430
+ case 5292:
1431
+ return WEBKIT + value + MS + replace(value, "basis", "preferred-size") + value;
1432
+ // flex-grow
1433
+ case 6060:
1434
+ return WEBKIT + "box-" + replace(value, "-grow", "") + WEBKIT + value + MS + replace(value, "grow", "positive") + value;
1435
+ // transition
1436
+ case 4554:
1437
+ return WEBKIT + replace(value, /([^-])(transform)/g, "$1" + WEBKIT + "$2") + value;
1438
+ // cursor
1439
+ case 6187:
1440
+ return replace(replace(replace(value, /(zoom-|grab)/, WEBKIT + "$1"), /(image-set)/, WEBKIT + "$1"), value, "") + value;
1441
+ // background, background-image
1442
+ case 5495:
1443
+ case 3959:
1444
+ return replace(value, /(image-set\([^]*)/, WEBKIT + "$1$`$1");
1445
+ // justify-content
1446
+ case 4968:
1447
+ return replace(replace(value, /(.+:)(flex-)?(.*)/, WEBKIT + "box-pack:$3" + MS + "flex-pack:$3"), /s.+-b[^;]+/, "justify") + WEBKIT + value + value;
1448
+ // (margin|padding)-inline-(start|end)
1449
+ case 4095:
1450
+ case 3583:
1451
+ case 4068:
1452
+ case 2532:
1453
+ return replace(value, /(.+)-inline(.+)/, WEBKIT + "$1$2") + value;
1454
+ // (min|max)?(width|height|inline-size|block-size)
1455
+ case 8116:
1456
+ case 7059:
1457
+ case 5753:
1458
+ case 5535:
1459
+ case 5445:
1460
+ case 5701:
1461
+ case 4933:
1462
+ case 4677:
1463
+ case 5533:
1464
+ case 5789:
1465
+ case 5021:
1466
+ case 4765:
1467
+ if (strlen(value) - 1 - length2 > 6) switch (charat(value, length2 + 1)) {
1468
+ // (m)ax-content, (m)in-content
1469
+ case 109:
1470
+ if (charat(value, length2 + 4) !== 45) break;
1471
+ // (f)ill-available, (f)it-content
1472
+ case 102:
1473
+ return replace(value, /(.+:)(.+)-([^]+)/, "$1" + WEBKIT + "$2-$3$1" + MOZ + (charat(value, length2 + 3) == 108 ? "$3" : "$2-$3")) + value;
1474
+ // (s)tretch
1475
+ case 115:
1476
+ return ~indexof(value, "stretch") ? prefix(replace(value, "stretch", "fill-available"), length2) + value : value;
1477
+ }
1478
+ break;
1479
+ // position: sticky
1480
+ case 4949:
1481
+ if (charat(value, length2 + 1) !== 115) break;
1482
+ // display: (flex|inline-flex)
1483
+ case 6444:
1484
+ switch (charat(value, strlen(value) - 3 - (~indexof(value, "!important") && 10))) {
1485
+ // stic(k)y
1486
+ case 107:
1487
+ return replace(value, ":", ":" + WEBKIT) + value;
1488
+ // (inline-)?fl(e)x
1489
+ case 101:
1490
+ return replace(value, /(.+:)([^;!]+)(;|!.+)?/, "$1" + WEBKIT + (charat(value, 14) === 45 ? "inline-" : "") + "box$3$1" + WEBKIT + "$2$3$1" + MS + "$2box$3") + value;
1491
+ }
1492
+ break;
1493
+ // writing-mode
1494
+ case 5936:
1495
+ switch (charat(value, length2 + 11)) {
1496
+ // vertical-l(r)
1497
+ case 114:
1498
+ return WEBKIT + value + MS + replace(value, /[svh]\w+-[tblr]{2}/, "tb") + value;
1499
+ // vertical-r(l)
1500
+ case 108:
1501
+ return WEBKIT + value + MS + replace(value, /[svh]\w+-[tblr]{2}/, "tb-rl") + value;
1502
+ // horizontal(-)tb
1503
+ case 45:
1504
+ return WEBKIT + value + MS + replace(value, /[svh]\w+-[tblr]{2}/, "lr") + value;
1505
+ }
1506
+ return WEBKIT + value + MS + value + value;
1507
+ }
1508
+ return value;
1509
+ }
1510
+ var prefixer = function prefixer2(element, index, children, callback) {
1511
+ if (element.length > -1) {
1512
+ if (!element["return"]) switch (element.type) {
1513
+ case DECLARATION:
1514
+ element["return"] = prefix(element.value, element.length);
1515
+ break;
1516
+ case KEYFRAMES:
1517
+ return serialize([copy(element, {
1518
+ value: replace(element.value, "@", "@" + WEBKIT)
1519
+ })], callback);
1520
+ case RULESET:
1521
+ if (element.length) return combine(element.props, function(value) {
1522
+ switch (match(value, /(::plac\w+|:read-\w+)/)) {
1523
+ // :read-(only|write)
1524
+ case ":read-only":
1525
+ case ":read-write":
1526
+ return serialize([copy(element, {
1527
+ props: [replace(value, /:(read-\w+)/, ":" + MOZ + "$1")]
1528
+ })], callback);
1529
+ // :placeholder
1530
+ case "::placeholder":
1531
+ return serialize([copy(element, {
1532
+ props: [replace(value, /:(plac\w+)/, ":" + WEBKIT + "input-$1")]
1533
+ }), copy(element, {
1534
+ props: [replace(value, /:(plac\w+)/, ":" + MOZ + "$1")]
1535
+ }), copy(element, {
1536
+ props: [replace(value, /:(plac\w+)/, MS + "input-$1")]
1537
+ })], callback);
1538
+ }
1539
+ return "";
1540
+ });
1541
+ }
1542
+ }
1543
+ };
1544
+ var getServerStylisCache = isBrowser ? void 0 : weakMemoize(function() {
1545
+ return memoize(function() {
1546
+ return {};
1547
+ });
1548
+ });
1549
+ var defaultStylisPlugins = [prefixer];
1550
+ var createCache = function createCache2(options) {
1551
+ var key = options.key;
1552
+ if (isBrowser && key === "css") {
1553
+ var ssrStyles = document.querySelectorAll("style[data-emotion]:not([data-s])");
1554
+ Array.prototype.forEach.call(ssrStyles, function(node2) {
1555
+ var dataEmotionAttribute = node2.getAttribute("data-emotion");
1556
+ if (dataEmotionAttribute.indexOf(" ") === -1) {
1557
+ return;
1558
+ }
1559
+ document.head.appendChild(node2);
1560
+ node2.setAttribute("data-s", "");
1561
+ });
1562
+ }
1563
+ var stylisPlugins = options.stylisPlugins || defaultStylisPlugins;
1564
+ var inserted = {};
1565
+ var container;
1566
+ var nodesToHydrate = [];
1567
+ if (isBrowser) {
1568
+ container = options.container || document.head;
1569
+ Array.prototype.forEach.call(
1570
+ // this means we will ignore elements which don't have a space in them which
1571
+ // means that the style elements we're looking at are only Emotion 11 server-rendered style elements
1572
+ document.querySelectorAll('style[data-emotion^="' + key + ' "]'),
1573
+ function(node2) {
1574
+ var attrib = node2.getAttribute("data-emotion").split(" ");
1575
+ for (var i = 1; i < attrib.length; i++) {
1576
+ inserted[attrib[i]] = true;
1577
+ }
1578
+ nodesToHydrate.push(node2);
1579
+ }
1580
+ );
1581
+ }
1582
+ var _insert;
1583
+ var omnipresentPlugins = [compat, removeLabel];
1584
+ if (!getServerStylisCache) {
1585
+ var currentSheet;
1586
+ var finalizingPlugins = [stringify, rulesheet(function(rule) {
1587
+ currentSheet.insert(rule);
1588
+ })];
1589
+ var serializer = middleware(omnipresentPlugins.concat(stylisPlugins, finalizingPlugins));
1590
+ var stylis = function stylis2(styles) {
1591
+ return serialize(compile(styles), serializer);
1592
+ };
1593
+ _insert = function insert(selector, serialized, sheet, shouldCache) {
1594
+ currentSheet = sheet;
1595
+ stylis(selector ? selector + "{" + serialized.styles + "}" : serialized.styles);
1596
+ if (shouldCache) {
1597
+ cache.inserted[serialized.name] = true;
1598
+ }
1599
+ };
1600
+ } else {
1601
+ var _finalizingPlugins = [stringify];
1602
+ var _serializer = middleware(omnipresentPlugins.concat(stylisPlugins, _finalizingPlugins));
1603
+ var _stylis = function _stylis2(styles) {
1604
+ return serialize(compile(styles), _serializer);
1605
+ };
1606
+ var serverStylisCache = getServerStylisCache(stylisPlugins)(key);
1607
+ var getRules3 = function getRules4(selector, serialized) {
1608
+ var name = serialized.name;
1609
+ if (serverStylisCache[name] === void 0) {
1610
+ serverStylisCache[name] = _stylis(selector ? selector + "{" + serialized.styles + "}" : serialized.styles);
1611
+ }
1612
+ return serverStylisCache[name];
1613
+ };
1614
+ _insert = function _insert2(selector, serialized, sheet, shouldCache) {
1615
+ var name = serialized.name;
1616
+ var rules = getRules3(selector, serialized);
1617
+ if (cache.compat === void 0) {
1618
+ if (shouldCache) {
1619
+ cache.inserted[name] = true;
1620
+ }
1621
+ return rules;
1622
+ } else {
1623
+ if (shouldCache) {
1624
+ cache.inserted[name] = rules;
1625
+ } else {
1626
+ return rules;
1627
+ }
1628
+ }
1629
+ };
1630
+ }
1631
+ var cache = {
1632
+ key,
1633
+ sheet: new StyleSheet({
1634
+ key,
1635
+ container,
1636
+ nonce: options.nonce,
1637
+ speedy: options.speedy,
1638
+ prepend: options.prepend,
1639
+ insertionPoint: options.insertionPoint
1640
+ }),
1641
+ nonce: options.nonce,
1642
+ inserted,
1643
+ registered: {},
1644
+ insert: _insert
1645
+ };
1646
+ cache.sheet.hydrate(nodesToHydrate);
1647
+ return cache;
1648
+ };
1649
+
1650
+ // src/react/styles/cache.ts
1651
+ var createWidgetCache = (container) => {
1652
+ return createCache({
1653
+ key: "la-widget",
1654
+ container,
1655
+ prepend: true
1656
+ });
1657
+ };
1658
+ var widgetCache = createCache({
1659
+ key: "la-widget",
1660
+ prepend: true
1661
+ });
1662
+ styled.div`
1663
+ display: flex;
1664
+ flex-direction: column;
1665
+ height: 100%;
1666
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.primary};
1667
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1668
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1669
+ `;
1670
+ styled.div`
1671
+ flex: 1;
1672
+ overflow-y: auto;
1673
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
1674
+
1675
+ &::-webkit-scrollbar {
1676
+ width: 6px;
1677
+ }
1678
+
1679
+ &::-webkit-scrollbar-track {
1680
+ background: transparent;
1681
+ }
1682
+
1683
+ &::-webkit-scrollbar-thumb {
1684
+ background: ${({ theme: theme2 }) => theme2.colors.background.tertiary};
1685
+ border-radius: ${({ theme: theme2 }) => theme2.radii.full};
1686
+ }
1687
+ `;
1688
+ var Flex = styled.div`
1689
+ display: flex;
1690
+ flex-direction: ${({ direction = "row" }) => direction};
1691
+ align-items: ${({ align = "stretch" }) => align};
1692
+ justify-content: ${({ justify = "flex-start" }) => justify};
1693
+ gap: ${({ theme: theme2, gap }) => gap ? theme2.spacing[gap] : 0};
1694
+ flex-wrap: ${({ wrap }) => wrap ? "wrap" : "nowrap"};
1695
+ `;
1696
+ styled.div`
1697
+ display: grid;
1698
+ grid-template-columns: ${({ columns = 1 }) => typeof columns === "number" ? `repeat(${columns}, 1fr)` : columns};
1699
+ gap: ${({ theme: theme2, gap = "md" }) => theme2.spacing[gap]};
1700
+ `;
1701
+ styled.div`
1702
+ display: flex;
1703
+ align-items: center;
1704
+ justify-content: space-between;
1705
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
1706
+ border-bottom: 1px solid ${({ theme: theme2 }) => theme2.colors.border};
1707
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.primary};
1708
+ `;
1709
+ styled.h2`
1710
+ margin: 0;
1711
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.md};
1712
+ font-weight: ${({ theme: theme2 }) => theme2.typography.fontWeight.medium};
1713
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1714
+ `;
1715
+ styled.button`
1716
+ display: inline-flex;
1717
+ align-items: center;
1718
+ justify-content: center;
1719
+ gap: ${({ theme: theme2 }) => theme2.spacing.sm};
1720
+ padding: ${({ theme: theme2, size = "md" }) => {
1721
+ const sizes = {
1722
+ sm: `${theme2.spacing.sm} ${theme2.spacing.md}`,
1723
+ md: `${theme2.spacing.md} ${theme2.spacing.lg}`,
1724
+ lg: `${theme2.spacing.lg} ${theme2.spacing.xl}`
1725
+ };
1726
+ return sizes[size];
1727
+ }};
1728
+ width: ${({ fullWidth }) => fullWidth ? "100%" : "auto"};
1729
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1730
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.sm};
1731
+ font-weight: ${({ theme: theme2 }) => theme2.typography.fontWeight.medium};
1732
+ border-radius: ${({ theme: theme2 }) => theme2.radii.sm};
1733
+ border: none;
1734
+ cursor: pointer;
1735
+ transition: all ${({ theme: theme2 }) => theme2.transitions.fast};
1736
+
1737
+ ${({ theme: theme2, variant = "primary" }) => {
1738
+ switch (variant) {
1739
+ case "primary":
1740
+ return `
1741
+ background-color: ${theme2.colors.accent.primary};
1742
+ color: ${theme2.colors.text.inverse};
1743
+ &:hover:not(:disabled) {
1744
+ background-color: ${theme2.colors.accent.hover};
1745
+ }
1746
+ `;
1747
+ case "secondary":
1748
+ return `
1749
+ background-color: ${theme2.colors.background.secondary};
1750
+ color: ${theme2.colors.text.primary};
1751
+ &:hover:not(:disabled) {
1752
+ background-color: ${theme2.colors.background.tertiary};
1753
+ }
1754
+ `;
1755
+ case "ghost":
1756
+ return `
1757
+ background: none;
1758
+ color: ${theme2.colors.text.secondary};
1759
+ &:hover:not(:disabled) {
1760
+ color: ${theme2.colors.text.primary};
1761
+ background-color: ${theme2.colors.background.secondary};
1762
+ }
1763
+ `;
1764
+ }
1765
+ }}
1766
+
1767
+ &:disabled {
1768
+ opacity: 0.5;
1769
+ cursor: not-allowed;
1770
+ }
1771
+ `;
1772
+ var IconButton = styled.button`
1773
+ display: inline-flex;
1774
+ align-items: center;
1775
+ justify-content: center;
1776
+ padding: ${({ theme: theme2 }) => theme2.spacing.xs};
1777
+ background: none;
1778
+ border: none;
1779
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1780
+ font-size: ${({ size = "md" }) => {
1781
+ const sizes = { sm: "1rem", md: "1.25rem", lg: "1.5rem" };
1782
+ return sizes[size];
1783
+ }};
1784
+ cursor: pointer;
1785
+ transition: color ${({ theme: theme2 }) => theme2.transitions.fast};
1786
+ line-height: 1;
1787
+
1788
+ &:hover {
1789
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
1790
+ }
1791
+ `;
1792
+ var FAB = styled(motion.button)`
1793
+ width: 48px;
1794
+ height: 48px;
1795
+ border-radius: 50%;
1796
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.primary};
1797
+ border: none;
1798
+ box-shadow: ${({ theme: theme2 }) => theme2.shadows.sm};
1799
+ cursor: pointer;
1800
+ display: flex;
1801
+ align-items: center;
1802
+ justify-content: center;
1803
+ font-size: 1.25rem;
1804
+ color: white;
1805
+ transition: box-shadow ${({ theme: theme2 }) => theme2.transitions.fast};
1806
+ position: relative;
1807
+ overflow: hidden;
1808
+
1809
+ &:hover {
1810
+ box-shadow: ${({ theme: theme2 }) => theme2.shadows.md};
1811
+ }
1812
+ `;
1813
+ styled.input`
1814
+ width: 100%;
1815
+ padding: ${({ theme: theme2 }) => `${theme2.spacing.md} ${theme2.spacing.md}`};
1816
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.secondary};
1817
+ border: none;
1818
+ border-radius: ${({ theme: theme2 }) => theme2.radii.sm};
1819
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1820
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1821
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.sm};
1822
+ outline: none;
1823
+ transition: background-color ${({ theme: theme2 }) => theme2.transitions.fast};
1824
+
1825
+ &::placeholder {
1826
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
1827
+ }
1828
+
1829
+ &:focus {
1830
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.tertiary};
1831
+ }
1832
+
1833
+ &:disabled {
1834
+ opacity: 0.5;
1835
+ cursor: not-allowed;
1836
+ }
1837
+ `;
1838
+ styled.textarea`
1839
+ width: 100%;
1840
+ min-height: 150px;
1841
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
1842
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.secondary};
1843
+ border: none;
1844
+ border-radius: ${({ theme: theme2 }) => theme2.radii.sm};
1845
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1846
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1847
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.sm};
1848
+ line-height: ${({ theme: theme2 }) => theme2.typography.lineHeight.normal};
1849
+ resize: vertical;
1850
+ outline: none;
1851
+
1852
+ &::placeholder {
1853
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
1854
+ }
1855
+
1856
+ &:focus {
1857
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.tertiary};
1858
+ }
1859
+ `;
1860
+ styled.button`
1861
+ display: flex;
1862
+ align-items: center;
1863
+ gap: ${({ theme: theme2 }) => theme2.spacing.md};
1864
+ width: 100%;
1865
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
1866
+ background-color: ${({ theme: theme2, selected }) => selected ? theme2.colors.background.tertiary : theme2.colors.background.secondary};
1867
+ border: 2px solid
1868
+ ${({ theme: theme2, selected }) => selected ? theme2.colors.accent.primary : "transparent"};
1869
+ border-radius: ${({ theme: theme2 }) => theme2.radii.sm};
1870
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1871
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1872
+ text-align: left;
1873
+ cursor: ${({ interactive = true }) => interactive ? "pointer" : "default"};
1874
+ transition: all ${({ theme: theme2 }) => theme2.transitions.fast};
1875
+
1876
+ &:hover {
1877
+ background-color: ${({ theme: theme2, interactive = true }) => interactive ? theme2.colors.background.tertiary : theme2.colors.background.secondary};
1878
+ }
1879
+ `;
1880
+ styled.div`
1881
+ flex: 1;
1882
+ min-width: 0;
1883
+ `;
1884
+ styled.div`
1885
+ font-weight: ${({ theme: theme2 }) => theme2.typography.fontWeight.medium};
1886
+ margin-bottom: ${({ theme: theme2 }) => theme2.spacing.xs};
1887
+ white-space: nowrap;
1888
+ overflow: hidden;
1889
+ text-overflow: ellipsis;
1890
+ `;
1891
+ styled.div`
1892
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
1893
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.xs};
1894
+ `;
1895
+ styled.button`
1896
+ display: flex;
1897
+ flex-direction: column;
1898
+ align-items: center;
1899
+ justify-content: center;
1900
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
1901
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.secondary};
1902
+ border: none;
1903
+ border-radius: ${({ theme: theme2 }) => theme2.radii.sm};
1904
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1905
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1906
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.xs};
1907
+ gap: ${({ theme: theme2 }) => theme2.spacing.xs};
1908
+ cursor: pointer;
1909
+ transition: background-color ${({ theme: theme2 }) => theme2.transitions.fast};
1910
+
1911
+ &:hover {
1912
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.tertiary};
1913
+ }
1914
+ `;
1915
+ styled.span`
1916
+ font-size: 1.25rem;
1917
+ `;
1918
+ styled.div`
1919
+ width: ${({ size = "md" }) => {
1920
+ const sizes = { sm: "40px", md: "64px", lg: "80px" };
1921
+ return sizes[size];
1922
+ }};
1923
+ height: ${({ size = "md" }) => {
1924
+ const sizes = { sm: "40px", md: "64px", lg: "80px" };
1925
+ return sizes[size];
1926
+ }};
1927
+ border-radius: ${({ theme: theme2 }) => theme2.radii.full};
1928
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.secondary};
1929
+ display: flex;
1930
+ align-items: center;
1931
+ justify-content: center;
1932
+ font-size: ${({ size = "md" }) => {
1933
+ const sizes = { sm: "1rem", md: "1.5rem", lg: "2rem" };
1934
+ return sizes[size];
1935
+ }};
1936
+ `;
1937
+ styled.h1`
1938
+ margin: 0;
1939
+ font-size: ${({ theme: theme2, size = "md" }) => {
1940
+ const sizes = {
1941
+ sm: theme2.typography.fontSize.lg,
1942
+ md: theme2.typography.fontSize.xl,
1943
+ lg: theme2.typography.fontSize["2xl"]
1944
+ };
1945
+ return sizes[size];
1946
+ }};
1947
+ font-weight: ${({ theme: theme2 }) => theme2.typography.fontWeight.medium};
1948
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1949
+ `;
1950
+ var Text = styled.p`
1951
+ margin: 0;
1952
+ font-size: ${({ theme: theme2, size = "md" }) => theme2.typography.fontSize[size]};
1953
+ color: ${({ theme: theme2, color = "primary" }) => {
1954
+ if (color === "accent") return theme2.colors.accent.primary;
1955
+ return theme2.colors.text[color];
1956
+ }};
1957
+ line-height: ${({ theme: theme2 }) => theme2.typography.lineHeight.normal};
1958
+ `;
1959
+ styled.button`
1960
+ background: none;
1961
+ border: none;
1962
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
1963
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1964
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.sm};
1965
+ text-decoration: underline;
1966
+ cursor: pointer;
1967
+ padding: 0;
1968
+
1969
+ &:hover {
1970
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1971
+ }
1972
+ `;
1973
+ styled.div`
1974
+ width: 100%;
1975
+ height: 1px;
1976
+ background-color: ${({ theme: theme2 }) => theme2.colors.border};
1977
+ `;
1978
+ styled.button`
1979
+ display: flex;
1980
+ flex-direction: column;
1981
+ width: 100%;
1982
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
1983
+ background: transparent;
1984
+ border: none;
1985
+ border-bottom: 1px solid ${({ theme: theme2 }) => theme2.colors.border};
1986
+ color: ${({ theme: theme2 }) => theme2.colors.text.primary};
1987
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
1988
+ text-align: left;
1989
+ cursor: pointer;
1990
+ transition: background-color ${({ theme: theme2 }) => theme2.transitions.fast};
1991
+
1992
+ &:hover {
1993
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.secondary};
1994
+ }
1995
+ `;
1996
+ var WidgetRoot = styled.div`
1997
+ position: fixed;
1998
+ bottom: 20px;
1999
+ ${({ position: position2 }) => position2 === "bottom-right" ? "right: 20px;" : "left: 20px;"}
2000
+ z-index: ${({ theme: theme2 }) => theme2.zIndex.widget};
2001
+ font-family: ${({ theme: theme2 }) => theme2.typography.fontFamily};
2002
+ `;
2003
+ var WidgetPanel = styled(motion.div)`
2004
+ width: 400px;
2005
+ height: 700px;
2006
+ border-radius: ${({ theme: theme2 }) => theme2.radii.xl};
2007
+ overflow: hidden;
2008
+ box-shadow: ${({ theme: theme2 }) => theme2.shadows.lg};
2009
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.primary};
2010
+ display: flex;
2011
+ flex-direction: column;
2012
+ `;
2013
+ var WidgetHeader = styled.div`
2014
+ display: flex;
2015
+ align-items: center;
2016
+ justify-content: space-between;
2017
+ padding: ${({ theme: theme2 }) => `${theme2.spacing.sm} ${theme2.spacing.md}`};
2018
+ background-color: ${({ theme: theme2 }) => theme2.colors.background.primary};
2019
+ border-bottom: 1px solid ${({ theme: theme2 }) => theme2.colors.border};
2020
+ flex-shrink: 0;
2021
+ min-width: 0;
2022
+ gap: ${({ theme: theme2 }) => theme2.spacing.sm};
2023
+ `;
2024
+ var WidgetContent = styled.div`
2025
+ flex: 1;
2026
+ overflow: hidden;
2027
+ display: flex;
2028
+ flex-direction: column;
2029
+ `;
2030
+ styled.div`
2031
+ max-width: 80%;
2032
+ padding: ${({ theme: theme2 }) => `${theme2.spacing.md} ${theme2.spacing.md}`};
2033
+ border-radius: ${({ theme: theme2 }) => theme2.radii.md};
2034
+ background-color: ${({ theme: theme2, isUser }) => isUser ? theme2.colors.accent.primary : theme2.colors.background.secondary};
2035
+ color: ${({ theme: theme2, isUser }) => isUser ? theme2.colors.text.inverse : theme2.colors.text.primary};
2036
+ `;
2037
+ styled.span`
2038
+ font-size: ${({ theme: theme2 }) => theme2.typography.fontSize.xs};
2039
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
2040
+ margin-top: ${({ theme: theme2 }) => theme2.spacing.xs};
2041
+ `;
2042
+ styled.form`
2043
+ display: flex;
2044
+ gap: ${({ theme: theme2 }) => theme2.spacing.sm};
2045
+ padding: ${({ theme: theme2 }) => theme2.spacing.md};
2046
+ border-top: 1px solid ${({ theme: theme2 }) => theme2.colors.border};
2047
+ `;
2048
+ styled.div`
2049
+ display: flex;
2050
+ align-items: center;
2051
+ justify-content: center;
2052
+ height: 100%;
2053
+ color: ${({ theme: theme2 }) => theme2.colors.text.secondary};
2054
+ text-align: center;
2055
+ padding: ${({ theme: theme2 }) => theme2.spacing.xl};
2056
+ `;
2057
+ var WidgetContext = createContext(null);
2058
+ function generateUserId() {
2059
+ return crypto.randomUUID();
2060
+ }
2061
+ function createApiHeaders(userId, assistantId) {
2062
+ return {
2063
+ "Content-Type": "application/json",
2064
+ "X-User-Id": userId,
2065
+ "X-Assistant-Id": assistantId
2066
+ };
2067
+ }
2068
+ function createThreadListAdapter(baseUrl, userId, assistantId) {
2069
+ const headers = createApiHeaders(userId, assistantId);
2070
+ return {
2071
+ // List all threads for this user
2072
+ async list() {
2073
+ try {
2074
+ const response = await fetch(`${baseUrl}/api/widget/threads`, {
2075
+ headers
2076
+ });
2077
+ if (!response.ok) {
2078
+ console.error("[Threads] List failed:", response.status);
2079
+ return { threads: [] };
2080
+ }
2081
+ const data = await response.json();
2082
+ return { threads: data.threads || [] };
2083
+ } catch (error) {
2084
+ console.error("[Threads] List error:", error);
2085
+ return { threads: [] };
2086
+ }
2087
+ },
2088
+ // Fetch a single thread's details
2089
+ async fetch(remoteId) {
2090
+ const response = await fetch(
2091
+ `${baseUrl}/api/widget/threads/${remoteId}`,
2092
+ {
2093
+ headers
2094
+ }
2095
+ );
2096
+ if (!response.ok) {
2097
+ throw new Error(`Failed to fetch thread: ${response.status}`);
2098
+ }
2099
+ const data = await response.json();
2100
+ return {
2101
+ remoteId: data.remoteId,
2102
+ status: data.status,
2103
+ title: data.title
2104
+ };
2105
+ },
2106
+ // Initialize a new thread
2107
+ async initialize(localId) {
2108
+ try {
2109
+ const response = await fetch(`${baseUrl}/api/widget/threads`, {
2110
+ method: "POST",
2111
+ headers,
2112
+ body: JSON.stringify({ localId })
2113
+ });
2114
+ if (!response.ok) {
2115
+ throw new Error(`Failed to create thread: ${response.status}`);
2116
+ }
2117
+ const data = await response.json();
2118
+ return { remoteId: data.remoteId, externalId: data.externalId };
2119
+ } catch (error) {
2120
+ console.error("[Threads] Initialize error:", error);
2121
+ throw error;
2122
+ }
2123
+ },
2124
+ // Rename a thread
2125
+ async rename(remoteId, newTitle) {
2126
+ try {
2127
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}`, {
2128
+ method: "PATCH",
2129
+ headers,
2130
+ body: JSON.stringify({ title: newTitle })
2131
+ });
2132
+ } catch (error) {
2133
+ console.error("[Threads] Rename error:", error);
2134
+ }
2135
+ },
2136
+ // Archive a thread
2137
+ async archive(remoteId) {
2138
+ try {
2139
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}/archive`, {
2140
+ method: "POST",
2141
+ headers
2142
+ });
2143
+ } catch (error) {
2144
+ console.error("[Threads] Archive error:", error);
2145
+ }
2146
+ },
2147
+ // Unarchive a thread
2148
+ async unarchive(remoteId) {
2149
+ try {
2150
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}/unarchive`, {
2151
+ method: "POST",
2152
+ headers
2153
+ });
2154
+ } catch (error) {
2155
+ console.error("[Threads] Unarchive error:", error);
2156
+ }
2157
+ },
2158
+ // Delete a thread
2159
+ async delete(remoteId) {
2160
+ try {
2161
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}`, {
2162
+ method: "DELETE",
2163
+ headers
2164
+ });
2165
+ } catch (error) {
2166
+ console.error("[Threads] Delete error:", error);
2167
+ }
2168
+ },
2169
+ // Generate a title from messages
2170
+ async generateTitle(remoteId, messages) {
2171
+ return createAssistantStream(async (controller) => {
2172
+ try {
2173
+ const response = await fetch(
2174
+ `${baseUrl}/api/widget/threads/${remoteId}/title`,
2175
+ {
2176
+ method: "POST",
2177
+ headers,
2178
+ body: JSON.stringify({ messages })
2179
+ }
2180
+ );
2181
+ if (!response.ok) {
2182
+ throw new Error(`Title generation failed: ${response.status}`);
2183
+ }
2184
+ const data = await response.json();
2185
+ controller.appendText(data.title);
2186
+ controller.close();
2187
+ } catch (error) {
2188
+ console.error("[Threads] Title generation error:", error);
2189
+ controller.appendText("New Chat");
2190
+ controller.close();
2191
+ }
2192
+ });
2193
+ }
2194
+ };
2195
+ }
2196
+ async function saveMessages(baseUrl, userId, assistantId, threadId, messages) {
2197
+ try {
2198
+ const response = await fetch(
2199
+ `${baseUrl}/api/widget/threads/${threadId}/messages/sync`,
2200
+ {
2201
+ method: "POST",
2202
+ headers: createApiHeaders(userId, assistantId),
2203
+ body: JSON.stringify({ messages })
2204
+ }
2205
+ );
2206
+ if (!response.ok) {
2207
+ console.error("[Messages] Sync failed:", response.status);
2208
+ }
2209
+ } catch (error) {
2210
+ console.error("[Messages] Sync error:", error);
2211
+ }
2212
+ }
2213
+ function createHistoryAdapter(baseUrl, userId, assistantId, remoteId) {
2214
+ const headers = createApiHeaders(userId, assistantId);
2215
+ return {
2216
+ async load() {
2217
+ console.log("[History] load() called, remoteId:", remoteId);
2218
+ if (!remoteId) return { headId: null, messages: [] };
2219
+ try {
2220
+ const response = await fetch(
2221
+ `${baseUrl}/api/widget/threads/${remoteId}/messages`,
2222
+ { headers }
2223
+ );
2224
+ if (!response.ok) {
2225
+ console.error("[History] Failed to load messages:", response.status);
2226
+ return { headId: null, messages: [] };
2227
+ }
2228
+ const { messages } = await response.json();
2229
+ console.log("[History] Loaded messages:", messages.length);
2230
+ const formattedMessages = messages.map(
2231
+ (m, index) => ({
2232
+ parentId: index > 0 ? messages[index - 1].id : null,
2233
+ message: {
2234
+ id: m.id,
2235
+ role: m.role,
2236
+ parts: m.content,
2237
+ metadata: m.metadata,
2238
+ createdAt: new Date(m.createdAt)
2239
+ }
2240
+ })
2241
+ );
2242
+ console.log("[History] Formatted messages:", formattedMessages.length);
2243
+ return {
2244
+ headId: messages.length > 0 ? messages[messages.length - 1].id : null,
2245
+ messages: formattedMessages
2246
+ };
2247
+ } catch (error) {
2248
+ console.error("[History] Load error:", error);
2249
+ return { headId: null, messages: [] };
2250
+ }
2251
+ },
2252
+ async append(message) {
2253
+ console.log("[History] append() called");
2254
+ },
2255
+ // Required by useExternalHistory in @assistant-ui/react-ai-sdk
2256
+ withFormat(_formatAdapter) {
2257
+ console.log("[History.withFormat] called, remoteId:", remoteId);
2258
+ return {
2259
+ async load() {
2260
+ if (!remoteId) return { headId: null, messages: [] };
2261
+ try {
2262
+ const response = await fetch(
2263
+ `${baseUrl}/api/widget/threads/${remoteId}/messages`,
2264
+ { headers }
2265
+ );
2266
+ if (!response.ok) {
2267
+ console.error("[History.withFormat] Failed:", response.status);
2268
+ return { headId: null, messages: [] };
2269
+ }
2270
+ const { messages } = await response.json();
2271
+ console.log("[History.withFormat] Loaded:", messages.length);
2272
+ const formattedMessages = messages.map(
2273
+ (m, index) => ({
2274
+ parentId: index > 0 ? messages[index - 1].id : null,
2275
+ message: {
2276
+ id: m.id,
2277
+ role: m.role,
2278
+ parts: m.content,
2279
+ metadata: m.metadata,
2280
+ createdAt: new Date(m.createdAt)
2281
+ }
2282
+ })
2283
+ );
2284
+ return {
2285
+ headId: messages.length > 0 ? messages[messages.length - 1].id : null,
2286
+ messages: formattedMessages
2287
+ };
2288
+ } catch (error) {
2289
+ console.error("[History.withFormat] Error:", error);
2290
+ return { headId: null, messages: [] };
2291
+ }
2292
+ },
2293
+ async append(_item) {
2294
+ }
2295
+ };
2296
+ }
2297
+ };
2298
+ }
2299
+ function AssistantRuntimeWrapper({
2300
+ config,
2301
+ userId,
2302
+ children
2303
+ }) {
2304
+ const baseUrl = config.baseUrl || "http://localhost:3000";
2305
+ const assistantId = config.apiKey;
2306
+ const { consumeContext, clearContext } = useMessageContext();
2307
+ const contextRef = useRef(consumeContext);
2308
+ contextRef.current = consumeContext;
2309
+ const clearContextRef = useRef(clearContext);
2310
+ clearContextRef.current = clearContext;
2311
+ const threadListAdapter = useMemo(
2312
+ () => createThreadListAdapter(baseUrl, userId, assistantId),
2313
+ [baseUrl, userId, assistantId]
2314
+ );
2315
+ const runtime = unstable_useRemoteThreadListRuntime({
2316
+ runtimeHook: function useChatThreadRuntime() {
2317
+ const threadId = useAssistantState(
2318
+ ({ threadListItem }) => threadListItem?.remoteId ?? void 0
2319
+ );
2320
+ const threadIdRef = useRef(threadId);
2321
+ threadIdRef.current = threadId;
2322
+ const history = useMemo(
2323
+ () => createHistoryAdapter(baseUrl, userId, assistantId, threadId),
2324
+ [threadId]
2325
+ );
2326
+ const transport = useMemo(() => {
2327
+ console.log("[Widget] Creating transport for threadId:", threadId);
2328
+ return new AssistantChatTransport({
2329
+ api: `${baseUrl}/api/widget/chat`,
2330
+ headers: {
2331
+ "X-User-Id": userId,
2332
+ "X-Assistant-Id": assistantId
2333
+ },
2334
+ // Use body as a function to dynamically include context
2335
+ body: () => {
2336
+ const currentContext = contextRef.current();
2337
+ const contextIds = currentContext.map((item) => item.id);
2338
+ const contextMetadata = currentContext.map((item) => ({
2339
+ id: item.id,
2340
+ type: item.type,
2341
+ title: item.title
2342
+ }));
2343
+ console.log("[Widget] Transport body - contextIds:", contextIds.length, "threadId:", threadId);
2344
+ if (contextIds.length > 0) {
2345
+ setTimeout(() => clearContextRef.current(), 0);
2346
+ }
2347
+ return {
2348
+ assistantId,
2349
+ threadId,
2350
+ ...contextIds.length > 0 && { contextIds, contextMetadata }
2351
+ };
2352
+ }
2353
+ });
2354
+ }, [threadId]);
2355
+ const runtime2 = useChatRuntime({
2356
+ transport,
2357
+ adapters: { history },
2358
+ onFinish: ({ message, messages }) => {
2359
+ const currentThreadId = threadIdRef.current;
2360
+ console.log(
2361
+ "[Widget] onFinish - threadId:",
2362
+ currentThreadId,
2363
+ "messages:",
2364
+ messages.length
2365
+ );
2366
+ if (currentThreadId && messages.length > 0) {
2367
+ saveMessages(
2368
+ baseUrl,
2369
+ userId,
2370
+ assistantId,
2371
+ currentThreadId,
2372
+ messages
2373
+ );
2374
+ }
2375
+ }
2376
+ });
2377
+ return runtime2;
2378
+ },
2379
+ adapter: threadListAdapter
2380
+ });
2381
+ return /* @__PURE__ */ jsxs(AssistantRuntimeProvider, { runtime, children: [
2382
+ /* @__PURE__ */ jsx(DetailedAnswerToolUI, {}),
2383
+ children
2384
+ ] });
2385
+ }
2386
+ function WidgetProvider({
2387
+ config,
2388
+ children,
2389
+ autoInitialize = true
2390
+ }) {
2391
+ const [userId] = useState(() => config.userId || generateUserId());
2392
+ const [client] = useState(() => new WidgetClient(config));
2393
+ const [state, setState] = useState(client.getState());
2394
+ useEffect(() => {
2395
+ const unsubscribe = client.on("state:change", ({ current }) => {
2396
+ setState(current);
2397
+ });
2398
+ if (autoInitialize && state.status === "idle") {
2399
+ client.initialize().catch(console.error);
2400
+ }
2401
+ return () => {
2402
+ unsubscribe();
2403
+ client.destroy();
2404
+ };
2405
+ }, [client, autoInitialize, state.status]);
2406
+ const contextValue = useMemo(
2407
+ () => ({ client, state, userId }),
2408
+ [client, state, userId]
2409
+ );
2410
+ return /* @__PURE__ */ jsx(CacheProvider, { value: widgetCache, children: /* @__PURE__ */ jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsx(WidgetContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(MessageContextProvider, { children: /* @__PURE__ */ jsx(AssistantRuntimeWrapper, { config, userId, children }) }) }) }) });
2411
+ }
2412
+ function useWidget() {
2413
+ const context = useContext(WidgetContext);
2414
+ if (!context) {
2415
+ throw new Error("useWidget must be used within a WidgetProvider");
2416
+ }
2417
+ const { client, state } = context;
2418
+ const initialize = useCallback(async () => {
2419
+ if (state.status === "idle") {
2420
+ await client.initialize();
2421
+ }
2422
+ }, [client, state.status]);
2423
+ const sendMessage = useCallback(
2424
+ async (content) => {
2425
+ return client.sendMessage(content);
2426
+ },
2427
+ [client]
2428
+ );
2429
+ return {
2430
+ state,
2431
+ client,
2432
+ isIdle: state.status === "idle",
2433
+ isInitializing: state.status === "initializing",
2434
+ isReady: state.status === "ready",
2435
+ isLoading: state.status === "loading",
2436
+ isError: state.status === "error",
2437
+ messages: state.status === "ready" ? state.session.messages : [],
2438
+ error: state.status === "error" ? state.error : null,
2439
+ initialize,
2440
+ sendMessage
2441
+ };
2442
+ }
2443
+ function useChat() {
2444
+ const { sendMessage, messages, isLoading, isReady } = useWidget();
2445
+ const [input, setInput] = useState("");
2446
+ const handleSubmit = useCallback(
2447
+ async (e) => {
2448
+ e?.preventDefault();
2449
+ if (!input.trim() || !isReady || isLoading) {
2450
+ return;
2451
+ }
2452
+ const message = input.trim();
2453
+ setInput("");
2454
+ try {
2455
+ await sendMessage(message);
2456
+ } catch (error) {
2457
+ console.error("Failed to send message:", error);
2458
+ setInput(message);
2459
+ }
2460
+ },
2461
+ [input, isReady, isLoading, sendMessage]
2462
+ );
2463
+ return {
2464
+ input,
2465
+ setInput,
2466
+ handleSubmit,
2467
+ messages,
2468
+ isLoading,
2469
+ canSubmit: isReady && !isLoading && input.trim().length > 0
2470
+ };
2471
+ }
2472
+ function Dialog({
2473
+ ...props
2474
+ }) {
2475
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
2476
+ }
2477
+ function DialogTrigger({
2478
+ ...props
2479
+ }) {
2480
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
2481
+ }
2482
+ function DialogPortal({
2483
+ ...props
2484
+ }) {
2485
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
2486
+ }
2487
+ function DialogOverlay({
2488
+ className,
2489
+ ...props
2490
+ }) {
2491
+ return /* @__PURE__ */ jsx(
2492
+ DialogPrimitive.Overlay,
2493
+ {
2494
+ "data-slot": "dialog-overlay",
2495
+ className: cn(
2496
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
2497
+ className
2498
+ ),
2499
+ ...props
2500
+ }
2501
+ );
2502
+ }
2503
+ function DialogContent({
2504
+ className,
2505
+ children,
2506
+ showCloseButton = true,
2507
+ ...props
2508
+ }) {
2509
+ return /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
2510
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
2511
+ /* @__PURE__ */ jsxs(
2512
+ DialogPrimitive.Content,
2513
+ {
2514
+ "data-slot": "dialog-content",
2515
+ className: cn(
2516
+ "bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
2517
+ className
2518
+ ),
2519
+ ...props,
2520
+ children: [
2521
+ children,
2522
+ showCloseButton && /* @__PURE__ */ jsxs(
2523
+ DialogPrimitive.Close,
2524
+ {
2525
+ "data-slot": "dialog-close",
2526
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
2527
+ children: [
2528
+ /* @__PURE__ */ jsx(XIcon, {}),
2529
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
2530
+ ]
2531
+ }
2532
+ )
2533
+ ]
2534
+ }
2535
+ )
2536
+ ] });
2537
+ }
2538
+ function DialogTitle({
2539
+ className,
2540
+ ...props
2541
+ }) {
2542
+ return /* @__PURE__ */ jsx(
2543
+ DialogPrimitive.Title,
2544
+ {
2545
+ "data-slot": "dialog-title",
2546
+ className: cn("text-lg leading-none font-semibold", className),
2547
+ ...props
2548
+ }
2549
+ );
2550
+ }
2551
+ function Avatar2({
2552
+ className,
2553
+ ...props
2554
+ }) {
2555
+ return /* @__PURE__ */ jsx(
2556
+ AvatarPrimitive.Root,
2557
+ {
2558
+ "data-slot": "avatar",
2559
+ className: cn(
2560
+ "relative flex size-8 shrink-0 overflow-hidden rounded-full",
2561
+ className
2562
+ ),
2563
+ ...props
2564
+ }
2565
+ );
2566
+ }
2567
+ function AvatarImage({
2568
+ className,
2569
+ ...props
2570
+ }) {
2571
+ return /* @__PURE__ */ jsx(
2572
+ AvatarPrimitive.Image,
2573
+ {
2574
+ "data-slot": "avatar-image",
2575
+ className: cn("aspect-square size-full", className),
2576
+ ...props
2577
+ }
2578
+ );
2579
+ }
2580
+ function AvatarFallback({
2581
+ className,
2582
+ ...props
2583
+ }) {
2584
+ return /* @__PURE__ */ jsx(
2585
+ AvatarPrimitive.Fallback,
2586
+ {
2587
+ "data-slot": "avatar-fallback",
2588
+ className: cn(
2589
+ "bg-muted flex size-full items-center justify-center rounded-full",
2590
+ className
2591
+ ),
2592
+ ...props
2593
+ }
2594
+ );
2595
+ }
2596
+ var useFileSrc = (file) => {
2597
+ const [src, setSrc] = useState(void 0);
2598
+ useEffect(() => {
2599
+ if (!file) {
2600
+ setSrc(void 0);
2601
+ return;
2602
+ }
2603
+ const objectUrl = URL.createObjectURL(file);
2604
+ setSrc(objectUrl);
2605
+ return () => {
2606
+ URL.revokeObjectURL(objectUrl);
2607
+ };
2608
+ }, [file]);
2609
+ return src;
2610
+ };
2611
+ var useAttachmentSrc = () => {
2612
+ const { file, src } = useAssistantState(
2613
+ useShallow(({ attachment }) => {
2614
+ if (attachment.type !== "image") return {};
2615
+ if (attachment.file) return { file: attachment.file };
2616
+ const src2 = attachment.content?.filter((c) => c.type === "image")[0]?.image;
2617
+ if (!src2) return {};
2618
+ return { src: src2 };
2619
+ })
2620
+ );
2621
+ return useFileSrc(file) ?? src;
2622
+ };
2623
+ var AttachmentPreview = ({ src }) => {
2624
+ return /* @__PURE__ */ jsx(
2625
+ "img",
2626
+ {
2627
+ src,
2628
+ alt: "Image Preview",
2629
+ className: "aui-attachment-preview-image-loaded block h-auto max-h-[80vh] w-auto max-w-full object-contain"
2630
+ }
2631
+ );
2632
+ };
2633
+ var AttachmentPreviewDialog = ({ children }) => {
2634
+ const src = useAttachmentSrc();
2635
+ if (!src) return children;
2636
+ return /* @__PURE__ */ jsxs(Dialog, { children: [
2637
+ /* @__PURE__ */ jsx(
2638
+ DialogTrigger,
2639
+ {
2640
+ className: "aui-attachment-preview-trigger cursor-pointer transition-colors hover:bg-accent/50",
2641
+ asChild: true,
2642
+ children
2643
+ }
2644
+ ),
2645
+ /* @__PURE__ */ jsxs(DialogContent, { className: "aui-attachment-preview-dialog-content p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:bg-foreground/60 [&>button]:p-1 [&>button]:opacity-100 [&>button]:ring-0! [&_svg]:text-background [&>button]:hover:[&_svg]:text-destructive", children: [
2646
+ /* @__PURE__ */ jsx(DialogTitle, { className: "aui-sr-only sr-only", children: "Image Attachment Preview" }),
2647
+ /* @__PURE__ */ jsx("div", { className: "aui-attachment-preview relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden bg-background", children: /* @__PURE__ */ jsx(AttachmentPreview, { src }) })
2648
+ ] })
2649
+ ] });
2650
+ };
2651
+ var AttachmentThumb = () => {
2652
+ const isImage = useAssistantState(
2653
+ ({ attachment }) => attachment.type === "image"
2654
+ );
2655
+ const src = useAttachmentSrc();
2656
+ return /* @__PURE__ */ jsxs(Avatar2, { className: "aui-attachment-tile-avatar h-full w-full rounded-none", children: [
2657
+ /* @__PURE__ */ jsx(
2658
+ AvatarImage,
2659
+ {
2660
+ src,
2661
+ alt: "Attachment preview",
2662
+ className: "aui-attachment-tile-image object-cover"
2663
+ }
2664
+ ),
2665
+ /* @__PURE__ */ jsx(AvatarFallback, { delayMs: isImage ? 200 : 0, children: /* @__PURE__ */ jsx(FileText, { className: "aui-attachment-tile-fallback-icon size-8 text-muted-foreground" }) })
2666
+ ] });
2667
+ };
2668
+ var AttachmentUI = () => {
2669
+ const api = useAssistantApi();
2670
+ const isComposer = api.attachment.source === "composer";
2671
+ const isImage = useAssistantState(
2672
+ ({ attachment }) => attachment.type === "image"
2673
+ );
2674
+ const typeLabel = useAssistantState(({ attachment }) => {
2675
+ const type = attachment.type;
2676
+ switch (type) {
2677
+ case "image":
2678
+ return "Image";
2679
+ case "document":
2680
+ return "Document";
2681
+ case "file":
2682
+ return "File";
2683
+ default:
2684
+ return "File";
2685
+ }
2686
+ });
2687
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
2688
+ /* @__PURE__ */ jsxs(
2689
+ AttachmentPrimitive.Root,
2690
+ {
2691
+ className: cn(
2692
+ "aui-attachment-root relative",
2693
+ isImage && "aui-attachment-root-composer only:[&>#attachment-tile]:size-24"
2694
+ ),
2695
+ children: [
2696
+ /* @__PURE__ */ jsx(AttachmentPreviewDialog, { children: /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2697
+ "div",
2698
+ {
2699
+ className: cn(
2700
+ "aui-attachment-tile size-14 cursor-pointer overflow-hidden rounded-[14px] border bg-muted transition-opacity hover:opacity-75",
2701
+ isComposer && "aui-attachment-tile-composer border-foreground/20"
2702
+ ),
2703
+ role: "button",
2704
+ id: "attachment-tile",
2705
+ "aria-label": `${typeLabel} attachment`,
2706
+ children: /* @__PURE__ */ jsx(AttachmentThumb, {})
2707
+ }
2708
+ ) }) }),
2709
+ isComposer && /* @__PURE__ */ jsx(AttachmentRemove, {})
2710
+ ]
2711
+ }
2712
+ ),
2713
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: /* @__PURE__ */ jsx(AttachmentPrimitive.Name, {}) })
2714
+ ] });
2715
+ };
2716
+ var AttachmentRemove = () => {
2717
+ return /* @__PURE__ */ jsx(AttachmentPrimitive.Remove, { asChild: true, children: /* @__PURE__ */ jsx(
2718
+ TooltipIconButton,
2719
+ {
2720
+ tooltip: "Remove file",
2721
+ className: "aui-attachment-tile-remove absolute top-1.5 right-1.5 size-3.5 rounded-full bg-white text-muted-foreground opacity-100 shadow-sm hover:bg-white! [&_svg]:text-black hover:[&_svg]:text-destructive",
2722
+ side: "top",
2723
+ children: /* @__PURE__ */ jsx(XIcon, { className: "aui-attachment-remove-icon size-3 dark:stroke-[2.5px]" })
2724
+ }
2725
+ ) });
2726
+ };
2727
+ var UserMessageAttachments = () => {
2728
+ return /* @__PURE__ */ jsx("div", { className: "aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2", children: /* @__PURE__ */ jsx(MessagePrimitive.Attachments, { components: { Attachment: AttachmentUI } }) });
2729
+ };
2730
+ var ComposerAttachments = () => {
2731
+ return /* @__PURE__ */ jsx("div", { className: "aui-composer-attachments mb-2 flex w-full flex-row items-center gap-2 overflow-x-auto px-1.5 pt-0.5 pb-1 empty:hidden", children: /* @__PURE__ */ jsx(
2732
+ ComposerPrimitive.Attachments,
2733
+ {
2734
+ components: { Attachment: AttachmentUI }
2735
+ }
2736
+ ) });
2737
+ };
2738
+ var ComposerAddAttachment = () => {
2739
+ return /* @__PURE__ */ jsx(ComposerPrimitive.AddAttachment, { asChild: true, children: /* @__PURE__ */ jsx(
2740
+ TooltipIconButton,
2741
+ {
2742
+ tooltip: "Add Attachment",
2743
+ side: "bottom",
2744
+ variant: "ghost",
2745
+ size: "icon",
2746
+ className: "aui-composer-add-attachment size-[34px] rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30",
2747
+ "aria-label": "Add Attachment",
2748
+ children: /* @__PURE__ */ jsx(PaperclipIcon, { className: "aui-attachment-add-icon size-5 stroke-[1.5px]" })
2749
+ }
2750
+ ) });
2751
+ };
2752
+ var MarkdownTextImpl = () => {
2753
+ return /* @__PURE__ */ jsx(
2754
+ MarkdownTextPrimitive,
2755
+ {
2756
+ remarkPlugins: [remarkGfm],
2757
+ className: "aui-md",
2758
+ components: defaultComponents
2759
+ }
2760
+ );
2761
+ };
2762
+ var MarkdownText = memo(MarkdownTextImpl);
2763
+ var CodeHeader = ({ language, code }) => {
2764
+ const { isCopied, copyToClipboard } = useCopyToClipboard2();
2765
+ const onCopy = () => {
2766
+ if (!code || isCopied) return;
2767
+ copyToClipboard(code);
2768
+ };
2769
+ return /* @__PURE__ */ jsxs("div", { className: "aui-code-header-root mt-4 flex items-center justify-between gap-4 rounded-t-lg bg-muted-foreground/15 px-4 py-2 font-semibold text-foreground text-sm dark:bg-muted-foreground/20", children: [
2770
+ /* @__PURE__ */ jsx("span", { className: "aui-code-header-language lowercase [&>span]:text-xs", children: language }),
2771
+ /* @__PURE__ */ jsxs(TooltipIconButton, { tooltip: "Copy", onClick: onCopy, children: [
2772
+ !isCopied && /* @__PURE__ */ jsx(CopyIcon, {}),
2773
+ isCopied && /* @__PURE__ */ jsx(CheckIcon, {})
2774
+ ] })
2775
+ ] });
2776
+ };
2777
+ var useCopyToClipboard2 = ({
2778
+ copiedDuration = 3e3
2779
+ } = {}) => {
2780
+ const [isCopied, setIsCopied] = useState(false);
2781
+ const copyToClipboard = (value) => {
2782
+ if (!value) return;
2783
+ navigator.clipboard.writeText(value).then(() => {
2784
+ setIsCopied(true);
2785
+ setTimeout(() => setIsCopied(false), copiedDuration);
2786
+ });
2787
+ };
2788
+ return { isCopied, copyToClipboard };
2789
+ };
2790
+ var defaultComponents = unstable_memoizeMarkdownComponents({
2791
+ h1: ({ className, ...props }) => /* @__PURE__ */ jsx(
2792
+ "h1",
2793
+ {
2794
+ className: cn(
2795
+ "aui-md-h1 mb-8 scroll-m-20 font-extrabold text-4xl tracking-tight last:mb-0",
2796
+ className
2797
+ ),
2798
+ ...props
2799
+ }
2800
+ ),
2801
+ h2: ({ className, ...props }) => /* @__PURE__ */ jsx(
2802
+ "h2",
2803
+ {
2804
+ className: cn(
2805
+ "aui-md-h2 mt-8 mb-4 scroll-m-20 font-semibold text-3xl tracking-tight first:mt-0 last:mb-0",
2806
+ className
2807
+ ),
2808
+ ...props
2809
+ }
2810
+ ),
2811
+ h3: ({ className, ...props }) => /* @__PURE__ */ jsx(
2812
+ "h3",
2813
+ {
2814
+ className: cn(
2815
+ "aui-md-h3 mt-6 mb-4 scroll-m-20 font-semibold text-2xl tracking-tight first:mt-0 last:mb-0",
2816
+ className
2817
+ ),
2818
+ ...props
2819
+ }
2820
+ ),
2821
+ h4: ({ className, ...props }) => /* @__PURE__ */ jsx(
2822
+ "h4",
2823
+ {
2824
+ className: cn(
2825
+ "aui-md-h4 mt-6 mb-4 scroll-m-20 font-semibold text-xl tracking-tight first:mt-0 last:mb-0",
2826
+ className
2827
+ ),
2828
+ ...props
2829
+ }
2830
+ ),
2831
+ h5: ({ className, ...props }) => /* @__PURE__ */ jsx(
2832
+ "h5",
2833
+ {
2834
+ className: cn(
2835
+ "aui-md-h5 my-4 font-semibold text-lg first:mt-0 last:mb-0",
2836
+ className
2837
+ ),
2838
+ ...props
2839
+ }
2840
+ ),
2841
+ h6: ({ className, ...props }) => /* @__PURE__ */ jsx(
2842
+ "h6",
2843
+ {
2844
+ className: cn(
2845
+ "aui-md-h6 my-4 font-semibold first:mt-0 last:mb-0",
2846
+ className
2847
+ ),
2848
+ ...props
2849
+ }
2850
+ ),
2851
+ p: ({ className, ...props }) => /* @__PURE__ */ jsx(
2852
+ "p",
2853
+ {
2854
+ className: cn(
2855
+ "aui-md-p mt-5 mb-5 leading-7 first:mt-0 last:mb-0",
2856
+ className
2857
+ ),
2858
+ ...props
2859
+ }
2860
+ ),
2861
+ a: ({ className, ...props }) => /* @__PURE__ */ jsx(
2862
+ "a",
2863
+ {
2864
+ className: cn(
2865
+ "aui-md-a font-medium text-primary underline underline-offset-4",
2866
+ className
2867
+ ),
2868
+ ...props
2869
+ }
2870
+ ),
2871
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ jsx(
2872
+ "blockquote",
2873
+ {
2874
+ className: cn("aui-md-blockquote border-l-2 pl-6 italic", className),
2875
+ ...props
2876
+ }
2877
+ ),
2878
+ ul: ({ className, ...props }) => /* @__PURE__ */ jsx(
2879
+ "ul",
2880
+ {
2881
+ className: cn("aui-md-ul my-5 ml-6 list-disc [&>li]:mt-2", className),
2882
+ ...props
2883
+ }
2884
+ ),
2885
+ ol: ({ className, ...props }) => /* @__PURE__ */ jsx(
2886
+ "ol",
2887
+ {
2888
+ className: cn("aui-md-ol my-5 ml-6 list-decimal [&>li]:mt-2", className),
2889
+ ...props
2890
+ }
2891
+ ),
2892
+ hr: ({ className, ...props }) => /* @__PURE__ */ jsx("hr", { className: cn("aui-md-hr my-5 border-b", className), ...props }),
2893
+ table: ({ className, ...props }) => /* @__PURE__ */ jsx(
2894
+ "table",
2895
+ {
2896
+ className: cn(
2897
+ "aui-md-table my-5 w-full border-separate border-spacing-0 overflow-y-auto",
2898
+ className
2899
+ ),
2900
+ ...props
2901
+ }
2902
+ ),
2903
+ th: ({ className, ...props }) => /* @__PURE__ */ jsx(
2904
+ "th",
2905
+ {
2906
+ className: cn(
2907
+ "aui-md-th bg-muted px-4 py-2 text-left font-bold first:rounded-tl-lg last:rounded-tr-lg [[align=center]]:text-center [[align=right]]:text-right",
2908
+ className
2909
+ ),
2910
+ ...props
2911
+ }
2912
+ ),
2913
+ td: ({ className, ...props }) => /* @__PURE__ */ jsx(
2914
+ "td",
2915
+ {
2916
+ className: cn(
2917
+ "aui-md-td border-b border-l px-4 py-2 text-left last:border-r [[align=center]]:text-center [[align=right]]:text-right",
2918
+ className
2919
+ ),
2920
+ ...props
2921
+ }
2922
+ ),
2923
+ tr: ({ className, ...props }) => /* @__PURE__ */ jsx(
2924
+ "tr",
2925
+ {
2926
+ className: cn(
2927
+ "aui-md-tr m-0 border-b p-0 first:border-t [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg",
2928
+ className
2929
+ ),
2930
+ ...props
2931
+ }
2932
+ ),
2933
+ sup: ({ className, ...props }) => /* @__PURE__ */ jsx(
2934
+ "sup",
2935
+ {
2936
+ className: cn("aui-md-sup [&>a]:text-xs [&>a]:no-underline", className),
2937
+ ...props
2938
+ }
2939
+ ),
2940
+ pre: ({ className, ...props }) => /* @__PURE__ */ jsx(
2941
+ "pre",
2942
+ {
2943
+ className: cn(
2944
+ "aui-md-pre overflow-x-auto rounded-t-none! rounded-b-lg bg-black p-4 text-white",
2945
+ className
2946
+ ),
2947
+ ...props
2948
+ }
2949
+ ),
2950
+ code: function Code({ className, ...props }) {
2951
+ const isCodeBlock = useIsMarkdownCodeBlock();
2952
+ return /* @__PURE__ */ jsx(
2953
+ "code",
2954
+ {
2955
+ className: cn(
2956
+ !isCodeBlock && "aui-md-inline-code rounded border bg-muted font-semibold",
2957
+ className
2958
+ ),
2959
+ ...props
2960
+ }
2961
+ );
2962
+ },
2963
+ CodeHeader
2964
+ });
2965
+ var ToolFallback = ({
2966
+ toolName,
2967
+ argsText,
2968
+ result,
2969
+ status
2970
+ }) => {
2971
+ const isStreaming = status?.type === "running";
2972
+ const isError = status?.type === "incomplete";
2973
+ const isCancelled = status?.type === "incomplete" && status.reason === "cancelled";
2974
+ const cancelledReason = isCancelled && status.error ? typeof status.error === "string" ? status.error : JSON.stringify(status.error) : null;
2975
+ const titlePrefix = isCancelled ? "Cancelled: " : isStreaming ? "Running: " : "";
2976
+ return /* @__PURE__ */ jsx(
2977
+ ToolCard,
2978
+ {
2979
+ title: `${titlePrefix}${toolName}`,
2980
+ isStreaming,
2981
+ isError,
2982
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 text-white", children: [
2983
+ cancelledReason && /* @__PURE__ */ jsxs("div", { children: [
2984
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Cancelled reason:" }),
2985
+ /* @__PURE__ */ jsx("p", { className: "text-white/60", children: cancelledReason })
2986
+ ] }),
2987
+ /* @__PURE__ */ jsxs("div", { className: cn(isCancelled && "opacity-60"), children: [
2988
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Arguments:" }),
2989
+ /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap bg-black/20 p-1.5 rounded text-white/80", children: argsText })
2990
+ ] }),
2991
+ !isCancelled && result !== void 0 && /* @__PURE__ */ jsxs("div", { className: "border-t border-white/10 pt-2", children: [
2992
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-white/70 mb-0.5", children: "Result:" }),
2993
+ /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap bg-black/20 p-1.5 rounded text-white/80", children: typeof result === "string" ? result : JSON.stringify(result, null, 2) })
2994
+ ] })
2995
+ ] })
2996
+ }
2997
+ );
2998
+ };
2999
+ var ContextPill = ({
3000
+ label,
3001
+ onRemove,
3002
+ readonly = false,
3003
+ className
3004
+ }) => {
3005
+ const showRemoveButton = !readonly && onRemove;
3006
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
3007
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
3008
+ "div",
3009
+ {
3010
+ className: cn(
3011
+ "group flex items-center gap-1 rounded-md border border-muted-foreground py-1 px-1.5 text-xs",
3012
+ "max-w-[200px] cursor-default",
3013
+ className
3014
+ ),
3015
+ children: [
3016
+ showRemoveButton && /* @__PURE__ */ jsx(
3017
+ "button",
3018
+ {
3019
+ onClick: onRemove,
3020
+ "aria-label": `Remove ${label}`,
3021
+ className: "shrink-0 hover:text-destructive transition-colors",
3022
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-3" })
3023
+ }
3024
+ ),
3025
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: label })
3026
+ ]
3027
+ }
3028
+ ) }),
3029
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", sideOffset: 4, children: label })
3030
+ ] });
3031
+ };
3032
+ function Popover({
3033
+ modal = false,
3034
+ ...props
3035
+ }) {
3036
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { modal, ...props });
3037
+ }
3038
+ function PopoverTrigger({
3039
+ ...props
3040
+ }) {
3041
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { ...props });
3042
+ }
3043
+ function PopoverContent({
3044
+ className,
3045
+ align = "start",
3046
+ sideOffset = 4,
3047
+ ...props
3048
+ }) {
3049
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3050
+ PopoverPrimitive.Content,
3051
+ {
3052
+ align,
3053
+ sideOffset,
3054
+ className: cn(
3055
+ "z-[10000] w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none 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",
3056
+ className
3057
+ ),
3058
+ style: {
3059
+ zIndex: 1e4,
3060
+ borderColor: theme.colors.border,
3061
+ ...props.style
3062
+ },
3063
+ ...props
3064
+ }
3065
+ ) });
3066
+ }
3067
+ var TYPE_ICONS = {
3068
+ attachment: FileIcon,
3069
+ description: FileTextIcon,
3070
+ caption: VideoIcon,
3071
+ link: LinkIcon
3072
+ };
3073
+ var ContextMentionPopover = ({
3074
+ isOpen,
3075
+ onOpenChange,
3076
+ categories,
3077
+ isLoading,
3078
+ activeIndex,
3079
+ flattenedItems,
3080
+ onSelectItem,
3081
+ onActiveIndexChange,
3082
+ getCategoryLabel,
3083
+ trigger,
3084
+ searchTerm
3085
+ }) => {
3086
+ const activeItemRef = useRef(null);
3087
+ useEffect(() => {
3088
+ if (isOpen && activeItemRef.current) {
3089
+ activeItemRef.current.scrollIntoView({
3090
+ block: "nearest",
3091
+ behavior: "smooth"
3092
+ });
3093
+ }
3094
+ }, [activeIndex, isOpen]);
3095
+ const getFlattenedIndex = (categoryIndex, itemIndex) => {
3096
+ let index = 0;
3097
+ for (let i = 0; i < categoryIndex; i++) {
3098
+ index += categories[i].items.length;
3099
+ }
3100
+ return index + itemIndex;
3101
+ };
3102
+ const hasNoResults = !isLoading && flattenedItems.length === 0;
3103
+ return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange, modal: false, children: [
3104
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }),
3105
+ /* @__PURE__ */ jsx(
3106
+ PopoverContent,
3107
+ {
3108
+ className: "w-72 max-h-80 overflow-y-auto p-0",
3109
+ align: "start",
3110
+ side: "top",
3111
+ sideOffset: 8,
3112
+ onOpenAutoFocus: (e) => e.preventDefault(),
3113
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3114
+ /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 border-b border-border bg-popover px-3 py-2", children: /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: searchTerm ? `Searching for "${searchTerm}"` : "Select context to focus on" }) }),
3115
+ isLoading && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(LoaderIcon, { className: "size-5 animate-spin text-muted-foreground" }) }),
3116
+ hasNoResults && /* @__PURE__ */ jsxs("div", { className: "px-3 py-8 text-center text-sm text-muted-foreground", children: [
3117
+ "No context items found",
3118
+ searchTerm && /* @__PURE__ */ jsx("span", { className: "block text-xs mt-1", children: "Try a different search term" })
3119
+ ] }),
3120
+ !isLoading && categories.map((category, categoryIndex) => {
3121
+ if (category.items.length === 0) return null;
3122
+ const Icon = TYPE_ICONS[category.type] || FileIcon;
3123
+ return /* @__PURE__ */ jsxs("div", { className: "py-1", children: [
3124
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5", children: [
3125
+ /* @__PURE__ */ jsx(Icon, { className: "size-3.5 text-muted-foreground" }),
3126
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: getCategoryLabel(category.type) }),
3127
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground/60", children: [
3128
+ "(",
3129
+ category.items.length,
3130
+ ")"
3131
+ ] })
3132
+ ] }),
3133
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col", children: category.items.map((item, itemIndex) => {
3134
+ const flatIndex = getFlattenedIndex(
3135
+ categoryIndex,
3136
+ itemIndex
3137
+ );
3138
+ const isActive = flatIndex === activeIndex;
3139
+ return /* @__PURE__ */ jsxs(
3140
+ "button",
3141
+ {
3142
+ ref: isActive ? activeItemRef : null,
3143
+ type: "button",
3144
+ className: cn(
3145
+ "flex flex-col items-start px-3 py-2 text-left text-sm transition-colors",
3146
+ "hover:bg-accent/10",
3147
+ isActive && "bg-accent/20"
3148
+ ),
3149
+ onClick: () => onSelectItem(item),
3150
+ onMouseEnter: () => onActiveIndexChange(flatIndex),
3151
+ children: [
3152
+ /* @__PURE__ */ jsx("span", { className: "truncate w-full font-medium text-foreground", children: item.title }),
3153
+ (item.lessonTitle || item.chapterTitle) && /* @__PURE__ */ jsx("span", { className: "truncate w-full text-xs text-muted-foreground", children: item.chapterTitle && item.lessonTitle ? `${item.chapterTitle} > ${item.lessonTitle}` : item.lessonTitle || item.chapterTitle })
3154
+ ]
3155
+ },
3156
+ item.id
3157
+ );
3158
+ }) })
3159
+ ] }, category.type);
3160
+ })
3161
+ ] })
3162
+ }
3163
+ )
3164
+ ] });
3165
+ };
3166
+ var TYPE_ICON_SVGS = {
3167
+ attachment: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg>',
3168
+ description: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>',
3169
+ caption: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5"/><rect x="2" y="6" width="14" height="12" rx="2"/></svg>',
3170
+ link: '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>'
3171
+ };
3172
+ function getTypeIconSvg(type) {
3173
+ return TYPE_ICON_SVGS[type] || TYPE_ICON_SVGS.attachment;
3174
+ }
3175
+ var ZERO_WIDTH_SPACE = "\u200B";
3176
+ var MentionComposerInput = forwardRef(
3177
+ ({
3178
+ placeholder = "Ask, search, or make anything...",
3179
+ className,
3180
+ autoFocus = false,
3181
+ onInput,
3182
+ onKeyDown,
3183
+ onMentionRemove,
3184
+ onTriggerDetected,
3185
+ onTriggerDismissed,
3186
+ onSubmit
3187
+ }, ref) => {
3188
+ const editorRef = useRef(null);
3189
+ const composerRuntime = useComposerRuntime();
3190
+ const [isEmpty, setIsEmpty] = useState(true);
3191
+ const [inlineMentions, setInlineMentions] = useState([]);
3192
+ const triggerPositionRef = useRef(null);
3193
+ const getPlainText = useCallback(() => {
3194
+ const editor = editorRef.current;
3195
+ if (!editor) return "";
3196
+ let text = "";
3197
+ const walkNodes = (node2) => {
3198
+ if (node2.nodeType === Node.TEXT_NODE) {
3199
+ const nodeText = node2.textContent || "";
3200
+ text += nodeText.replace(/\u200B/g, "");
3201
+ } else if (node2.nodeType === Node.ELEMENT_NODE) {
3202
+ const element = node2;
3203
+ if (element.dataset.mentionId) {
3204
+ const title = element.dataset.mentionTitle || "";
3205
+ text += `[${title}]`;
3206
+ } else if (element.tagName === "BR") {
3207
+ text += "\n";
3208
+ } else {
3209
+ node2.childNodes.forEach(walkNodes);
3210
+ }
3211
+ }
3212
+ };
3213
+ editor.childNodes.forEach(walkNodes);
3214
+ return text.trim();
3215
+ }, []);
3216
+ const getCursorPosition = useCallback(() => {
3217
+ const selection = window.getSelection();
3218
+ if (!selection || !selection.rangeCount) return 0;
3219
+ const range = selection.getRangeAt(0);
3220
+ const preCaretRange = range.cloneRange();
3221
+ preCaretRange.selectNodeContents(editorRef.current);
3222
+ preCaretRange.setEnd(range.endContainer, range.endOffset);
3223
+ let position2 = 0;
3224
+ const walkNodes = (node2) => {
3225
+ if (node2 === range.endContainer) {
3226
+ if (node2.nodeType === Node.TEXT_NODE) {
3227
+ position2 += range.endOffset;
3228
+ }
3229
+ return true;
3230
+ }
3231
+ if (node2.nodeType === Node.TEXT_NODE) {
3232
+ const text = (node2.textContent || "").replace(/\u200B/g, "");
3233
+ position2 += text.length;
3234
+ } else if (node2.nodeType === Node.ELEMENT_NODE) {
3235
+ const element = node2;
3236
+ if (element.dataset.mentionId) {
3237
+ const title = element.dataset.mentionTitle || "";
3238
+ position2 += title.length + 2;
3239
+ } else if (element.tagName === "BR") {
3240
+ position2 += 1;
3241
+ } else {
3242
+ for (const child of Array.from(node2.childNodes)) {
3243
+ if (walkNodes(child)) return true;
3244
+ }
3245
+ }
3246
+ }
3247
+ return false;
3248
+ };
3249
+ if (editorRef.current) {
3250
+ for (const child of Array.from(editorRef.current.childNodes)) {
3251
+ if (walkNodes(child)) break;
3252
+ }
3253
+ }
3254
+ return position2;
3255
+ }, []);
3256
+ const syncToRuntime = useCallback(() => {
3257
+ const text = getPlainText();
3258
+ composerRuntime.setText(text);
3259
+ setIsEmpty(text.length === 0);
3260
+ }, [composerRuntime, getPlainText]);
3261
+ const handleInput = useCallback(() => {
3262
+ syncToRuntime();
3263
+ const text = getPlainText();
3264
+ const cursorPos = getCursorPosition();
3265
+ onInput?.({ text, cursorPosition: cursorPos });
3266
+ const editor = editorRef.current;
3267
+ if (!editor) return;
3268
+ const selection = window.getSelection();
3269
+ if (!selection || !selection.rangeCount) return;
3270
+ const range = selection.getRangeAt(0);
3271
+ let textBeforeCursor = "";
3272
+ let charCount = 0;
3273
+ const walkForText = (node2) => {
3274
+ if (node2 === range.endContainer) {
3275
+ if (node2.nodeType === Node.TEXT_NODE) {
3276
+ textBeforeCursor += (node2.textContent || "").slice(0, range.endOffset);
3277
+ }
3278
+ return true;
3279
+ }
3280
+ if (node2.nodeType === Node.TEXT_NODE) {
3281
+ textBeforeCursor += node2.textContent || "";
3282
+ charCount += (node2.textContent || "").length;
3283
+ } else if (node2.nodeType === Node.ELEMENT_NODE) {
3284
+ const element = node2;
3285
+ if (element.dataset.mentionId) {
3286
+ textBeforeCursor += " ";
3287
+ charCount += 1;
3288
+ } else {
3289
+ for (const child of Array.from(node2.childNodes)) {
3290
+ if (walkForText(child)) return true;
3291
+ }
3292
+ }
3293
+ }
3294
+ return false;
3295
+ };
3296
+ for (const child of Array.from(editor.childNodes)) {
3297
+ if (walkForText(child)) break;
3298
+ }
3299
+ const lastAtIndex = textBeforeCursor.lastIndexOf("@");
3300
+ if (lastAtIndex !== -1) {
3301
+ const charBeforeAt = lastAtIndex > 0 ? textBeforeCursor[lastAtIndex - 1] : " ";
3302
+ if (charBeforeAt === " " || charBeforeAt === "\n" || charBeforeAt === ZERO_WIDTH_SPACE || lastAtIndex === 0) {
3303
+ const searchText = textBeforeCursor.slice(lastAtIndex + 1);
3304
+ if (!searchText.includes(" ")) {
3305
+ triggerPositionRef.current = lastAtIndex;
3306
+ onTriggerDetected?.(searchText, lastAtIndex);
3307
+ return;
3308
+ }
3309
+ }
3310
+ }
3311
+ if (triggerPositionRef.current !== null) {
3312
+ triggerPositionRef.current = null;
3313
+ onTriggerDismissed?.();
3314
+ }
3315
+ }, [syncToRuntime, getPlainText, getCursorPosition, onInput, onTriggerDetected, onTriggerDismissed]);
3316
+ const handleKeyDown = useCallback(
3317
+ (e) => {
3318
+ if (e.key === "Enter" && !e.shiftKey) {
3319
+ if (onKeyDown) {
3320
+ onKeyDown(e);
3321
+ if (e.defaultPrevented) {
3322
+ return;
3323
+ }
3324
+ }
3325
+ e.preventDefault();
3326
+ const text = getPlainText();
3327
+ if (text.trim()) {
3328
+ onSubmit?.();
3329
+ }
3330
+ return;
3331
+ }
3332
+ if (e.key === "Backspace") {
3333
+ const selection = window.getSelection();
3334
+ if (!selection || !selection.rangeCount) return;
3335
+ const range = selection.getRangeAt(0);
3336
+ if (range.collapsed) {
3337
+ const container = range.startContainer;
3338
+ const offset = range.startOffset;
3339
+ if (container.nodeType === Node.TEXT_NODE && offset === 0) {
3340
+ let prevSibling = container.previousSibling;
3341
+ if (!prevSibling && container.parentElement !== editorRef.current) {
3342
+ prevSibling = container.parentElement?.previousSibling || null;
3343
+ }
3344
+ if (prevSibling && prevSibling.dataset?.mentionId) {
3345
+ e.preventDefault();
3346
+ const mentionId = prevSibling.dataset.mentionId;
3347
+ prevSibling.parentNode?.removeChild(prevSibling);
3348
+ setInlineMentions((prev2) => prev2.filter((m) => m.id !== mentionId));
3349
+ onMentionRemove?.(mentionId);
3350
+ syncToRuntime();
3351
+ return;
3352
+ }
3353
+ }
3354
+ if (container.nodeType === Node.ELEMENT_NODE) {
3355
+ const element = container;
3356
+ const childAtOffset = element.childNodes[offset - 1];
3357
+ if (childAtOffset && childAtOffset.dataset?.mentionId) {
3358
+ e.preventDefault();
3359
+ const mentionId = childAtOffset.dataset.mentionId;
3360
+ childAtOffset.parentNode?.removeChild(childAtOffset);
3361
+ setInlineMentions((prev2) => prev2.filter((m) => m.id !== mentionId));
3362
+ onMentionRemove?.(mentionId);
3363
+ syncToRuntime();
3364
+ return;
3365
+ }
3366
+ }
3367
+ }
3368
+ }
3369
+ onKeyDown?.(e);
3370
+ },
3371
+ [onKeyDown, onMentionRemove, syncToRuntime, onSubmit, getPlainText]
3372
+ );
3373
+ const insertMention = useCallback(
3374
+ (mention) => {
3375
+ const editor = editorRef.current;
3376
+ if (!editor) return;
3377
+ const selection = window.getSelection();
3378
+ if (!selection || !selection.rangeCount) return;
3379
+ const range = selection.getRangeAt(0);
3380
+ if (triggerPositionRef.current !== null) {
3381
+ let currentPos = 0;
3382
+ let foundNode = null;
3383
+ let foundOffset = 0;
3384
+ const findAtPosition = (node2) => {
3385
+ if (node2.nodeType === Node.TEXT_NODE) {
3386
+ const text = node2.textContent || "";
3387
+ const targetPosInNode = triggerPositionRef.current - currentPos;
3388
+ if (targetPosInNode >= 0 && targetPosInNode < text.length) {
3389
+ foundNode = node2;
3390
+ foundOffset = targetPosInNode;
3391
+ return true;
3392
+ }
3393
+ currentPos += text.length;
3394
+ } else if (node2.nodeType === Node.ELEMENT_NODE) {
3395
+ const element = node2;
3396
+ if (element.dataset.mentionId) {
3397
+ currentPos += 1;
3398
+ } else {
3399
+ for (const child of Array.from(node2.childNodes)) {
3400
+ if (findAtPosition(child)) return true;
3401
+ }
3402
+ }
3403
+ }
3404
+ return false;
3405
+ };
3406
+ for (const child of Array.from(editor.childNodes)) {
3407
+ if (findAtPosition(child)) break;
3408
+ }
3409
+ if (foundNode) {
3410
+ const deleteRange = document.createRange();
3411
+ deleteRange.setStart(foundNode, foundOffset);
3412
+ deleteRange.setEnd(range.endContainer, range.endOffset);
3413
+ deleteRange.deleteContents();
3414
+ }
3415
+ }
3416
+ const mentionEl = document.createElement("span");
3417
+ mentionEl.className = "inline-flex items-center gap-1 rounded-md border border-muted-foreground py-0.5 px-1.5 text-xs mx-0.5 cursor-default select-none bg-muted/50 max-w-[350px]";
3418
+ mentionEl.contentEditable = "false";
3419
+ mentionEl.dataset.mentionId = mention.id;
3420
+ mentionEl.dataset.mentionTitle = mention.title;
3421
+ if (mention.icon) {
3422
+ const iconImg = document.createElement("img");
3423
+ iconImg.src = mention.icon;
3424
+ iconImg.className = "size-3.5 rounded-sm shrink-0";
3425
+ iconImg.alt = "";
3426
+ mentionEl.appendChild(iconImg);
3427
+ } else if (mention.type) {
3428
+ const iconSpan = document.createElement("span");
3429
+ iconSpan.className = "size-3.5 shrink-0 flex items-center justify-center";
3430
+ iconSpan.innerHTML = getTypeIconSvg(mention.type);
3431
+ mentionEl.appendChild(iconSpan);
3432
+ }
3433
+ const titleSpan = document.createElement("span");
3434
+ titleSpan.className = "truncate";
3435
+ titleSpan.textContent = mention.title;
3436
+ mentionEl.appendChild(titleSpan);
3437
+ const insertRange = selection.getRangeAt(0);
3438
+ insertRange.insertNode(mentionEl);
3439
+ const spaceNode = document.createTextNode(" ");
3440
+ mentionEl.after(spaceNode);
3441
+ const newRange = document.createRange();
3442
+ newRange.setStartAfter(spaceNode);
3443
+ newRange.collapse(true);
3444
+ selection.removeAllRanges();
3445
+ selection.addRange(newRange);
3446
+ setInlineMentions((prev2) => [...prev2, mention]);
3447
+ triggerPositionRef.current = null;
3448
+ syncToRuntime();
3449
+ setTimeout(() => {
3450
+ editorRef.current?.focus();
3451
+ }, 10);
3452
+ },
3453
+ [syncToRuntime]
3454
+ );
3455
+ useImperativeHandle(
3456
+ ref,
3457
+ () => ({
3458
+ focus: () => editorRef.current?.focus(),
3459
+ getValue: getPlainText,
3460
+ insertMention,
3461
+ getInlineMentions: () => inlineMentions
3462
+ }),
3463
+ [getPlainText, insertMention, inlineMentions]
3464
+ );
3465
+ useEffect(() => {
3466
+ if (autoFocus) {
3467
+ editorRef.current?.focus();
3468
+ }
3469
+ }, [autoFocus]);
3470
+ useEffect(() => {
3471
+ const unsubscribe = composerRuntime.subscribe(() => {
3472
+ const composerState = composerRuntime.getState();
3473
+ if (composerState.text === "" && editorRef.current) {
3474
+ editorRef.current.innerHTML = "";
3475
+ setInlineMentions([]);
3476
+ setIsEmpty(true);
3477
+ }
3478
+ });
3479
+ return unsubscribe;
3480
+ }, [composerRuntime]);
3481
+ const handlePaste = useCallback((e) => {
3482
+ e.preventDefault();
3483
+ const text = e.clipboardData.getData("text/plain");
3484
+ document.execCommand("insertText", false, text);
3485
+ }, []);
3486
+ return /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
3487
+ "div",
3488
+ {
3489
+ ref: editorRef,
3490
+ contentEditable: true,
3491
+ role: "textbox",
3492
+ "aria-label": "Message input",
3493
+ "data-placeholder": placeholder,
3494
+ className: cn(
3495
+ "aui-composer-input mb-1 max-h-32 min-h-14 w-full resize-none bg-transparent px-4 pt-2 pb-3 text-sm outline-none",
3496
+ "overflow-y-auto whitespace-pre-wrap wrap-break-word",
3497
+ "focus:outline-none focus-visible:ring-0",
3498
+ // Placeholder styling using data attribute
3499
+ "empty:before:content-[attr(data-placeholder)] empty:before:text-muted-foreground empty:before:pointer-events-none",
3500
+ className
3501
+ ),
3502
+ onInput: handleInput,
3503
+ onKeyDown: handleKeyDown,
3504
+ onPaste: handlePaste,
3505
+ suppressContentEditableWarning: true
3506
+ }
3507
+ ) });
3508
+ }
3509
+ );
3510
+ MentionComposerInput.displayName = "MentionComposerInput";
3511
+ var TYPE_ICONS2 = {
3512
+ attachment: FileIcon,
3513
+ description: FileTextIcon,
3514
+ caption: VideoIcon,
3515
+ link: LinkIcon
3516
+ };
3517
+ var InlineContextPill = ({
3518
+ title,
3519
+ type = "attachment",
3520
+ className
3521
+ }) => {
3522
+ const Icon = TYPE_ICONS2[type] || FileIcon;
3523
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
3524
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
3525
+ "span",
3526
+ {
3527
+ className: cn(
3528
+ "inline-flex items-center gap-1 rounded-md border border-muted-foreground/50 py-0.5 px-1.5 text-xs mx-0.5",
3529
+ "max-w-[350px] cursor-default bg-muted/30 align-middle",
3530
+ className
3531
+ ),
3532
+ children: [
3533
+ /* @__PURE__ */ jsx(Icon, { className: "size-3 shrink-0" }),
3534
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: title })
3535
+ ]
3536
+ }
3537
+ ) }),
3538
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", sideOffset: 4, children: title })
3539
+ ] });
3540
+ };
3541
+ function parseMessageContent(text) {
3542
+ const parts = [];
3543
+ const regex = /\[([^\]]+)\]/g;
3544
+ let lastIndex = 0;
3545
+ let match2;
3546
+ while ((match2 = regex.exec(text)) !== null) {
3547
+ if (match2.index > lastIndex) {
3548
+ parts.push({
3549
+ type: "text",
3550
+ content: text.slice(lastIndex, match2.index)
3551
+ });
3552
+ }
3553
+ parts.push({
3554
+ type: "context",
3555
+ content: match2[1]
3556
+ // The title inside brackets
3557
+ });
3558
+ lastIndex = match2.index + match2[0].length;
3559
+ }
3560
+ if (lastIndex < text.length) {
3561
+ parts.push({
3562
+ type: "text",
3563
+ content: text.slice(lastIndex)
3564
+ });
3565
+ }
3566
+ return parts;
3567
+ }
3568
+ var UserMessageContent = () => {
3569
+ const message = useMessage();
3570
+ const renderedContent = useMemo(() => {
3571
+ const textParts = message.content?.filter(
3572
+ (part) => part.type === "text"
3573
+ );
3574
+ if (!textParts || textParts.length === 0) {
3575
+ return null;
3576
+ }
3577
+ const fullText = textParts.map((part) => part.text).join("");
3578
+ const parsed = parseMessageContent(fullText);
3579
+ return parsed.map((part, index) => {
3580
+ if (part.type === "context") {
3581
+ return /* @__PURE__ */ jsx(
3582
+ InlineContextPill,
3583
+ {
3584
+ title: part.content
3585
+ },
3586
+ `context-${index}`
3587
+ );
3588
+ }
3589
+ return /* @__PURE__ */ jsx("span", { children: part.content }, `text-${index}`);
3590
+ });
3591
+ }, [message.content]);
3592
+ return /* @__PURE__ */ jsx(Fragment, { children: renderedContent });
3593
+ };
3594
+ var CATEGORY_LABELS = {
3595
+ attachment: "Attachments",
3596
+ description: "Description",
3597
+ caption: "Video",
3598
+ link: "Links"
3599
+ };
3600
+ function useContextMention(options = {}) {
3601
+ const { onInsertMention } = options;
3602
+ const widgetContext = useContext(WidgetContext);
3603
+ if (!widgetContext) {
3604
+ throw new Error("useContextMention must be used within a WidgetProvider");
3605
+ }
3606
+ const { client } = widgetContext;
3607
+ const { selectedContext: selectedItems, addContextItem, removeContextItem, clearContext } = useMessageContext();
3608
+ const [isOpen, setIsOpen] = useState(false);
3609
+ const [searchTerm, setSearchTerm] = useState("");
3610
+ const [activeIndex, setActiveIndex] = useState(0);
3611
+ const [isLoading, setIsLoading] = useState(false);
3612
+ const [categories, setCategories] = useState([]);
3613
+ const [hasMore, setHasMore] = useState(false);
3614
+ const config = client.getConfig();
3615
+ const baseUrl = config.baseUrl || "http://localhost:3000";
3616
+ const assistantId = config.apiKey;
3617
+ const fetchContextItems = useCallback(
3618
+ async (search = "", limit = 10) => {
3619
+ setIsLoading(true);
3620
+ try {
3621
+ const params = new URLSearchParams({
3622
+ limit: limit.toString()
3623
+ });
3624
+ if (search) {
3625
+ params.set("search", search);
3626
+ }
3627
+ const response = await fetch(
3628
+ `${baseUrl}/api/widget/context?${params.toString()}`,
3629
+ {
3630
+ headers: {
3631
+ "Content-Type": "application/json",
3632
+ "X-Assistant-Id": assistantId
3633
+ }
3634
+ }
3635
+ );
3636
+ if (!response.ok) {
3637
+ console.error("[ContextMention] Failed to fetch context:", response.status);
3638
+ return;
3639
+ }
3640
+ const data = await response.json();
3641
+ setCategories(data.categories);
3642
+ setHasMore(data.hasMore);
3643
+ } catch (error) {
3644
+ console.error("[ContextMention] Error fetching context:", error);
3645
+ } finally {
3646
+ setIsLoading(false);
3647
+ }
3648
+ },
3649
+ [baseUrl, assistantId]
3650
+ );
3651
+ const openPopover = useCallback(() => {
3652
+ setIsOpen(true);
3653
+ setSearchTerm("");
3654
+ setActiveIndex(0);
3655
+ fetchContextItems();
3656
+ }, [fetchContextItems]);
3657
+ const closePopover = useCallback(() => {
3658
+ setIsOpen(false);
3659
+ setSearchTerm("");
3660
+ setActiveIndex(0);
3661
+ }, []);
3662
+ const updateSearch = useCallback(
3663
+ (term) => {
3664
+ setSearchTerm(term);
3665
+ setActiveIndex(0);
3666
+ fetchContextItems(term);
3667
+ },
3668
+ [fetchContextItems]
3669
+ );
3670
+ const flattenedItems = useMemo(() => {
3671
+ return categories.flatMap((category) => category.items);
3672
+ }, [categories]);
3673
+ const navigateDown = useCallback(() => {
3674
+ setActiveIndex(
3675
+ (prev2) => prev2 < flattenedItems.length - 1 ? prev2 + 1 : prev2
3676
+ );
3677
+ }, [flattenedItems.length]);
3678
+ const navigateUp = useCallback(() => {
3679
+ setActiveIndex((prev2) => prev2 > 0 ? prev2 - 1 : 0);
3680
+ }, []);
3681
+ const selectActiveItem = useCallback(() => {
3682
+ const item = flattenedItems[activeIndex];
3683
+ if (item) {
3684
+ addContextItem(item);
3685
+ closePopover();
3686
+ onInsertMention?.(item);
3687
+ }
3688
+ }, [flattenedItems, activeIndex, addContextItem, closePopover, onInsertMention]);
3689
+ const selectItem = useCallback(
3690
+ (item) => {
3691
+ addContextItem(item);
3692
+ closePopover();
3693
+ onInsertMention?.(item);
3694
+ },
3695
+ [addContextItem, closePopover, onInsertMention]
3696
+ );
3697
+ const removeItem = useCallback((itemId) => {
3698
+ removeContextItem(itemId);
3699
+ }, [removeContextItem]);
3700
+ const clearAll = useCallback(() => {
3701
+ clearContext();
3702
+ }, [clearContext]);
3703
+ const handleKeyDown = useCallback(
3704
+ (event) => {
3705
+ if (!isOpen) return;
3706
+ switch (event.key) {
3707
+ case "ArrowDown":
3708
+ event.preventDefault();
3709
+ navigateDown();
3710
+ break;
3711
+ case "ArrowUp":
3712
+ event.preventDefault();
3713
+ navigateUp();
3714
+ break;
3715
+ case "Enter":
3716
+ event.preventDefault();
3717
+ selectActiveItem();
3718
+ break;
3719
+ case "Escape":
3720
+ event.preventDefault();
3721
+ closePopover();
3722
+ break;
3723
+ }
3724
+ },
3725
+ [isOpen, navigateDown, navigateUp, selectActiveItem, closePopover]
3726
+ );
3727
+ const getCategoryLabel = useCallback((type) => {
3728
+ return CATEGORY_LABELS[type] || type;
3729
+ }, []);
3730
+ return {
3731
+ // Selected items
3732
+ selectedItems,
3733
+ selectItem,
3734
+ removeItem,
3735
+ clearAll,
3736
+ // Popover state
3737
+ isOpen,
3738
+ openPopover,
3739
+ closePopover,
3740
+ // Search
3741
+ searchTerm,
3742
+ updateSearch,
3743
+ // Navigation
3744
+ activeIndex,
3745
+ setActiveIndex,
3746
+ navigateUp,
3747
+ navigateDown,
3748
+ selectActiveItem,
3749
+ handleKeyDown,
3750
+ // Data
3751
+ categories,
3752
+ flattenedItems,
3753
+ isLoading,
3754
+ hasMore,
3755
+ // Utilities
3756
+ getCategoryLabel
3757
+ };
3758
+ }
3759
+ var Thread = () => {
3760
+ return /* @__PURE__ */ jsx(
3761
+ ThreadPrimitive.Root,
3762
+ {
3763
+ className: "aui-thread-root @container flex h-full flex-col bg-background",
3764
+ style: {
3765
+ ["--thread-max-width"]: "44rem"
3766
+ },
3767
+ children: /* @__PURE__ */ jsxs(
3768
+ ThreadPrimitive.Viewport,
3769
+ {
3770
+ className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4",
3771
+ children: [
3772
+ /* @__PURE__ */ jsx(AssistantIf, { condition: ({ thread }) => thread.isEmpty, children: /* @__PURE__ */ jsx(ThreadWelcome, {}) }),
3773
+ /* @__PURE__ */ jsx(
3774
+ ThreadPrimitive.Messages,
3775
+ {
3776
+ components: {
3777
+ UserMessage,
3778
+ EditComposer,
3779
+ AssistantMessage
3780
+ }
3781
+ }
3782
+ ),
3783
+ /* @__PURE__ */ jsxs(ThreadPrimitive.ViewportFooter, { className: "aui-thread-viewport-footer sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-3xl bg-background pb-4", children: [
3784
+ /* @__PURE__ */ jsx(ThreadScrollToBottom, {}),
3785
+ /* @__PURE__ */ jsx(Composer, {})
3786
+ ] })
3787
+ ]
3788
+ }
3789
+ )
3790
+ }
3791
+ );
3792
+ };
3793
+ var ThreadScrollToBottom = () => {
3794
+ return /* @__PURE__ */ jsx(ThreadPrimitive.ScrollToBottom, { asChild: true, children: /* @__PURE__ */ jsx(
3795
+ TooltipIconButton,
3796
+ {
3797
+ tooltip: "Scroll to bottom",
3798
+ variant: "outline",
3799
+ className: "aui-thread-scroll-to-bottom absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:bg-background dark:hover:bg-accent",
3800
+ children: /* @__PURE__ */ jsx(ArrowDownIcon, {})
3801
+ }
3802
+ ) });
3803
+ };
3804
+ var getGreeting = () => {
3805
+ const hour = (/* @__PURE__ */ new Date()).getHours();
3806
+ if (hour < 12) return "Good morning";
3807
+ if (hour < 18) return "Good afternoon";
3808
+ return "Good evening";
3809
+ };
3810
+ var STATIC_SUGGESTIONS = [
3811
+ {
3812
+ label: "Explain this concept in detail",
3813
+ icon: MessageSquareTextIcon,
3814
+ prompt: "Explain this concept to me by drawing comparisons"
3815
+ },
3816
+ {
3817
+ label: "Generate a podcast",
3818
+ icon: PodcastIcon,
3819
+ prompt: "/audio"
3820
+ },
3821
+ {
3822
+ label: "Quiz me",
3823
+ icon: BadgeQuestionMarkIcon,
3824
+ prompt: "/quiz"
3825
+ },
3826
+ {
3827
+ label: "Generate flashcards",
3828
+ icon: WalletCardsIcon,
3829
+ prompt: "/flashcards"
3830
+ }
3831
+ ];
3832
+ var ThreadWelcome = () => {
3833
+ return /* @__PURE__ */ jsxs("div", { className: "aui-thread-welcome-root mx-auto flex w-full max-w-(--thread-max-width) flex-col gap-4", children: [
3834
+ /* @__PURE__ */ jsx("div", { className: "aui-thread-welcome-center flex w-full grow flex-col items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "aui-thread-welcome-message flex size-full flex-col justify-center px-4", children: [
3835
+ /* @__PURE__ */ jsx(
3836
+ "h1",
3837
+ {
3838
+ className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in font-semibold text-2xl duration-200",
3839
+ style: {
3840
+ color: "var(--color-primary)"
3841
+ },
3842
+ children: getGreeting()
3843
+ }
3844
+ ),
3845
+ /* @__PURE__ */ jsx("p", { className: "aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in text-muted-foreground text-xl delay-75 duration-200", children: "How may I be of service?" })
3846
+ ] }) }),
3847
+ /* @__PURE__ */ jsx(ThreadSuggestions, {})
3848
+ ] });
3849
+ };
3850
+ var ThreadSuggestions = () => {
3851
+ return /* @__PURE__ */ jsx("div", { className: "aui-thread-welcome-suggestions flex w-full flex-col gap-2", children: STATIC_SUGGESTIONS.map((suggestion, index) => {
3852
+ const Icon = suggestion.icon;
3853
+ return /* @__PURE__ */ jsx(
3854
+ "div",
3855
+ {
3856
+ className: "fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200",
3857
+ style: { animationDelay: `${200 + index * 50}ms` },
3858
+ children: /* @__PURE__ */ jsx(ThreadPrimitive.Suggestion, { prompt: suggestion.prompt, send: true, asChild: true, children: /* @__PURE__ */ jsx(
3859
+ Button,
3860
+ {
3861
+ variant: "ghost",
3862
+ className: "aui-thread-welcome-suggestion h-auto w-full @md:flex-col flex-wrap items-start justify-start gap-1 rounded-2xl border text-left text-sm transition-colors hover:bg-muted hover:text-primary",
3863
+ "aria-label": suggestion.label,
3864
+ style: {
3865
+ borderWidth: 0,
3866
+ padding: 8
3867
+ },
3868
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3869
+ /* @__PURE__ */ jsx(Icon, { className: "size-4 shrink-0" }),
3870
+ /* @__PURE__ */ jsx("span", { children: suggestion.label })
3871
+ ] })
3872
+ }
3873
+ ) })
3874
+ },
3875
+ suggestion.prompt
3876
+ );
3877
+ }) });
3878
+ };
3879
+ var Composer = () => {
3880
+ const inputRef = useRef(null);
3881
+ const composerRuntime = useComposerRuntime();
3882
+ const handleSubmit = useCallback(() => {
3883
+ composerRuntime.send();
3884
+ }, [composerRuntime]);
3885
+ const handleInsertMention = useCallback((item) => {
3886
+ inputRef.current?.insertMention({
3887
+ id: item.id,
3888
+ title: item.title,
3889
+ icon: item.icon,
3890
+ type: item.type
3891
+ });
3892
+ setTimeout(() => {
3893
+ inputRef.current?.focus();
3894
+ }, 0);
3895
+ }, []);
3896
+ const {
3897
+ isOpen,
3898
+ openPopover,
3899
+ closePopover,
3900
+ categories,
3901
+ isLoading,
3902
+ activeIndex,
3903
+ flattenedItems,
3904
+ selectItem,
3905
+ setActiveIndex,
3906
+ handleKeyDown,
3907
+ getCategoryLabel,
3908
+ searchTerm,
3909
+ updateSearch
3910
+ } = useContextMention({ onInsertMention: handleInsertMention });
3911
+ const { selectedContext, removeContextItem } = useMessageContext();
3912
+ const handleTriggerDetected = useCallback(
3913
+ (searchText) => {
3914
+ if (!isOpen) {
3915
+ openPopover();
3916
+ }
3917
+ updateSearch(searchText);
3918
+ },
3919
+ [isOpen, openPopover, updateSearch]
3920
+ );
3921
+ const handleTriggerDismissed = useCallback(() => {
3922
+ if (isOpen) {
3923
+ closePopover();
3924
+ }
3925
+ }, [isOpen, closePopover]);
3926
+ const handleComposerKeyDown = useCallback(
3927
+ (e) => {
3928
+ if (isOpen) {
3929
+ if (["ArrowUp", "ArrowDown", "Enter", "Escape"].includes(e.key)) {
3930
+ e.preventDefault();
3931
+ handleKeyDown(e);
3932
+ if (e.key === "Escape") {
3933
+ setTimeout(() => {
3934
+ inputRef.current?.focus();
3935
+ }, 0);
3936
+ }
3937
+ }
3938
+ }
3939
+ },
3940
+ [isOpen, handleKeyDown]
3941
+ );
3942
+ const handleMentionRemove = useCallback(
3943
+ (mentionId) => {
3944
+ removeContextItem(mentionId);
3945
+ },
3946
+ [removeContextItem]
3947
+ );
3948
+ return /* @__PURE__ */ jsx(ComposerPrimitive.Root, { className: "aui-composer-root relative flex w-full flex-col", children: /* @__PURE__ */ jsxs(ComposerPrimitive.AttachmentDropzone, { className: "aui-composer-attachment-dropzone flex w-full flex-col rounded-2xl border border-input bg-background px-1 pt-2 outline-none transition-shadow has-[[contenteditable]:focus-visible]:border-ring has-[[contenteditable]:focus-visible]:ring-2 has-[[contenteditable]:focus-visible]:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50", children: [
3949
+ /* @__PURE__ */ jsx(
3950
+ ComposerContextUI,
3951
+ {
3952
+ isOpen,
3953
+ onOpenChange: (open) => open ? openPopover() : closePopover(),
3954
+ categories,
3955
+ isLoading,
3956
+ activeIndex,
3957
+ flattenedItems,
3958
+ onSelectItem: selectItem,
3959
+ onActiveIndexChange: setActiveIndex,
3960
+ getCategoryLabel,
3961
+ searchTerm,
3962
+ selectedItems: selectedContext,
3963
+ onRemoveItem: removeContextItem
3964
+ }
3965
+ ),
3966
+ /* @__PURE__ */ jsx(ComposerAttachments, {}),
3967
+ /* @__PURE__ */ jsx(
3968
+ MentionComposerInput,
3969
+ {
3970
+ ref: inputRef,
3971
+ placeholder: "Ask, search, or make anything...",
3972
+ autoFocus: true,
3973
+ onTriggerDetected: handleTriggerDetected,
3974
+ onTriggerDismissed: handleTriggerDismissed,
3975
+ onKeyDown: handleComposerKeyDown,
3976
+ onMentionRemove: handleMentionRemove,
3977
+ onSubmit: handleSubmit
3978
+ }
3979
+ ),
3980
+ /* @__PURE__ */ jsx(ComposerAction, {})
3981
+ ] }) });
3982
+ };
3983
+ var ComposerContextUI = ({
3984
+ isOpen,
3985
+ onOpenChange,
3986
+ categories,
3987
+ isLoading,
3988
+ activeIndex,
3989
+ flattenedItems,
3990
+ onSelectItem,
3991
+ onActiveIndexChange,
3992
+ getCategoryLabel,
3993
+ searchTerm,
3994
+ selectedItems,
3995
+ onRemoveItem
3996
+ }) => {
3997
+ return /* @__PURE__ */ jsxs("div", { className: "aui-composer-context mb-2 flex items-center gap-2 overflow-x-auto px-1.5 pt-0.5 pb-1", children: [
3998
+ /* @__PURE__ */ jsx(
3999
+ ContextMentionPopover,
4000
+ {
4001
+ isOpen,
4002
+ onOpenChange,
4003
+ categories,
4004
+ isLoading,
4005
+ activeIndex,
4006
+ flattenedItems,
4007
+ onSelectItem,
4008
+ onActiveIndexChange,
4009
+ getCategoryLabel,
4010
+ searchTerm,
4011
+ trigger: /* @__PURE__ */ jsx(
4012
+ TooltipIconButton,
4013
+ {
4014
+ tooltip: "Add context (@)",
4015
+ side: "bottom",
4016
+ variant: "ghost",
4017
+ size: "icon",
4018
+ className: "aui-composer-add-context size-[34px] rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30",
4019
+ "aria-label": "Add context (@)",
4020
+ children: /* @__PURE__ */ jsx(AtSignIcon, { className: "size-5 stroke-[1.5px]" })
4021
+ }
4022
+ )
4023
+ }
4024
+ ),
4025
+ selectedItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 overflow-x-auto", children: selectedItems.map((item) => /* @__PURE__ */ jsx(
4026
+ ContextPill,
4027
+ {
4028
+ label: item.title,
4029
+ onRemove: () => onRemoveItem(item.id)
4030
+ },
4031
+ item.id
4032
+ )) })
4033
+ ] });
4034
+ };
4035
+ var ComposerAction = () => {
4036
+ return /* @__PURE__ */ jsxs("div", { className: "aui-composer-action-wrapper relative mx-2 mb-2 flex items-center justify-between", children: [
4037
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4038
+ /* @__PURE__ */ jsx(ComposerAddAttachment, {}),
4039
+ /* @__PURE__ */ jsx(
4040
+ TooltipIconButton,
4041
+ {
4042
+ tooltip: "All sources",
4043
+ side: "bottom",
4044
+ variant: "ghost",
4045
+ size: "icon",
4046
+ className: "aui-composer-all-sources size-[34px] rounded-full p-1 font-semibold text-xs hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30",
4047
+ "aria-label": "All sources",
4048
+ children: /* @__PURE__ */ jsx(GlobeIcon, { className: "size-5 stroke-[1.5px]" })
4049
+ }
4050
+ )
4051
+ ] }),
4052
+ /* @__PURE__ */ jsx(AssistantIf, { condition: ({ thread }) => !thread.isRunning, children: /* @__PURE__ */ jsx(ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ jsx(
4053
+ TooltipIconButton,
4054
+ {
4055
+ tooltip: "Send message",
4056
+ side: "bottom",
4057
+ type: "submit",
4058
+ variant: "default",
4059
+ className: "aui-composer-send size-8 rounded-full",
4060
+ "aria-label": "Send message",
4061
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "aui-composer-send-icon size-4" })
4062
+ }
4063
+ ) }) }),
4064
+ /* @__PURE__ */ jsx(AssistantIf, { condition: ({ thread }) => thread.isRunning, children: /* @__PURE__ */ jsx(ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ jsx(
4065
+ Button,
4066
+ {
4067
+ type: "button",
4068
+ variant: "default",
4069
+ size: "icon",
4070
+ className: "aui-composer-cancel size-8 rounded-full",
4071
+ "aria-label": "Stop generating",
4072
+ children: /* @__PURE__ */ jsx(SquareIcon, { className: "aui-composer-cancel-icon size-3 fill-current" })
4073
+ }
4074
+ ) }) })
4075
+ ] });
4076
+ };
4077
+ var MessageError = () => {
4078
+ return /* @__PURE__ */ jsx(MessagePrimitive.Error, { children: /* @__PURE__ */ jsx(ErrorPrimitive.Root, { className: "aui-message-error-root mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm dark:bg-destructive/5 dark:text-red-200", children: /* @__PURE__ */ jsx(ErrorPrimitive.Message, { className: "aui-message-error-message line-clamp-2" }) }) });
4079
+ };
4080
+ var AssistantMessage = () => {
4081
+ return /* @__PURE__ */ jsxs(
4082
+ MessagePrimitive.Root,
4083
+ {
4084
+ className: "aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150",
4085
+ "data-role": "assistant",
4086
+ children: [
4087
+ /* @__PURE__ */ jsxs("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
4088
+ /* @__PURE__ */ jsx(
4089
+ MessagePrimitive.Parts,
4090
+ {
4091
+ components: {
4092
+ Text: MarkdownText,
4093
+ tools: { Fallback: ToolFallback }
4094
+ }
4095
+ }
4096
+ ),
4097
+ /* @__PURE__ */ jsx(MessageError, {})
4098
+ ] }),
4099
+ /* @__PURE__ */ jsxs("div", { className: "aui-assistant-message-footer mt-1 ml-2 flex", children: [
4100
+ /* @__PURE__ */ jsx(BranchPicker, {}),
4101
+ /* @__PURE__ */ jsx(AssistantActionBar, {})
4102
+ ] })
4103
+ ]
4104
+ }
4105
+ );
4106
+ };
4107
+ var AssistantActionBar = () => {
4108
+ return /* @__PURE__ */ jsxs(
4109
+ ActionBarPrimitive.Root,
4110
+ {
4111
+ hideWhenRunning: true,
4112
+ autohide: "not-last",
4113
+ autohideFloat: "single-branch",
4114
+ className: "aui-assistant-action-bar-root col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground data-floating:absolute data-floating:rounded-md data-floating:border data-floating:bg-background data-floating:p-1 data-floating:shadow-sm",
4115
+ children: [
4116
+ /* @__PURE__ */ jsx(ActionBarPrimitive.Copy, { asChild: true, children: /* @__PURE__ */ jsxs(TooltipIconButton, { tooltip: "Copy", children: [
4117
+ /* @__PURE__ */ jsx(AssistantIf, { condition: ({ message }) => message.isCopied, children: /* @__PURE__ */ jsx(CheckIcon, {}) }),
4118
+ /* @__PURE__ */ jsx(AssistantIf, { condition: ({ message }) => !message.isCopied, children: /* @__PURE__ */ jsx(CopyIcon, {}) })
4119
+ ] }) }),
4120
+ /* @__PURE__ */ jsx(ActionBarPrimitive.ExportMarkdown, { asChild: true, children: /* @__PURE__ */ jsx(TooltipIconButton, { tooltip: "Export as Markdown", children: /* @__PURE__ */ jsx(DownloadIcon, {}) }) }),
4121
+ /* @__PURE__ */ jsx(ActionBarPrimitive.Reload, { asChild: true, children: /* @__PURE__ */ jsx(TooltipIconButton, { tooltip: "Refresh", children: /* @__PURE__ */ jsx(RefreshCwIcon, {}) }) })
4122
+ ]
4123
+ }
4124
+ );
4125
+ };
4126
+ var MessageContextIndicator = () => {
4127
+ const [isExpanded, setIsExpanded] = useState(false);
4128
+ const contextItems = useMessage((state) => {
4129
+ console.log("[MessageContextIndicator] Message state:", state);
4130
+ const metadata = state.metadata;
4131
+ const context = metadata?.context || metadata?.custom?.context;
4132
+ console.log("[MessageContextIndicator] Context:", context);
4133
+ return context;
4134
+ });
4135
+ if (!contextItems || contextItems.length === 0) {
4136
+ return null;
4137
+ }
4138
+ return /* @__PURE__ */ jsxs("div", { className: "col-start-2 mb-1 flex flex-col items-end", children: [
4139
+ /* @__PURE__ */ jsxs(
4140
+ "button",
4141
+ {
4142
+ onClick: () => setIsExpanded(!isExpanded),
4143
+ className: "flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors",
4144
+ children: [
4145
+ /* @__PURE__ */ jsxs("span", { children: [
4146
+ contextItems.length,
4147
+ " Context"
4148
+ ] }),
4149
+ /* @__PURE__ */ jsx(
4150
+ ChevronDownIcon,
4151
+ {
4152
+ className: cn(
4153
+ "size-3.5 transition-transform duration-200",
4154
+ isExpanded && "rotate-180"
4155
+ )
4156
+ }
4157
+ )
4158
+ ]
4159
+ }
4160
+ ),
4161
+ isExpanded && /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-1 justify-end", children: contextItems.map((item) => /* @__PURE__ */ jsx(
4162
+ "span",
4163
+ {
4164
+ className: "rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground",
4165
+ children: item.title
4166
+ },
4167
+ item.id
4168
+ )) })
4169
+ ] });
4170
+ };
4171
+ var UserMessage = () => {
4172
+ return /* @__PURE__ */ jsxs(
4173
+ MessagePrimitive.Root,
4174
+ {
4175
+ className: "aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2",
4176
+ "data-role": "user",
4177
+ children: [
4178
+ /* @__PURE__ */ jsx(MessageContextIndicator, {}),
4179
+ /* @__PURE__ */ jsx(UserMessageAttachments, {}),
4180
+ /* @__PURE__ */ jsxs("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: [
4181
+ /* @__PURE__ */ jsx("div", { className: "aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground", children: /* @__PURE__ */ jsx(UserMessageContent, {}) }),
4182
+ /* @__PURE__ */ jsx("div", { className: "aui-user-action-bar-wrapper absolute top-1/2 left-0 -translate-x-full -translate-y-1/2 pr-2", children: /* @__PURE__ */ jsx(UserActionBar, {}) })
4183
+ ] }),
4184
+ /* @__PURE__ */ jsx(BranchPicker, { className: "aui-user-branch-picker col-span-full col-start-1 row-start-3 -mr-1 justify-end" })
4185
+ ]
4186
+ }
4187
+ );
4188
+ };
4189
+ var UserActionBar = () => {
4190
+ return /* @__PURE__ */ jsx(
4191
+ ActionBarPrimitive.Root,
4192
+ {
4193
+ hideWhenRunning: true,
4194
+ autohide: "not-last",
4195
+ className: "aui-user-action-bar-root flex flex-col items-end",
4196
+ children: /* @__PURE__ */ jsx(ActionBarPrimitive.Edit, { asChild: true, children: /* @__PURE__ */ jsx(TooltipIconButton, { tooltip: "Edit", className: "aui-user-action-edit p-4", children: /* @__PURE__ */ jsx(PencilIcon, {}) }) })
4197
+ }
4198
+ );
4199
+ };
4200
+ var EditComposer = () => {
4201
+ return /* @__PURE__ */ jsx(MessagePrimitive.Root, { className: "aui-edit-composer-wrapper mx-auto flex w-full max-w-(--thread-max-width) flex-col px-2 py-3", children: /* @__PURE__ */ jsxs(ComposerPrimitive.Root, { className: "aui-edit-composer-root ml-auto flex w-full max-w-[85%] flex-col rounded-2xl bg-muted", children: [
4202
+ /* @__PURE__ */ jsx(
4203
+ ComposerPrimitive.Input,
4204
+ {
4205
+ className: "aui-edit-composer-input min-h-14 w-full resize-none bg-transparent p-4 text-foreground text-sm outline-none",
4206
+ autoFocus: true
4207
+ }
4208
+ ),
4209
+ /* @__PURE__ */ jsxs("div", { className: "aui-edit-composer-footer mx-3 mb-3 flex items-center gap-2 self-end", children: [
4210
+ /* @__PURE__ */ jsx(ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", children: "Cancel" }) }),
4211
+ /* @__PURE__ */ jsx(ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "sm", children: "Update" }) })
4212
+ ] })
4213
+ ] }) });
4214
+ };
4215
+ var BranchPicker = ({
4216
+ className,
4217
+ ...rest
4218
+ }) => {
4219
+ return /* @__PURE__ */ jsxs(
4220
+ BranchPickerPrimitive.Root,
4221
+ {
4222
+ hideWhenSingleBranch: true,
4223
+ className: cn(
4224
+ "aui-branch-picker-root mr-2 -ml-2 inline-flex items-center text-muted-foreground text-xs",
4225
+ className
4226
+ ),
4227
+ ...rest,
4228
+ children: [
4229
+ /* @__PURE__ */ jsx(BranchPickerPrimitive.Previous, { asChild: true, children: /* @__PURE__ */ jsx(TooltipIconButton, { tooltip: "Previous", children: /* @__PURE__ */ jsx(ChevronLeftIcon, {}) }) }),
4230
+ /* @__PURE__ */ jsxs("span", { className: "aui-branch-picker-state font-medium", children: [
4231
+ /* @__PURE__ */ jsx(BranchPickerPrimitive.Number, {}),
4232
+ " / ",
4233
+ /* @__PURE__ */ jsx(BranchPickerPrimitive.Count, {})
4234
+ ] }),
4235
+ /* @__PURE__ */ jsx(BranchPickerPrimitive.Next, { asChild: true, children: /* @__PURE__ */ jsx(TooltipIconButton, { tooltip: "Next", children: /* @__PURE__ */ jsx(ChevronRightIcon, {}) }) })
4236
+ ]
4237
+ }
4238
+ );
4239
+ };
4240
+ var ThreadList = () => {
4241
+ return /* @__PURE__ */ jsxs(ThreadListPrimitive.Root, { className: "aui-thread-list-root flex flex-col", children: [
4242
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [
4243
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: "Chats" }),
4244
+ /* @__PURE__ */ jsx(ThreadListPrimitive.New, { asChild: true, children: /* @__PURE__ */ jsx(
4245
+ TooltipIconButton,
4246
+ {
4247
+ tooltip: "New chat",
4248
+ variant: "ghost",
4249
+ size: "icon",
4250
+ className: "h-7 w-7",
4251
+ children: /* @__PURE__ */ jsx(PlusIcon, { className: "h-4 w-4" })
4252
+ }
4253
+ ) })
4254
+ ] }),
4255
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
4256
+ /* @__PURE__ */ jsx(
4257
+ ThreadListPrimitive.Items,
4258
+ {
4259
+ components: {
4260
+ ThreadListItem
4261
+ }
4262
+ }
4263
+ ),
4264
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Archived" }) }),
4265
+ /* @__PURE__ */ jsx(
4266
+ ThreadListPrimitive.Items,
4267
+ {
4268
+ archived: true,
4269
+ components: {
4270
+ ThreadListItem: ArchivedThreadListItem
4271
+ }
4272
+ }
4273
+ )
4274
+ ] })
4275
+ ] });
4276
+ };
4277
+ var ThreadListItem = () => {
4278
+ return /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Root, { className: "aui-thread-list-item group relative flex items-center gap-2 px-3 py-2 hover:bg-muted/50 data-[active]:bg-muted cursor-pointer transition-colors", children: [
4279
+ /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Trigger, { className: "flex flex-1 items-center gap-2 min-w-0", children: [
4280
+ /* @__PURE__ */ jsx(MessageSquareIcon, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground" }),
4281
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col min-w-0", children: /* @__PURE__ */ jsx("span", { className: "truncate text-sm font-medium text-foreground", children: /* @__PURE__ */ jsx(ThreadListItemPrimitive.Title, { fallback: "New Chat" }) }) })
4282
+ ] }),
4283
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
4284
+ /* @__PURE__ */ jsx(ThreadListItemPrimitive.Archive, { asChild: true, children: /* @__PURE__ */ jsx(
4285
+ TooltipIconButton,
4286
+ {
4287
+ tooltip: "Archive",
4288
+ variant: "ghost",
4289
+ size: "icon",
4290
+ className: "h-6 w-6",
4291
+ children: /* @__PURE__ */ jsx(ArchiveIcon, { className: "h-3.5 w-3.5" })
4292
+ }
4293
+ ) }),
4294
+ /* @__PURE__ */ jsx(ThreadListItemPrimitive.Delete, { asChild: true, children: /* @__PURE__ */ jsx(
4295
+ TooltipIconButton,
4296
+ {
4297
+ tooltip: "Delete",
4298
+ variant: "ghost",
4299
+ size: "icon",
4300
+ className: "h-6 w-6 text-destructive hover:text-destructive",
4301
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "h-3.5 w-3.5" })
4302
+ }
4303
+ ) })
4304
+ ] })
4305
+ ] });
4306
+ };
4307
+ var ArchivedThreadListItem = () => {
4308
+ return /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Root, { className: "aui-thread-list-item-archived group relative flex items-center gap-2 px-3 py-2 hover:bg-muted/50 data-[active]:bg-muted cursor-pointer transition-colors opacity-70", children: [
4309
+ /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Trigger, { className: "flex flex-1 items-center gap-2 min-w-0", children: [
4310
+ /* @__PURE__ */ jsx(ArchiveIcon, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground" }),
4311
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col min-w-0", children: /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-foreground", children: /* @__PURE__ */ jsx(ThreadListItemPrimitive.Title, { fallback: "Archived Chat" }) }) })
4312
+ ] }),
4313
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
4314
+ /* @__PURE__ */ jsx(ThreadListItemPrimitive.Unarchive, { asChild: true, children: /* @__PURE__ */ jsx(
4315
+ TooltipIconButton,
4316
+ {
4317
+ tooltip: "Unarchive",
4318
+ variant: "ghost",
4319
+ size: "icon",
4320
+ className: "h-6 w-6",
4321
+ children: /* @__PURE__ */ jsx(ArchiveRestoreIcon, { className: "h-3.5 w-3.5" })
4322
+ }
4323
+ ) }),
4324
+ /* @__PURE__ */ jsx(ThreadListItemPrimitive.Delete, { asChild: true, children: /* @__PURE__ */ jsx(
4325
+ TooltipIconButton,
4326
+ {
4327
+ tooltip: "Delete",
4328
+ variant: "ghost",
4329
+ size: "icon",
4330
+ className: "h-6 w-6 text-destructive hover:text-destructive",
4331
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "h-3.5 w-3.5" })
4332
+ }
4333
+ ) })
4334
+ ] })
4335
+ ] });
4336
+ };
4337
+ var categoryIcons = {
4338
+ audio: HeadphonesIcon,
4339
+ "audio-overview": HeadphonesIcon,
4340
+ "video-overview": VideoIcon,
4341
+ "mind-map": NetworkIcon,
4342
+ reports: FileTextIcon,
4343
+ flashcards: LayersIcon,
4344
+ quiz: HelpCircleIcon,
4345
+ "slide-deck": PresentationIcon,
4346
+ infographic: BarChart3Icon
4347
+ };
4348
+ var categoryColors = {
4349
+ audio: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300",
4350
+ "audio-overview": "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300",
4351
+ "video-overview": "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300",
4352
+ "mind-map": "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300",
4353
+ reports: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300",
4354
+ flashcards: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300",
4355
+ quiz: "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300",
4356
+ "slide-deck": "bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300",
4357
+ infographic: "bg-teal-100 text-teal-700 dark:bg-teal-900/30 dark:text-teal-300"
4358
+ };
4359
+ var categoryLabels = {
4360
+ audio: "Audio",
4361
+ "audio-overview": "Audio Overview",
4362
+ "video-overview": "Video Overview",
4363
+ "mind-map": "Mind Map",
4364
+ reports: "Report",
4365
+ flashcards: "Flashcards",
4366
+ quiz: "Quiz",
4367
+ "slide-deck": "Slide Deck",
4368
+ infographic: "Infographic"
4369
+ };
4370
+ var ArtifactCard = ({
4371
+ category,
4372
+ title,
4373
+ content,
4374
+ isLoading,
4375
+ children
4376
+ }) => {
4377
+ const Icon = categoryIcons[category];
4378
+ const colorClass = categoryColors[category];
4379
+ const label = categoryLabels[category];
4380
+ return /* @__PURE__ */ jsxs("div", { className: "my-3 overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: [
4381
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3 px-4 py-3", colorClass), children: [
4382
+ /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-white/50 dark:bg-black/20", children: isLoading ? /* @__PURE__ */ jsx(Loader2Icon, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" }) }),
4383
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
4384
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium opacity-80", children: label }),
4385
+ /* @__PURE__ */ jsx("h4", { className: "truncate font-semibold text-sm", children: title })
4386
+ ] })
4387
+ ] }),
4388
+ content && /* @__PURE__ */ jsx("div", { className: "px-4 py-3 text-sm text-muted-foreground", children: /* @__PURE__ */ jsx("div", { className: "line-clamp-4 whitespace-pre-wrap", children: content }) }),
4389
+ children,
4390
+ !isLoading && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-border px-4 py-2", children: [
4391
+ /* @__PURE__ */ jsxs("button", { className: "flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors", children: [
4392
+ /* @__PURE__ */ jsx(DownloadIcon, { className: "h-3 w-3" }),
4393
+ "Export"
4394
+ ] }),
4395
+ /* @__PURE__ */ jsxs("button", { className: "flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors", children: [
4396
+ /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "h-3 w-3" }),
4397
+ "Open"
4398
+ ] })
4399
+ ] })
4400
+ ] });
4401
+ };
4402
+ function createArtifactToolUI(category) {
4403
+ return makeAssistantToolUI({
4404
+ toolName: `create_${category.replace(/-/g, "_")}`,
4405
+ render: ({ args, result, status }) => {
4406
+ const isLoading = status.type === "running";
4407
+ return /* @__PURE__ */ jsx(
4408
+ ArtifactCard,
4409
+ {
4410
+ category,
4411
+ title: args.title || "Generating...",
4412
+ content: result?.content || args.content,
4413
+ isLoading
4414
+ }
4415
+ );
4416
+ }
4417
+ });
4418
+ }
4419
+ var AudioOverviewToolUI = createArtifactToolUI("audio-overview");
4420
+ var VideoOverviewToolUI = createArtifactToolUI("video-overview");
4421
+ var MindMapToolUI = createArtifactToolUI("mind-map");
4422
+ var ReportsToolUI = createArtifactToolUI("reports");
4423
+ var FlashcardsToolUI = createArtifactToolUI("flashcards");
4424
+ var QuizToolUI = createArtifactToolUI("quiz");
4425
+ var SlideDeckToolUI = createArtifactToolUI("slide-deck");
4426
+ var InfographicToolUI = createArtifactToolUI("infographic");
4427
+ var ArtifactToolUIs = () => {
4428
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4429
+ /* @__PURE__ */ jsx(AudioOverviewToolUI, {}),
4430
+ /* @__PURE__ */ jsx(VideoOverviewToolUI, {}),
4431
+ /* @__PURE__ */ jsx(MindMapToolUI, {}),
4432
+ /* @__PURE__ */ jsx(ReportsToolUI, {}),
4433
+ /* @__PURE__ */ jsx(FlashcardsToolUI, {}),
4434
+ /* @__PURE__ */ jsx(QuizToolUI, {}),
4435
+ /* @__PURE__ */ jsx(SlideDeckToolUI, {}),
4436
+ /* @__PURE__ */ jsx(InfographicToolUI, {})
4437
+ ] });
4438
+ };
4439
+ var ChatWidget = ({
4440
+ sidebarOpen = false,
4441
+ onSidebarClose
4442
+ }) => {
4443
+ return /* @__PURE__ */ jsxs("div", { className: "relative flex flex-1 h-full w-full overflow-hidden bg-background", children: [
4444
+ /* @__PURE__ */ jsx(ArtifactToolUIs, {}),
4445
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col min-w-0", children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsx(Thread, {}) }) }),
4446
+ /* @__PURE__ */ jsx(AnimatePresence, { children: sidebarOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
4447
+ /* @__PURE__ */ jsx(
4448
+ motion.div,
4449
+ {
4450
+ initial: { opacity: 0 },
4451
+ animate: { opacity: 1 },
4452
+ exit: { opacity: 0 },
4453
+ transition: { duration: 0.2 },
4454
+ className: "absolute inset-0 bg-black/50 z-40",
4455
+ onClick: onSidebarClose
4456
+ }
4457
+ ),
4458
+ /* @__PURE__ */ jsx(
4459
+ motion.div,
4460
+ {
4461
+ initial: { x: -256 },
4462
+ animate: { x: 0 },
4463
+ exit: { x: -256 },
4464
+ transition: { duration: 0.2, ease: [0.4, 0, 0.2, 1] },
4465
+ className: cn(
4466
+ "absolute left-0 top-0 bottom-0 w-64 bg-background z-50 overflow-hidden shadow-lg"
4467
+ ),
4468
+ children: /* @__PURE__ */ jsx(ThreadList, {})
4469
+ }
4470
+ )
4471
+ ] }) })
4472
+ ] });
4473
+ };
4474
+ var ThreadListItem2 = () => {
4475
+ return /* @__PURE__ */ jsx(ThreadListItemPrimitive.Root, { className: "group relative flex items-center gap-2 px-2 py-1.5 hover:bg-muted/50 data-[active]:bg-muted cursor-pointer transition-colors rounded-sm", children: /* @__PURE__ */ jsx(ThreadListItemPrimitive.Trigger, { className: "flex flex-1 items-center gap-2 min-w-0", children: /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-foreground", children: /* @__PURE__ */ jsx(ThreadListItemPrimitive.Title, { fallback: "New Chat" }) }) }) });
4476
+ };
4477
+ var ChatHistoryPopover = ({
4478
+ onSelectThread
4479
+ }) => {
4480
+ const handleThreadSelect = () => {
4481
+ onSelectThread?.();
4482
+ };
4483
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", onClick: handleThreadSelect, children: [
4484
+ /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx(Text, { size: "xs", style: { color: "hsl(var(--muted-foreground))" }, children: "Previous 7 days" }) }),
4485
+ /* @__PURE__ */ jsx("div", { className: "max-h-[300px] overflow-y-auto", children: /* @__PURE__ */ jsx(
4486
+ ThreadListPrimitive.Items,
4487
+ {
4488
+ components: {
4489
+ ThreadListItem: ThreadListItem2
4490
+ }
4491
+ }
4492
+ ) })
4493
+ ] });
4494
+ };
4495
+ var layoutOptions = [
4496
+ {
4497
+ value: "sidebar",
4498
+ label: "Sidebar",
4499
+ icon: /* @__PURE__ */ jsx(PanelLeftIcon, { className: "h-4 w-4" })
4500
+ },
4501
+ {
4502
+ value: "floating",
4503
+ label: "Floating",
4504
+ icon: /* @__PURE__ */ jsx(SquareIcon, { className: "h-4 w-4" })
4505
+ },
4506
+ {
4507
+ value: "fullscreen",
4508
+ label: "Full Screen",
4509
+ icon: /* @__PURE__ */ jsx(Maximize2Icon, { className: "h-4 w-4" })
4510
+ }
4511
+ ];
4512
+ var LayoutPopover = ({
4513
+ currentLayout,
4514
+ onLayoutChange
4515
+ }) => {
4516
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: layoutOptions.map((option) => {
4517
+ const isSelected = currentLayout === option.value;
4518
+ return /* @__PURE__ */ jsxs(
4519
+ "button",
4520
+ {
4521
+ onClick: () => onLayoutChange(option.value),
4522
+ className: cn(
4523
+ "flex items-center gap-2 px-2 py-1.5 rounded-sm hover:bg-muted/50 transition-colors cursor-pointer w-full text-left",
4524
+ isSelected && "bg-muted/30"
4525
+ ),
4526
+ children: [
4527
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-4 h-4", children: option.icon }),
4528
+ /* @__PURE__ */ jsx(Text, { size: "sm", style: { flex: 1 }, children: option.label }),
4529
+ isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4 text-foreground" })
4530
+ ]
4531
+ },
4532
+ option.value
4533
+ );
4534
+ }) });
4535
+ };
4536
+ var LAYOUT_STORAGE_KEY = "learn-alchemy-widget-layout";
4537
+ function WidgetContainer({
4538
+ defaultOpen = false,
4539
+ position: position2 = "bottom-right"
4540
+ }) {
4541
+ const [isOpen, setIsOpen] = useState(defaultOpen);
4542
+ const [sidebarOpen, setSidebarOpen] = useState(false);
4543
+ const [chatHistoryOpen, setChatHistoryOpen] = useState(false);
4544
+ const [layoutOpen, setLayoutOpen] = useState(false);
4545
+ const [layout, setLayout] = useState("floating");
4546
+ useEffect(() => {
4547
+ const savedLayout = localStorage.getItem(LAYOUT_STORAGE_KEY);
4548
+ if (savedLayout && ["floating", "fullscreen", "sidebar"].includes(savedLayout)) {
4549
+ setLayout(savedLayout);
4550
+ }
4551
+ }, []);
4552
+ const handleLayoutChange = (newLayout) => {
4553
+ setLayout(newLayout);
4554
+ localStorage.setItem(LAYOUT_STORAGE_KEY, newLayout);
4555
+ setLayoutOpen(false);
4556
+ };
4557
+ const threadTitle = useAssistantState(
4558
+ ({ threadListItem }) => threadListItem?.title ?? "New AI chat"
4559
+ );
4560
+ const handleMinimize = () => {
4561
+ setIsOpen(false);
4562
+ };
4563
+ const handleChatHistorySelect = () => {
4564
+ setChatHistoryOpen(false);
4565
+ };
4566
+ const getWidgetStyles = () => {
4567
+ const baseStyle = {
4568
+ transformOrigin: position2 === "bottom-right" ? "bottom right" : "bottom left"
4569
+ };
4570
+ switch (layout) {
4571
+ case "fullscreen":
4572
+ return {
4573
+ ...baseStyle,
4574
+ position: "fixed",
4575
+ width: "100vw",
4576
+ height: "100vh",
4577
+ maxWidth: "100vw",
4578
+ maxHeight: "100vh",
4579
+ borderRadius: 0,
4580
+ bottom: 0,
4581
+ right: 0,
4582
+ left: 0,
4583
+ top: 0,
4584
+ margin: 0
4585
+ };
4586
+ case "sidebar":
4587
+ return {
4588
+ ...baseStyle,
4589
+ position: "fixed",
4590
+ width: "400px",
4591
+ height: "100vh",
4592
+ maxHeight: "100vh",
4593
+ bottom: 0,
4594
+ top: 0,
4595
+ right: position2 === "bottom-right" ? 0 : "auto",
4596
+ left: position2 === "bottom-left" ? 0 : "auto",
4597
+ borderRadius: 0,
4598
+ margin: 0
4599
+ };
4600
+ case "floating":
4601
+ default:
4602
+ return baseStyle;
4603
+ }
4604
+ };
4605
+ return /* @__PURE__ */ jsxs(WidgetRoot, { position: position2, children: [
4606
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxs(
4607
+ WidgetPanel,
4608
+ {
4609
+ initial: { opacity: 0, scale: 0, y: 0 },
4610
+ animate: { opacity: 1, scale: 1, y: 0 },
4611
+ exit: { opacity: 0, scale: 0, y: 0 },
4612
+ transition: { duration: 0.2, ease: [0.4, 0, 0.2, 1] },
4613
+ style: getWidgetStyles(),
4614
+ children: [
4615
+ /* @__PURE__ */ jsxs(WidgetHeader, { children: [
4616
+ /* @__PURE__ */ jsxs(Popover, { open: chatHistoryOpen, onOpenChange: setChatHistoryOpen, children: [
4617
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
4618
+ "button",
4619
+ {
4620
+ type: "button",
4621
+ style: {
4622
+ cursor: "pointer",
4623
+ background: "none",
4624
+ border: "none",
4625
+ padding: 0,
4626
+ display: "flex",
4627
+ alignItems: "center",
4628
+ minWidth: 0,
4629
+ flex: 1
4630
+ },
4631
+ children: /* @__PURE__ */ jsxs(
4632
+ Flex,
4633
+ {
4634
+ align: "center",
4635
+ gap: "xs",
4636
+ style: { minWidth: 0, flex: 1 },
4637
+ children: [
4638
+ /* @__PURE__ */ jsx(
4639
+ Text,
4640
+ {
4641
+ size: "sm",
4642
+ style: {
4643
+ fontWeight: 500,
4644
+ overflow: "hidden",
4645
+ textOverflow: "ellipsis",
4646
+ whiteSpace: "nowrap",
4647
+ minWidth: 0
4648
+ },
4649
+ children: threadTitle
4650
+ }
4651
+ ),
4652
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 16, style: { flexShrink: 0 } })
4653
+ ]
4654
+ }
4655
+ )
4656
+ }
4657
+ ) }),
4658
+ /* @__PURE__ */ jsx(
4659
+ PopoverContent,
4660
+ {
4661
+ align: "start",
4662
+ side: "bottom",
4663
+ sideOffset: 8,
4664
+ className: "w-64 p-0",
4665
+ children: /* @__PURE__ */ jsx(
4666
+ ChatHistoryPopover,
4667
+ {
4668
+ onSelectThread: handleChatHistorySelect
4669
+ }
4670
+ )
4671
+ }
4672
+ )
4673
+ ] }),
4674
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "xs", style: { flexShrink: 0 }, children: [
4675
+ /* @__PURE__ */ jsx(ThreadListPrimitive.New, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { "aria-label": "New chat", children: /* @__PURE__ */ jsx(EditIcon, { size: 18 }) }) }),
4676
+ /* @__PURE__ */ jsxs(Popover, { open: layoutOpen, onOpenChange: setLayoutOpen, children: [
4677
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
4678
+ IconButton,
4679
+ {
4680
+ "aria-label": "Layout options",
4681
+ style: {
4682
+ backgroundColor: layoutOpen ? "hsl(var(--muted))" : "transparent"
4683
+ },
4684
+ children: /* @__PURE__ */ jsx(LayoutIcon, { size: 18 })
4685
+ }
4686
+ ) }),
4687
+ /* @__PURE__ */ jsx(
4688
+ PopoverContent,
4689
+ {
4690
+ align: "end",
4691
+ side: "bottom",
4692
+ sideOffset: 8,
4693
+ className: "w-48 p-2",
4694
+ children: /* @__PURE__ */ jsx(
4695
+ LayoutPopover,
4696
+ {
4697
+ currentLayout: layout,
4698
+ onLayoutChange: handleLayoutChange
4699
+ }
4700
+ )
4701
+ }
4702
+ )
4703
+ ] }),
4704
+ /* @__PURE__ */ jsx(
4705
+ IconButton,
4706
+ {
4707
+ onClick: handleMinimize,
4708
+ "aria-label": "Minimize widget",
4709
+ children: /* @__PURE__ */ jsx(Minimize2Icon, { size: 18 })
4710
+ }
4711
+ )
4712
+ ] })
4713
+ ] }),
4714
+ /* @__PURE__ */ jsx(WidgetContent, { children: /* @__PURE__ */ jsx(
4715
+ ChatWidget,
4716
+ {
4717
+ sidebarOpen,
4718
+ onSidebarClose: () => setSidebarOpen(false)
4719
+ }
4720
+ ) })
4721
+ ]
4722
+ }
4723
+ ) }),
4724
+ /* @__PURE__ */ jsx(AnimatePresence, { children: !isOpen && /* @__PURE__ */ jsx(
4725
+ Flex,
4726
+ {
4727
+ justify: position2 === "bottom-right" ? "flex-end" : "flex-start",
4728
+ children: /* @__PURE__ */ jsx(
4729
+ FAB,
4730
+ {
4731
+ onClick: () => setIsOpen(true),
4732
+ initial: { opacity: 0, y: 20 },
4733
+ animate: { opacity: 1, y: 0 },
4734
+ exit: { opacity: 0, y: 20 },
4735
+ transition: { duration: 0.2, ease: [0.4, 0, 0.2, 1] },
4736
+ whileHover: { scale: 1.1 },
4737
+ whileTap: { scale: 0.9 },
4738
+ "aria-label": "Open chat",
4739
+ children: /* @__PURE__ */ jsx(BotIcon, { size: 24, strokeWidth: 2 })
4740
+ }
4741
+ )
4742
+ }
4743
+ ) })
4744
+ ] });
4745
+ }
4746
+ var ReadOnlyThread = () => {
4747
+ return /* @__PURE__ */ jsx(
4748
+ ThreadPrimitive.Root,
4749
+ {
4750
+ className: "aui-thread-root @container flex h-full flex-col bg-background",
4751
+ style: {
4752
+ ["--thread-max-width"]: "44rem"
4753
+ },
4754
+ children: /* @__PURE__ */ jsxs(
4755
+ ThreadPrimitive.Viewport,
4756
+ {
4757
+ turnAnchor: "top",
4758
+ className: "aui-thread-viewport relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4 pb-4",
4759
+ children: [
4760
+ /* @__PURE__ */ jsx(
4761
+ ThreadPrimitive.Messages,
4762
+ {
4763
+ components: {
4764
+ UserMessage: ReadOnlyUserMessage,
4765
+ EditComposer: ReadOnlyUserMessage,
4766
+ // Disable edit mode
4767
+ AssistantMessage: ReadOnlyAssistantMessage
4768
+ }
4769
+ }
4770
+ ),
4771
+ /* @__PURE__ */ jsx(ThreadPrimitive.Empty, { children: /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center text-muted-foreground", children: "No messages in this conversation." }) })
4772
+ ]
4773
+ }
4774
+ )
4775
+ }
4776
+ );
4777
+ };
4778
+ var ReadOnlyAssistantMessage = () => {
4779
+ return /* @__PURE__ */ jsx(
4780
+ MessagePrimitive.Root,
4781
+ {
4782
+ className: "aui-assistant-message-root fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150",
4783
+ "data-role": "assistant",
4784
+ children: /* @__PURE__ */ jsxs("div", { className: "aui-assistant-message-content wrap-break-word px-2 text-foreground leading-relaxed", children: [
4785
+ /* @__PURE__ */ jsx(
4786
+ MessagePrimitive.Parts,
4787
+ {
4788
+ components: {
4789
+ Text: MarkdownText,
4790
+ tools: { Fallback: ToolFallback }
4791
+ }
4792
+ }
4793
+ ),
4794
+ /* @__PURE__ */ jsx(MessagePrimitive.Error, { children: /* @__PURE__ */ jsx("div", { className: "mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm", children: /* @__PURE__ */ jsx(MessagePrimitive.Error, {}) }) })
4795
+ ] })
4796
+ }
4797
+ );
4798
+ };
4799
+ var ReadOnlyUserMessage = () => {
4800
+ return /* @__PURE__ */ jsxs(
4801
+ MessagePrimitive.Root,
4802
+ {
4803
+ className: "aui-user-message-root fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2",
4804
+ "data-role": "user",
4805
+ children: [
4806
+ /* @__PURE__ */ jsx(UserMessageAttachments, {}),
4807
+ /* @__PURE__ */ jsx("div", { className: "aui-user-message-content-wrapper relative col-start-2 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "aui-user-message-content wrap-break-word rounded-2xl bg-muted px-4 py-2.5 text-foreground", children: /* @__PURE__ */ jsx(UserMessageContent, {}) }) })
4808
+ ]
4809
+ }
4810
+ );
4811
+ };
4812
+
4813
+ export { ArtifactToolUIs, ChatWidget, ReadOnlyThread, Thread, ThreadList, WidgetContainer, WidgetContext, WidgetProvider, createWidgetCache, theme, useChat, useWidget, widgetCache };
4814
+ //# sourceMappingURL=react.js.map
4815
+ //# sourceMappingURL=react.js.map