@tinkrapp/widget 1.0.0 → 1.0.2

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 CHANGED
@@ -1,20 +1,20 @@
1
- import * as React from 'react';
2
- import { forwardRef, memo, createContext, useRef, useState, useCallback, useImperativeHandle, useEffect, useMemo, useContext } from 'react';
1
+ import * as React2 from 'react';
2
+ import { createContext, forwardRef, memo, useRef, useState, useCallback, useImperativeHandle, useEffect, useMemo, useContext } from 'react';
3
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
4
  import { AssistantChatTransport, useChatRuntime } from '@assistant-ui/react-ai-sdk';
5
5
  import { CacheProvider, ThemeProvider } from '@emotion/react';
6
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';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import styled from '@emotion/styled';
9
+ import { motion, AnimatePresence } from 'motion/react';
10
+ import { FileTextIcon, ChevronUpIcon, ChevronDownIcon, CheckIcon, CopyIcon, ExternalLinkIcon, Loader2Icon, BarChart3Icon, PresentationIcon, HelpCircleIcon, LayersIcon, NetworkIcon, VideoIcon, HeadphonesIcon, DownloadIcon, XCircleIcon, 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
11
  import { clsx } from 'clsx';
11
12
  import { twMerge } from 'tailwind-merge';
13
+ import ReactMarkdown from 'react-markdown';
14
+ import remarkGfm from 'remark-gfm';
12
15
  import { Slot, Slottable } from '@radix-ui/react-slot';
13
16
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
14
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
15
17
  import { cva } from 'class-variance-authority';
16
- import styled from '@emotion/styled';
17
- import { motion, AnimatePresence } from 'motion/react';
18
18
  import { useShallow } from 'zustand/shallow';
19
19
  import * as DialogPrimitive from '@radix-ui/react-dialog';
20
20
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
@@ -249,557 +249,143 @@ var WidgetClient = class {
249
249
  this.events.emit("state:change", { previous, current: newState });
250
250
  }
251
251
  };
252
- function cn(...inputs) {
253
- return twMerge(clsx(inputs));
254
- }
255
- function TooltipProvider({
256
- delayDuration = 0,
257
- ...props
258
- }) {
252
+ var MessageContext = createContext(null);
253
+ function MessageContextProvider({ children }) {
254
+ const [selectedContext, setSelectedContext] = useState([]);
255
+ const addContextItem = useCallback((item) => {
256
+ console.log("[MessageContext] Adding context item:", item.id, item.title);
257
+ setSelectedContext((prev2) => {
258
+ if (prev2.some((i) => i.id === item.id)) {
259
+ console.log("[MessageContext] Item already exists, skipping");
260
+ return prev2;
261
+ }
262
+ console.log("[MessageContext] Context items count:", prev2.length + 1);
263
+ return [...prev2, item];
264
+ });
265
+ }, []);
266
+ const removeContextItem = useCallback((id) => {
267
+ setSelectedContext((prev2) => prev2.filter((item) => item.id !== id));
268
+ }, []);
269
+ const clearContext = useCallback(() => {
270
+ console.log("[MessageContext] Clearing context");
271
+ setSelectedContext([]);
272
+ }, []);
273
+ const setContext = useCallback((items) => {
274
+ setSelectedContext(items);
275
+ }, []);
276
+ const consumeContext = useCallback(() => {
277
+ const context = selectedContext;
278
+ console.log("[MessageContext] Consuming context:", context.length, "items");
279
+ return context;
280
+ }, [selectedContext]);
259
281
  return /* @__PURE__ */ jsx(
260
- TooltipPrimitive.Provider,
282
+ MessageContext.Provider,
261
283
  {
262
- "data-slot": "tooltip-provider",
263
- delayDuration,
264
- ...props
284
+ value: {
285
+ selectedContext,
286
+ addContextItem,
287
+ removeContextItem,
288
+ clearContext,
289
+ setContext,
290
+ consumeContext
291
+ },
292
+ children
265
293
  }
266
294
  );
267
295
  }
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
- ) });
296
+ function useMessageContext() {
297
+ const context = useContext(MessageContext);
298
+ if (!context) {
299
+ throw new Error(
300
+ "useMessageContext must be used within a MessageContextProvider"
301
+ );
302
+ }
303
+ return context;
300
304
  }
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
- }
305
+
306
+ // src/react/styles/theme.ts
307
+ var theme = {
308
+ colors: {
309
+ background: {
310
+ primary: "#1a1a1a",
311
+ secondary: "#2a2a2a",
312
+ tertiary: "#3a3a3a"
321
313
  },
322
- defaultVariants: {
323
- variant: "default",
324
- size: "default"
314
+ accent: {
315
+ primary: "#c9a227",
316
+ hover: "#d4af37",
317
+ muted: "rgba(201, 162, 39, 0.4)"
318
+ },
319
+ text: {
320
+ primary: "#ffffff",
321
+ secondary: "#888888",
322
+ tertiary: "#cccccc",
323
+ inverse: "#1a1a1a"
324
+ },
325
+ border: "#2a2a2a",
326
+ shadow: "rgba(0, 0, 0, 0.4)"
327
+ },
328
+ spacing: {
329
+ xs: "0.25rem",
330
+ sm: "0.5rem",
331
+ md: "1rem",
332
+ lg: "1.5rem",
333
+ xl: "2rem",
334
+ "2xl": "3rem"
335
+ },
336
+ radii: {
337
+ sm: "0.5rem",
338
+ md: "0.75rem",
339
+ lg: "1rem",
340
+ xl: "1.5rem",
341
+ full: "50%"
342
+ },
343
+ typography: {
344
+ fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
345
+ fontSize: {
346
+ xs: "0.75rem",
347
+ sm: "0.875rem",
348
+ md: "1rem",
349
+ lg: "1.125rem",
350
+ xl: "1.25rem",
351
+ "2xl": "1.5rem"
352
+ },
353
+ fontWeight: {
354
+ normal: 400,
355
+ medium: 500,
356
+ semibold: 600,
357
+ bold: 700
358
+ },
359
+ lineHeight: {
360
+ tight: 1.25,
361
+ normal: 1.5,
362
+ relaxed: 1.7
325
363
  }
364
+ },
365
+ zIndex: {
366
+ widget: 9999,
367
+ overlay: 9998
368
+ },
369
+ shadows: {
370
+ sm: "0 2px 8px rgba(0, 0, 0, 0.2)",
371
+ md: "0 4px 16px rgba(0, 0, 0, 0.3)",
372
+ lg: "0 8px 32px rgba(0, 0, 0, 0.4)",
373
+ accent: "0 4px 16px rgba(201, 162, 39, 0.4)",
374
+ accentHover: "0 6px 20px rgba(201, 162, 39, 0.5)"
375
+ },
376
+ transitions: {
377
+ fast: "0.15s ease",
378
+ normal: "0.2s ease",
379
+ slow: "0.3s ease"
326
380
  }
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];
381
+ };
382
+ function sheetForTag(tag) {
383
+ if (tag.sheet) {
384
+ return tag.sheet;
385
+ }
386
+ for (var i = 0; i < document.styleSheets.length; i++) {
387
+ if (document.styleSheets[i].ownerNode === tag) {
388
+ return document.styleSheets[i];
803
389
  }
804
390
  }
805
391
  return void 0;
@@ -2133,342 +1719,881 @@ function createThreadListAdapter(baseUrl, userId, assistantId) {
2133
1719
  console.error("[Threads] Rename error:", error);
2134
1720
  }
2135
1721
  },
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);
1722
+ // Archive a thread
1723
+ async archive(remoteId) {
1724
+ try {
1725
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}/archive`, {
1726
+ method: "POST",
1727
+ headers
1728
+ });
1729
+ } catch (error) {
1730
+ console.error("[Threads] Archive error:", error);
1731
+ }
1732
+ },
1733
+ // Unarchive a thread
1734
+ async unarchive(remoteId) {
1735
+ try {
1736
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}/unarchive`, {
1737
+ method: "POST",
1738
+ headers
1739
+ });
1740
+ } catch (error) {
1741
+ console.error("[Threads] Unarchive error:", error);
1742
+ }
1743
+ },
1744
+ // Delete a thread
1745
+ async delete(remoteId) {
1746
+ try {
1747
+ await fetch(`${baseUrl}/api/widget/threads/${remoteId}`, {
1748
+ method: "DELETE",
1749
+ headers
1750
+ });
1751
+ } catch (error) {
1752
+ console.error("[Threads] Delete error:", error);
1753
+ }
1754
+ },
1755
+ // Generate a title from messages
1756
+ async generateTitle(remoteId, messages) {
1757
+ return createAssistantStream(async (controller) => {
1758
+ try {
1759
+ const response = await fetch(
1760
+ `${baseUrl}/api/widget/threads/${remoteId}/title`,
1761
+ {
1762
+ method: "POST",
1763
+ headers,
1764
+ body: JSON.stringify({ messages })
1765
+ }
1766
+ );
1767
+ if (!response.ok) {
1768
+ throw new Error(`Title generation failed: ${response.status}`);
1769
+ }
1770
+ const data = await response.json();
1771
+ controller.appendText(data.title);
1772
+ controller.close();
1773
+ } catch (error) {
1774
+ console.error("[Threads] Title generation error:", error);
1775
+ controller.appendText("New Chat");
1776
+ controller.close();
1777
+ }
1778
+ });
1779
+ }
1780
+ };
1781
+ }
1782
+ async function saveMessages(baseUrl, userId, assistantId, threadId, messages) {
1783
+ try {
1784
+ const response = await fetch(
1785
+ `${baseUrl}/api/widget/threads/${threadId}/messages/sync`,
1786
+ {
1787
+ method: "POST",
1788
+ headers: createApiHeaders(userId, assistantId),
1789
+ body: JSON.stringify({ messages })
1790
+ }
1791
+ );
1792
+ if (!response.ok) {
1793
+ console.error("[Messages] Sync failed:", response.status);
1794
+ }
1795
+ } catch (error) {
1796
+ console.error("[Messages] Sync error:", error);
1797
+ }
1798
+ }
1799
+ function createHistoryAdapter(baseUrl, userId, assistantId, remoteId) {
1800
+ const headers = createApiHeaders(userId, assistantId);
1801
+ return {
1802
+ async load() {
1803
+ console.log("[History] load() called, remoteId:", remoteId);
1804
+ if (!remoteId) return { headId: null, messages: [] };
1805
+ try {
1806
+ const response = await fetch(
1807
+ `${baseUrl}/api/widget/threads/${remoteId}/messages`,
1808
+ { headers }
1809
+ );
1810
+ if (!response.ok) {
1811
+ console.error("[History] Failed to load messages:", response.status);
1812
+ return { headId: null, messages: [] };
1813
+ }
1814
+ const { messages } = await response.json();
1815
+ console.log("[History] Loaded messages:", messages.length);
1816
+ const formattedMessages = messages.map(
1817
+ (m, index) => ({
1818
+ parentId: index > 0 ? messages[index - 1].id : null,
1819
+ message: {
1820
+ id: m.id,
1821
+ role: m.role,
1822
+ parts: m.content,
1823
+ metadata: m.metadata,
1824
+ createdAt: new Date(m.createdAt)
1825
+ }
1826
+ })
1827
+ );
1828
+ console.log("[History] Formatted messages:", formattedMessages.length);
1829
+ return {
1830
+ headId: messages.length > 0 ? messages[messages.length - 1].id : null,
1831
+ messages: formattedMessages
1832
+ };
1833
+ } catch (error) {
1834
+ console.error("[History] Load error:", error);
1835
+ return { headId: null, messages: [] };
1836
+ }
1837
+ },
1838
+ async append(message) {
1839
+ console.log("[History] append() called");
1840
+ },
1841
+ // Required by useExternalHistory in @assistant-ui/react-ai-sdk
1842
+ withFormat(_formatAdapter) {
1843
+ console.log("[History.withFormat] called, remoteId:", remoteId);
1844
+ return {
1845
+ async load() {
1846
+ if (!remoteId) return { headId: null, messages: [] };
1847
+ try {
1848
+ const response = await fetch(
1849
+ `${baseUrl}/api/widget/threads/${remoteId}/messages`,
1850
+ { headers }
1851
+ );
1852
+ if (!response.ok) {
1853
+ console.error("[History.withFormat] Failed:", response.status);
1854
+ return { headId: null, messages: [] };
1855
+ }
1856
+ const { messages } = await response.json();
1857
+ console.log("[History.withFormat] Loaded:", messages.length);
1858
+ const formattedMessages = messages.map(
1859
+ (m, index) => ({
1860
+ parentId: index > 0 ? messages[index - 1].id : null,
1861
+ message: {
1862
+ id: m.id,
1863
+ role: m.role,
1864
+ parts: m.content,
1865
+ metadata: m.metadata,
1866
+ createdAt: new Date(m.createdAt)
1867
+ }
1868
+ })
1869
+ );
1870
+ return {
1871
+ headId: messages.length > 0 ? messages[messages.length - 1].id : null,
1872
+ messages: formattedMessages
1873
+ };
1874
+ } catch (error) {
1875
+ console.error("[History.withFormat] Error:", error);
1876
+ return { headId: null, messages: [] };
1877
+ }
1878
+ },
1879
+ async append(_item) {
1880
+ }
1881
+ };
1882
+ }
1883
+ };
1884
+ }
1885
+ function AssistantRuntimeWrapper({
1886
+ config,
1887
+ userId,
1888
+ children
1889
+ }) {
1890
+ const baseUrl = config.baseUrl || "http://localhost:3000";
1891
+ const assistantId = config.apiKey;
1892
+ const { consumeContext, clearContext } = useMessageContext();
1893
+ const contextRef = useRef(consumeContext);
1894
+ contextRef.current = consumeContext;
1895
+ const clearContextRef = useRef(clearContext);
1896
+ clearContextRef.current = clearContext;
1897
+ const threadListAdapter = useMemo(
1898
+ () => createThreadListAdapter(baseUrl, userId, assistantId),
1899
+ [baseUrl, userId, assistantId]
1900
+ );
1901
+ const runtime = unstable_useRemoteThreadListRuntime({
1902
+ runtimeHook: function useChatThreadRuntime() {
1903
+ const threadId = useAssistantState(
1904
+ ({ threadListItem }) => threadListItem?.remoteId ?? void 0
1905
+ );
1906
+ const threadIdRef = useRef(threadId);
1907
+ threadIdRef.current = threadId;
1908
+ const history = useMemo(
1909
+ () => createHistoryAdapter(baseUrl, userId, assistantId, threadId),
1910
+ [threadId]
1911
+ );
1912
+ const transport = useMemo(() => {
1913
+ console.log("[Widget] Creating transport for threadId:", threadId);
1914
+ return new AssistantChatTransport({
1915
+ api: `${baseUrl}/api/widget/chat`,
1916
+ headers: {
1917
+ "X-User-Id": userId,
1918
+ "X-Assistant-Id": assistantId
1919
+ },
1920
+ // Use body as a function to dynamically include context
1921
+ body: () => {
1922
+ const currentContext = contextRef.current();
1923
+ const contextIds = currentContext.map((item) => item.id);
1924
+ const contextMetadata = currentContext.map((item) => ({
1925
+ id: item.id,
1926
+ type: item.type,
1927
+ title: item.title
1928
+ }));
1929
+ console.log(
1930
+ "[Widget] Transport body - contextIds:",
1931
+ contextIds.length,
1932
+ "threadId:",
1933
+ threadId
1934
+ );
1935
+ if (contextIds.length > 0) {
1936
+ setTimeout(() => clearContextRef.current(), 0);
1937
+ }
1938
+ return {
1939
+ assistantId,
1940
+ threadId,
1941
+ ...contextIds.length > 0 && { contextIds, contextMetadata }
1942
+ };
1943
+ }
1944
+ });
1945
+ }, [threadId]);
1946
+ const runtime2 = useChatRuntime({
1947
+ transport,
1948
+ adapters: { history },
1949
+ onFinish: ({ message, messages }) => {
1950
+ const currentThreadId = threadIdRef.current;
1951
+ console.log(
1952
+ "[Widget] onFinish - threadId:",
1953
+ currentThreadId,
1954
+ "messages:",
1955
+ messages.length
1956
+ );
1957
+ if (currentThreadId && messages.length > 0) {
1958
+ saveMessages(
1959
+ baseUrl,
1960
+ userId,
1961
+ assistantId,
1962
+ currentThreadId,
1963
+ messages
1964
+ );
1965
+ }
1966
+ }
1967
+ });
1968
+ return runtime2;
1969
+ },
1970
+ adapter: threadListAdapter
1971
+ });
1972
+ return /* @__PURE__ */ jsx(AssistantRuntimeProvider, { runtime, children });
1973
+ }
1974
+ function WidgetProvider({
1975
+ config,
1976
+ children,
1977
+ autoInitialize = true
1978
+ }) {
1979
+ const [userId] = useState(() => config.userId || generateUserId());
1980
+ const [client] = useState(() => new WidgetClient(config));
1981
+ const [state, setState] = useState(client.getState());
1982
+ useEffect(() => {
1983
+ const unsubscribe = client.on("state:change", ({ current }) => {
1984
+ setState(current);
1985
+ });
1986
+ if (autoInitialize && state.status === "idle") {
1987
+ client.initialize().catch(console.error);
1988
+ }
1989
+ return () => {
1990
+ unsubscribe();
1991
+ client.destroy();
1992
+ };
1993
+ }, [client, autoInitialize, state.status]);
1994
+ const contextValue = useMemo(
1995
+ () => ({ client, state, userId }),
1996
+ [client, state, userId]
1997
+ );
1998
+ 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 }) }) }) }) });
1999
+ }
2000
+ function useWidget() {
2001
+ const context = useContext(WidgetContext);
2002
+ if (!context) {
2003
+ throw new Error("useWidget must be used within a WidgetProvider");
2004
+ }
2005
+ const { client, state } = context;
2006
+ const initialize = useCallback(async () => {
2007
+ if (state.status === "idle") {
2008
+ await client.initialize();
2009
+ }
2010
+ }, [client, state.status]);
2011
+ const sendMessage = useCallback(
2012
+ async (content) => {
2013
+ return client.sendMessage(content);
2014
+ },
2015
+ [client]
2016
+ );
2017
+ return {
2018
+ state,
2019
+ client,
2020
+ isIdle: state.status === "idle",
2021
+ isInitializing: state.status === "initializing",
2022
+ isReady: state.status === "ready",
2023
+ isLoading: state.status === "loading",
2024
+ isError: state.status === "error",
2025
+ messages: state.status === "ready" ? state.session.messages : [],
2026
+ error: state.status === "error" ? state.error : null,
2027
+ initialize,
2028
+ sendMessage
2029
+ };
2030
+ }
2031
+ function useChat() {
2032
+ const { sendMessage, messages, isLoading, isReady } = useWidget();
2033
+ const [input, setInput] = useState("");
2034
+ const handleSubmit = useCallback(
2035
+ async (e) => {
2036
+ e?.preventDefault();
2037
+ if (!input.trim() || !isReady || isLoading) {
2038
+ return;
2145
2039
  }
2146
- },
2147
- // Unarchive a thread
2148
- async unarchive(remoteId) {
2040
+ const message = input.trim();
2041
+ setInput("");
2149
2042
  try {
2150
- await fetch(`${baseUrl}/api/widget/threads/${remoteId}/unarchive`, {
2151
- method: "POST",
2152
- headers
2153
- });
2043
+ await sendMessage(message);
2154
2044
  } catch (error) {
2155
- console.error("[Threads] Unarchive error:", error);
2045
+ console.error("Failed to send message:", error);
2046
+ setInput(message);
2156
2047
  }
2157
2048
  },
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);
2049
+ [input, isReady, isLoading, sendMessage]
2050
+ );
2051
+ return {
2052
+ input,
2053
+ setInput,
2054
+ handleSubmit,
2055
+ messages,
2056
+ isLoading,
2057
+ canSubmit: isReady && !isLoading && input.trim().length > 0
2058
+ };
2059
+ }
2060
+ var ThreadListItem = () => {
2061
+ 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" }) }) }) });
2062
+ };
2063
+ var ChatHistoryPopover = ({
2064
+ onSelectThread
2065
+ }) => {
2066
+ const handleThreadSelect = () => {
2067
+ onSelectThread?.();
2068
+ };
2069
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", onClick: handleThreadSelect, children: [
2070
+ /* @__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" }) }),
2071
+ /* @__PURE__ */ jsx("div", { className: "max-h-[300px] overflow-y-auto", children: /* @__PURE__ */ jsx(
2072
+ ThreadListPrimitive.Items,
2073
+ {
2074
+ components: {
2075
+ ThreadListItem
2076
+ }
2167
2077
  }
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();
2078
+ ) })
2079
+ ] });
2080
+ };
2081
+ function cn(...inputs) {
2082
+ return twMerge(clsx(inputs));
2083
+ }
2084
+ var categoryIcons = {
2085
+ audio: HeadphonesIcon,
2086
+ "audio-overview": HeadphonesIcon,
2087
+ "video-overview": VideoIcon,
2088
+ "mind-map": NetworkIcon,
2089
+ reports: FileTextIcon,
2090
+ flashcards: LayersIcon,
2091
+ quiz: HelpCircleIcon,
2092
+ "slide-deck": PresentationIcon,
2093
+ infographic: BarChart3Icon
2094
+ };
2095
+ var categoryColors = {
2096
+ audio: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300",
2097
+ "audio-overview": "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300",
2098
+ "video-overview": "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300",
2099
+ "mind-map": "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300",
2100
+ reports: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300",
2101
+ flashcards: "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300",
2102
+ quiz: "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300",
2103
+ "slide-deck": "bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300",
2104
+ infographic: "bg-teal-100 text-teal-700 dark:bg-teal-900/30 dark:text-teal-300"
2105
+ };
2106
+ var categoryLabels = {
2107
+ audio: "Audio",
2108
+ "audio-overview": "Audio Overview",
2109
+ "video-overview": "Video Overview",
2110
+ "mind-map": "Mind Map",
2111
+ reports: "Report",
2112
+ flashcards: "Flashcards",
2113
+ quiz: "Quiz",
2114
+ "slide-deck": "Slide Deck",
2115
+ infographic: "Infographic"
2116
+ };
2117
+ var ArtifactCard = ({
2118
+ category,
2119
+ title,
2120
+ content,
2121
+ isLoading,
2122
+ children
2123
+ }) => {
2124
+ const Icon = categoryIcons[category];
2125
+ const colorClass = categoryColors[category];
2126
+ const label = categoryLabels[category];
2127
+ return /* @__PURE__ */ jsxs("div", { className: "my-3 overflow-hidden rounded-xl border border-border bg-card shadow-sm", children: [
2128
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-3 px-4 py-3", colorClass), children: [
2129
+ /* @__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" }) }),
2130
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2131
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium opacity-80", children: label }),
2132
+ /* @__PURE__ */ jsx("h4", { className: "truncate font-semibold text-sm", children: title })
2133
+ ] })
2134
+ ] }),
2135
+ 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 }) }),
2136
+ children,
2137
+ !isLoading && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-border px-4 py-2", children: [
2138
+ /* @__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: [
2139
+ /* @__PURE__ */ jsx(DownloadIcon, { className: "h-3 w-3" }),
2140
+ "Export"
2141
+ ] }),
2142
+ /* @__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: [
2143
+ /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "h-3 w-3" }),
2144
+ "Open"
2145
+ ] })
2146
+ ] })
2147
+ ] });
2148
+ };
2149
+ function createArtifactToolUI(category) {
2150
+ return makeAssistantToolUI({
2151
+ toolName: `create_${category.replace(/-/g, "_")}`,
2152
+ render: ({ args, result, status }) => {
2153
+ const isLoading = status.type === "running";
2154
+ return /* @__PURE__ */ jsx(
2155
+ ArtifactCard,
2156
+ {
2157
+ category,
2158
+ title: args.title || "Generating...",
2159
+ content: result?.content || args.content,
2160
+ isLoading
2191
2161
  }
2192
- });
2162
+ );
2193
2163
  }
2194
- };
2164
+ });
2165
+ }
2166
+ var AudioOverviewToolUI = createArtifactToolUI("audio-overview");
2167
+ var VideoOverviewToolUI = createArtifactToolUI("video-overview");
2168
+ var MindMapToolUI = createArtifactToolUI("mind-map");
2169
+ var ReportsToolUI = createArtifactToolUI("reports");
2170
+ var FlashcardsToolUI = createArtifactToolUI("flashcards");
2171
+ var QuizToolUI = createArtifactToolUI("quiz");
2172
+ var SlideDeckToolUI = createArtifactToolUI("slide-deck");
2173
+ var InfographicToolUI = createArtifactToolUI("infographic");
2174
+ var ArtifactToolUIs = () => {
2175
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2176
+ /* @__PURE__ */ jsx(AudioOverviewToolUI, {}),
2177
+ /* @__PURE__ */ jsx(VideoOverviewToolUI, {}),
2178
+ /* @__PURE__ */ jsx(MindMapToolUI, {}),
2179
+ /* @__PURE__ */ jsx(ReportsToolUI, {}),
2180
+ /* @__PURE__ */ jsx(FlashcardsToolUI, {}),
2181
+ /* @__PURE__ */ jsx(QuizToolUI, {}),
2182
+ /* @__PURE__ */ jsx(SlideDeckToolUI, {}),
2183
+ /* @__PURE__ */ jsx(InfographicToolUI, {})
2184
+ ] });
2185
+ };
2186
+ function TooltipProvider({
2187
+ delayDuration = 0,
2188
+ ...props
2189
+ }) {
2190
+ return /* @__PURE__ */ jsx(
2191
+ TooltipPrimitive.Provider,
2192
+ {
2193
+ "data-slot": "tooltip-provider",
2194
+ delayDuration,
2195
+ ...props
2196
+ }
2197
+ );
2195
2198
  }
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);
2199
+ function Tooltip({
2200
+ ...props
2201
+ }) {
2202
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) });
2203
+ }
2204
+ function TooltipTrigger({
2205
+ ...props
2206
+ }) {
2207
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
2208
+ }
2209
+ function TooltipContent({
2210
+ className,
2211
+ sideOffset = 0,
2212
+ children,
2213
+ ...props
2214
+ }) {
2215
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
2216
+ TooltipPrimitive.Content,
2217
+ {
2218
+ "data-slot": "tooltip-content",
2219
+ sideOffset,
2220
+ className: cn(
2221
+ "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",
2222
+ className
2223
+ ),
2224
+ ...props,
2225
+ children: [
2226
+ children,
2227
+ /* @__PURE__ */ jsx(TooltipPrimitive.Arrow, { className: "bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" })
2228
+ ]
2208
2229
  }
2209
- } catch (error) {
2210
- console.error("[Messages] Sync error:", error);
2211
- }
2230
+ ) });
2212
2231
  }
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: [] };
2232
+ var buttonVariants = cva(
2233
+ "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",
2234
+ {
2235
+ variants: {
2236
+ variant: {
2237
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
2238
+ destructive: "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
2239
+ 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",
2240
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
2241
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
2242
+ link: "text-primary underline-offset-4 hover:underline"
2243
+ },
2244
+ size: {
2245
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
2246
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
2247
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
2248
+ icon: "size-9",
2249
+ "icon-sm": "size-8",
2250
+ "icon-lg": "size-10"
2250
2251
  }
2251
2252
  },
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
- };
2253
+ defaultVariants: {
2254
+ variant: "default",
2255
+ size: "default"
2256
+ }
2257
+ }
2258
+ );
2259
+ var Button2 = React2.forwardRef(({ className, variant = "default", size = "default", asChild = false, ...props }, ref) => {
2260
+ const Comp = asChild ? Slot : "button";
2261
+ return /* @__PURE__ */ jsx(
2262
+ Comp,
2263
+ {
2264
+ ref,
2265
+ "data-slot": "button",
2266
+ "data-variant": variant,
2267
+ "data-size": size,
2268
+ className: cn(buttonVariants({ variant, size, className })),
2269
+ ...props
2296
2270
  }
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
2271
  );
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,
2272
+ });
2273
+ Button2.displayName = "Button";
2274
+ var TooltipIconButton = forwardRef(({ children, tooltip, side = "bottom", className, ...rest }, ref) => {
2275
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
2276
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button2, { variant: "ghost", size: "icon-sm", ...rest, ref, children: [
2277
+ /* @__PURE__ */ jsx(Slottable, { children }),
2278
+ /* @__PURE__ */ jsx("span", { className: "aui-sr-only sr-only", children: tooltip })
2279
+ ] }) }),
2280
+ /* @__PURE__ */ jsx(TooltipContent, { side, children: tooltip })
2281
+ ] });
2282
+ });
2283
+ TooltipIconButton.displayName = "TooltipIconButton";
2284
+ var ToolCard = ({
2285
+ title,
2286
+ subtitle,
2287
+ isStreaming,
2288
+ isError = false,
2289
+ icon,
2290
+ persistentContent,
2388
2291
  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());
2292
+ footer
2293
+ }) => {
2294
+ const [manualExpanded, setManualExpanded] = useState(null);
2295
+ const prevStreamingRef = useRef(isStreaming);
2296
+ const contentRef = useRef(null);
2297
+ const isExpanded = manualExpanded ?? isStreaming;
2394
2298
  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);
2299
+ if (isStreaming && !prevStreamingRef.current) {
2300
+ setManualExpanded(null);
2400
2301
  }
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();
2302
+ prevStreamingRef.current = isStreaming;
2303
+ }, [isStreaming]);
2304
+ useEffect(() => {
2305
+ if (isStreaming && contentRef.current) {
2306
+ contentRef.current.scrollTop = contentRef.current.scrollHeight;
2421
2307
  }
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
2308
+ });
2309
+ const renderIcon = () => {
2310
+ if (icon) return icon;
2311
+ const iconClass = cn("h-4 w-4", isStreaming && "animate-spin");
2312
+ if (isStreaming) {
2313
+ return /* @__PURE__ */ jsx(Loader2Icon, { className: iconClass });
2314
+ }
2315
+ if (isError) {
2316
+ return /* @__PURE__ */ jsx(XCircleIcon, { className: "h-4 w-4 text-red-400" });
2317
+ }
2318
+ return /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4" });
2441
2319
  };
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;
2320
+ const handleToggle = () => {
2321
+ if (!isStreaming) {
2322
+ setManualExpanded((prev2) => prev2 === null ? true : !prev2);
2323
+ }
2324
+ };
2325
+ return /* @__PURE__ */ jsxs("div", { className: "my-2 overflow-hidden rounded-xl border border-border shadow-sm", children: [
2326
+ /* @__PURE__ */ jsxs(
2327
+ "div",
2328
+ {
2329
+ className: cn(
2330
+ "flex items-center gap-2 p-2 cursor-pointer transition-colors text-white bg-primary-foreground",
2331
+ !isStreaming && "hover:opacity-90"
2332
+ ),
2333
+ onClick: handleToggle,
2334
+ children: [
2335
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: renderIcon() }),
2336
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2337
+ subtitle && /* @__PURE__ */ jsx("p", { className: "font-medium opacity-80 leading-tight text-xs text-muted-foreground", children: subtitle }),
2338
+ /* @__PURE__ */ jsx("h4", { className: "truncate font-semibold leading-tight text-sm text-muted-foreground", children: title })
2339
+ ] }),
2340
+ /* @__PURE__ */ jsx(
2341
+ "button",
2342
+ {
2343
+ className: "p-1 rounded hover:bg-white/20 transition-colors",
2344
+ "aria-label": isExpanded ? "Collapse" : "Expand",
2345
+ onClick: (e) => {
2346
+ e.stopPropagation();
2347
+ handleToggle();
2348
+ },
2349
+ children: isExpanded ? /* @__PURE__ */ jsx(ChevronUpIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4" })
2350
+ }
2351
+ )
2352
+ ]
2353
+ }
2354
+ ),
2355
+ persistentContent,
2356
+ isExpanded && /* @__PURE__ */ jsx(
2357
+ "div",
2358
+ {
2359
+ ref: contentRef,
2360
+ className: "p-2 max-h-[400px] overflow-y-auto bg-secondary",
2361
+ children
2362
+ }
2363
+ ),
2364
+ 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 })
2365
+ ] });
2366
+ };
2367
+ var useCopyToClipboard = ({
2368
+ copiedDuration = 3e3
2369
+ } = {}) => {
2370
+ const [isCopied, setIsCopied] = useState(false);
2371
+ const copyToClipboard = (value) => {
2372
+ if (!value) return;
2373
+ navigator.clipboard.writeText(value).then(() => {
2374
+ setIsCopied(true);
2375
+ setTimeout(() => setIsCopied(false), copiedDuration);
2376
+ });
2377
+ };
2378
+ return { isCopied, copyToClipboard };
2379
+ };
2380
+ var MarkdownContent = memo(({ content }) => {
2381
+ return /* @__PURE__ */ jsx("div", { className: "aui-md max-w-none text-white", children: /* @__PURE__ */ jsx(
2382
+ ReactMarkdown,
2383
+ {
2384
+ remarkPlugins: [remarkGfm],
2385
+ components: {
2386
+ h1: ({ className, ...props }) => /* @__PURE__ */ jsx(
2387
+ "h1",
2388
+ {
2389
+ className: cn(
2390
+ "mb-2 font-extrabold tracking-tight last:mb-0 text-white",
2391
+ className
2392
+ ),
2393
+ style: { fontSize: "12px" },
2394
+ ...props
2395
+ }
2396
+ ),
2397
+ h2: ({ className, ...props }) => /* @__PURE__ */ jsx(
2398
+ "h2",
2399
+ {
2400
+ className: cn(
2401
+ "mt-3 mb-1.5 font-semibold tracking-tight first:mt-0 last:mb-0 text-white",
2402
+ className
2403
+ ),
2404
+ style: { fontSize: "10px" },
2405
+ ...props
2406
+ }
2407
+ ),
2408
+ h3: ({ className, ...props }) => /* @__PURE__ */ jsx(
2409
+ "h3",
2410
+ {
2411
+ className: cn(
2412
+ "mt-2 mb-1 font-semibold tracking-tight first:mt-0 last:mb-0 text-white",
2413
+ className
2414
+ ),
2415
+ style: { fontSize: "9px" },
2416
+ ...props
2417
+ }
2418
+ ),
2419
+ p: ({ className, ...props }) => /* @__PURE__ */ jsx(
2420
+ "p",
2421
+ {
2422
+ className: cn(
2423
+ "mt-1.5 mb-1.5 leading-relaxed first:mt-0 last:mb-0 text-white/90",
2424
+ className
2425
+ ),
2426
+ ...props
2427
+ }
2428
+ ),
2429
+ ul: ({ className, ...props }) => /* @__PURE__ */ jsx(
2430
+ "ul",
2431
+ {
2432
+ className: cn(
2433
+ "my-1.5 ml-3 list-disc [&>li]:mt-0.5 text-white/90",
2434
+ className
2435
+ ),
2436
+ ...props
2437
+ }
2438
+ ),
2439
+ ol: ({ className, ...props }) => /* @__PURE__ */ jsx(
2440
+ "ol",
2441
+ {
2442
+ className: cn(
2443
+ "my-1.5 ml-3 list-decimal [&>li]:mt-0.5 text-white/90",
2444
+ className
2445
+ ),
2446
+ ...props
2447
+ }
2448
+ ),
2449
+ blockquote: ({ className, ...props }) => /* @__PURE__ */ jsx(
2450
+ "blockquote",
2451
+ {
2452
+ className: cn(
2453
+ "border-l-2 border-white/30 pl-2 italic text-white/70",
2454
+ className
2455
+ ),
2456
+ ...props
2457
+ }
2458
+ ),
2459
+ pre: ({ className, ...props }) => /* @__PURE__ */ jsx(
2460
+ "pre",
2461
+ {
2462
+ className: cn(
2463
+ "overflow-x-auto rounded bg-black/30 p-1.5 text-white/90 my-1.5",
2464
+ className
2465
+ ),
2466
+ ...props
2467
+ }
2468
+ ),
2469
+ code: ({ className, ...props }) => {
2470
+ const isInline = !className?.includes("language-");
2471
+ return /* @__PURE__ */ jsx(
2472
+ "code",
2473
+ {
2474
+ className: cn(
2475
+ isInline && "rounded bg-black/30 px-0.5 py-0.5 font-mono text-white/90",
2476
+ className
2477
+ ),
2478
+ ...props
2479
+ }
2480
+ );
2481
+ },
2482
+ a: ({ className, ...props }) => /* @__PURE__ */ jsx(
2483
+ "a",
2484
+ {
2485
+ className: cn(
2486
+ "font-medium text-blue-300 underline underline-offset-2",
2487
+ className
2488
+ ),
2489
+ target: "_blank",
2490
+ rel: "noopener noreferrer",
2491
+ ...props
2492
+ }
2493
+ ),
2494
+ hr: ({ className, ...props }) => /* @__PURE__ */ jsx(
2495
+ "hr",
2496
+ {
2497
+ className: cn("my-2 border-b border-white/20", className),
2498
+ ...props
2499
+ }
2500
+ )
2501
+ },
2502
+ children: content
2503
+ }
2504
+ ) });
2505
+ });
2506
+ MarkdownContent.displayName = "MarkdownContent";
2507
+ var DetailedAnswerToolUI = makeAssistantToolUI({
2508
+ toolName: "generateDetailedAnswer",
2509
+ render: function DetailedAnswerUI({ args, result, status }) {
2510
+ const { isCopied, copyToClipboard } = useCopyToClipboard();
2511
+ const isStreaming = status.type === "running";
2512
+ const isError = status.type === "incomplete";
2513
+ const title = result?.title || args.title || "Generating...";
2514
+ const content = result?.content || args.content || "";
2515
+ const summary = result?.summary || args.summary || "";
2516
+ const handleCopy = () => {
2517
+ if (content) {
2518
+ copyToClipboard(content);
2451
2519
  }
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);
2520
+ };
2521
+ const handleOpenFullScreen = () => {
2522
+ const newWindow = window.open("", "_blank");
2523
+ if (newWindow) {
2524
+ newWindow.document.write(`
2525
+ <!DOCTYPE html>
2526
+ <html>
2527
+ <head>
2528
+ <title>${title}</title>
2529
+ <meta charset="utf-8">
2530
+ <meta name="viewport" content="width=device-width, initial-scale=1">
2531
+ <style>
2532
+ body {
2533
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
2534
+ max-width: 800px;
2535
+ margin: 0 auto;
2536
+ padding: 2rem;
2537
+ line-height: 1.6;
2538
+ color: #1a1a1a;
2539
+ }
2540
+ h1 { border-bottom: 1px solid #eee; padding-bottom: 0.5rem; }
2541
+ pre { background: #f5f5f5; padding: 1rem; overflow-x: auto; border-radius: 4px; }
2542
+ code { background: #f5f5f5; padding: 0.2em 0.4em; border-radius: 3px; font-size: 0.9em; }
2543
+ pre code { background: none; padding: 0; }
2544
+ blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 1rem; color: #666; }
2545
+ </style>
2546
+ </head>
2547
+ <body>
2548
+ <h1>${title}</h1>
2549
+ <div id="content">${content.replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>
2550
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
2551
+ <script>
2552
+ document.getElementById('content').innerHTML = marked.parse(${JSON.stringify(
2553
+ content
2554
+ )});
2555
+ </script>
2556
+ </body>
2557
+ </html>
2558
+ `);
2559
+ newWindow.document.close();
2459
2560
  }
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
- }
2561
+ };
2562
+ 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;
2563
+ const footerActions = content ? /* @__PURE__ */ jsxs(Fragment, { children: [
2564
+ /* @__PURE__ */ jsx(
2565
+ TooltipIconButton,
2566
+ {
2567
+ tooltip: isCopied ? "Copied!" : "Copy markdown",
2568
+ onClick: handleCopy,
2569
+ className: "flex items-center justify-center rounded-md p-1.5 text-white/70 hover:bg-white/10 transition-colors",
2570
+ children: isCopied ? /* @__PURE__ */ jsx(CheckIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(CopyIcon, { className: "h-3.5 w-3.5" })
2571
+ }
2572
+ ),
2573
+ /* @__PURE__ */ jsx(
2574
+ TooltipIconButton,
2575
+ {
2576
+ tooltip: "Open in new window",
2577
+ onClick: handleOpenFullScreen,
2578
+ className: "flex items-center justify-center rounded-md p-1.5 text-white/70 hover:bg-white/10 transition-colors",
2579
+ children: /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "h-3.5 w-3.5" })
2580
+ }
2581
+ )
2582
+ ] }) : void 0;
2583
+ return /* @__PURE__ */ jsx(
2584
+ ToolCard,
2585
+ {
2586
+ title,
2587
+ isStreaming,
2588
+ isError,
2589
+ icon: !isStreaming && !isError ? /* @__PURE__ */ jsx(FileTextIcon, { className: "h-4 w-4" }) : void 0,
2590
+ persistentContent: persistentSummary,
2591
+ footer: footerActions,
2592
+ children: content ? /* @__PURE__ */ jsx(MarkdownContent, { content }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground italic", children: "Generating content..." })
2593
+ }
2594
+ );
2595
+ }
2596
+ });
2472
2597
  function Dialog({
2473
2598
  ...props
2474
2599
  }) {
@@ -3856,7 +3981,7 @@ var ThreadSuggestions = () => {
3856
3981
  className: "fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200",
3857
3982
  style: { animationDelay: `${200 + index * 50}ms` },
3858
3983
  children: /* @__PURE__ */ jsx(ThreadPrimitive.Suggestion, { prompt: suggestion.prompt, send: true, asChild: true, children: /* @__PURE__ */ jsx(
3859
- Button,
3984
+ Button2,
3860
3985
  {
3861
3986
  variant: "ghost",
3862
3987
  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",
@@ -4062,7 +4187,7 @@ var ComposerAction = () => {
4062
4187
  }
4063
4188
  ) }) }),
4064
4189
  /* @__PURE__ */ jsx(AssistantIf, { condition: ({ thread }) => thread.isRunning, children: /* @__PURE__ */ jsx(ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ jsx(
4065
- Button,
4190
+ Button2,
4066
4191
  {
4067
4192
  type: "button",
4068
4193
  variant: "default",
@@ -4207,8 +4332,8 @@ var EditComposer = () => {
4207
4332
  }
4208
4333
  ),
4209
4334
  /* @__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" }) })
4335
+ /* @__PURE__ */ jsx(ComposerPrimitive.Cancel, { asChild: true, children: /* @__PURE__ */ jsx(Button2, { variant: "ghost", size: "sm", children: "Cancel" }) }),
4336
+ /* @__PURE__ */ jsx(ComposerPrimitive.Send, { asChild: true, children: /* @__PURE__ */ jsx(Button2, { size: "sm", children: "Update" }) })
4212
4337
  ] })
4213
4338
  ] }) });
4214
4339
  };
@@ -4257,7 +4382,7 @@ var ThreadList = () => {
4257
4382
  ThreadListPrimitive.Items,
4258
4383
  {
4259
4384
  components: {
4260
- ThreadListItem
4385
+ ThreadListItem: ThreadListItem2
4261
4386
  }
4262
4387
  }
4263
4388
  ),
@@ -4274,7 +4399,7 @@ var ThreadList = () => {
4274
4399
  ] })
4275
4400
  ] });
4276
4401
  };
4277
- var ThreadListItem = () => {
4402
+ var ThreadListItem2 = () => {
4278
4403
  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
4404
  /* @__PURE__ */ jsxs(ThreadListItemPrimitive.Trigger, { className: "flex flex-1 items-center gap-2 min-w-0", children: [
4280
4405
  /* @__PURE__ */ jsx(MessageSquareIcon, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground" }),
@@ -4334,114 +4459,13 @@ var ArchivedThreadListItem = () => {
4334
4459
  ] })
4335
4460
  ] });
4336
4461
  };
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
4462
  var ChatWidget = ({
4440
4463
  sidebarOpen = false,
4441
4464
  onSidebarClose
4442
4465
  }) => {
4443
4466
  return /* @__PURE__ */ jsxs("div", { className: "relative flex flex-1 h-full w-full overflow-hidden bg-background", children: [
4444
4467
  /* @__PURE__ */ jsx(ArtifactToolUIs, {}),
4468
+ /* @__PURE__ */ jsx(DetailedAnswerToolUI, {}),
4445
4469
  /* @__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
4470
  /* @__PURE__ */ jsx(AnimatePresence, { children: sidebarOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
4447
4471
  /* @__PURE__ */ jsx(
@@ -4471,27 +4495,6 @@ var ChatWidget = ({
4471
4495
  ] }) })
4472
4496
  ] });
4473
4497
  };
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
4498
  var layoutOptions = [
4496
4499
  {
4497
4500
  value: "sidebar",