@docyrus/ui-pro-ai-assistant 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { Input } from '@docyrus/ui-pro-shared/components/input';
9
9
  import { Tabs as Tabs$1, TabsList as TabsList$1, TabsTrigger as TabsTrigger$1, TabsContent as TabsContent$1 } from '@docyrus/ui-pro-shared/components/tabs';
10
10
  import { cn } from '@docyrus/ui-pro-shared/lib/utils';
11
11
  import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
12
- import { PilcrowIcon, Heading1Icon, Heading2Icon, Heading3Icon, SquareIcon, ListIcon, ListOrderedIcon, ChevronDownIcon, Code2Icon, QuoteIcon, LightbulbIcon, Columns3Icon, GripVertical, FileUpIcon, TableIcon, ImageIcon, FilmIcon, AudioLinesIcon, TableOfContentsIcon, RadicalIcon, RectangleVerticalIcon, CalendarIcon, PlusIcon, FileCodeIcon, MinusIcon, ChevronRightIcon, ListTree, PenToolIcon, Link2Icon, Check, Copy, FilesIcon, Link, Text, ExternalLink, Unlink, Bold, Italic, Underline, Strikethrough, Code2, MoreHorizontal, ArrowLeftIcon, ArrowRightIcon, Minus, Plus, CircleArrowDown, Minimize2, Trash2, FileUp, CheckCircle2, FileText, Loader2, CornerDownLeftIcon, PencilLineIcon, MessageSquareTextIcon, MessagesSquareIcon, ArrowUpIcon, CheckIcon, CaptionsIcon, ZoomInIcon, CircleArrowDownIcon, MoveUpRightIcon, MoreHorizontalIcon, Eye, Pencil, PlusCircle, HelpCircle, Maximize2, X, Download, FileSpreadsheet, ChevronDown, Search, Globe, CheckCircle, FolderOpen, User, ArrowRight, MapPin, CalendarClock, List, RefreshCw, FilePlus, XIcon, CornerUpLeftIcon, AlbumIcon, FeatherIcon, ListMinusIcon, ListPlusIcon, ListEnd, Wand, LanguagesIcon, BadgeHelpIcon, PenLineIcon, SearchIcon, MusicIcon, CompassIcon, SmileIcon, LeafIcon, ClockIcon, AppleIcon, FlagIcon, StarIcon, DeleteIcon, AlignLeft, AlignCenter, AlignRight, RotateCcw, AlertTriangle, XCircle, AlertCircle, ArrowUpDown, ArrowDownToLine, PenLine, PencilIcon, TrashIcon, RefreshCwIcon, PaintRoller, MessageSquareText, ArrowLeft, RefreshCcw, Code, Brain, Star, Trash, Edit, FolderInput, Archive, Sparkles, PanelLeft, MessageSquare, NotebookText, CirclePlus, MoreVertical, SlidersHorizontal, FileSearch, Microscope, Ruler, Mic, AudioLines, BrainCircuit, File as File$1, Plug, Inbox, Menu, ChevronRight, LayoutDashboard, Table2, WandSparklesIcon, ArrowUpToLineIcon, BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, HighlighterIcon, Undo2Icon, Redo2Icon, ArrowDownToLineIcon, AlignLeftIcon, AlignCenterIcon, AlignRightIcon, AlignJustifyIcon, ListOrdered, ListTodoIcon, ListCollapseIcon, Table, Grid3x3Icon, Combine, Ungroup, ArrowUp, ArrowDown, Trash2Icon, LinkIcon, WrapText, OutdentIcon, IndentIcon, EyeIcon, PenIcon } from 'lucide-react';
12
+ import { PilcrowIcon, Heading1Icon, Heading2Icon, Heading3Icon, SquareIcon, ListIcon, ListOrderedIcon, ChevronDownIcon, Code2Icon, QuoteIcon, LightbulbIcon, Columns3Icon, GripVertical, FileUpIcon, TableIcon, ImageIcon, FilmIcon, AudioLinesIcon, TableOfContentsIcon, RadicalIcon, RectangleVerticalIcon, CalendarIcon, PlusIcon, FileCodeIcon, MinusIcon, ChevronRightIcon, ListTree, PenToolIcon, Link2Icon, Check, Copy, FilesIcon, Link, Text, ExternalLink, Unlink, Bold, Italic, Underline, Strikethrough, Code2, MoreHorizontal, ArrowLeftIcon, ArrowRightIcon, Minus, Plus, CircleArrowDown, Minimize2, Trash2, FileUp, CheckCircle2, FileText, Loader2, CornerDownLeftIcon, PencilLineIcon, MessageSquareTextIcon, MessagesSquareIcon, ArrowUpIcon, CheckIcon, CaptionsIcon, ZoomInIcon, CircleArrowDownIcon, MoveUpRightIcon, MoreHorizontalIcon, Eye, Pencil, PlusCircle, HelpCircle, Maximize2, X, Download, FileSpreadsheet, ChevronDown, Search, Globe, CheckCircle, FolderOpen, User, ArrowRight, MapPin, CalendarClock, List, RefreshCw, FilePlus, XIcon, CornerUpLeftIcon, AlbumIcon, FeatherIcon, ListMinusIcon, ListPlusIcon, ListEnd, Wand, LanguagesIcon, BadgeHelpIcon, PenLineIcon, SearchIcon, MusicIcon, CompassIcon, SmileIcon, LeafIcon, ClockIcon, AppleIcon, FlagIcon, StarIcon, DeleteIcon, AlignLeft, AlignCenter, AlignRight, RotateCcw, AlertTriangle, XCircle, AlertCircle, ArrowUpDown, ArrowDownToLine, PenLine, PencilIcon, TrashIcon, RefreshCwIcon, PaintRoller, MessageSquareText, ArrowLeft, ChevronLeft, Bot, ChevronRight, Brain, Lightbulb, BookOpen, PenTool, SlidersHorizontal, Mic, RefreshCcw, Code, Star, Trash, Edit, FolderInput, Archive, Sparkles, PanelLeft, MessageSquare, NotebookText, CirclePlus, MoreVertical, FileSearch, Microscope, Ruler, AudioLines, BrainCircuit, File as File$1, Plug, Inbox, Menu, LayoutDashboard, Table2, WandSparklesIcon, ArrowUpToLineIcon, BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, HighlighterIcon, Undo2Icon, Redo2Icon, ArrowDownToLineIcon, AlignLeftIcon, AlignCenterIcon, AlignRightIcon, AlignJustifyIcon, ListOrdered, ListTodoIcon, ListCollapseIcon, Table, Grid3x3Icon, Combine, Ungroup, ArrowUp, ArrowDown, Trash2Icon, LinkIcon, WrapText, OutdentIcon, IndentIcon, EyeIcon, PenIcon } from 'lucide-react';
13
13
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
14
14
  import { AsyncTokenManager, RestApiClient } from '@docyrus/api-client';
15
15
  import { TooltipProvider, Tooltip as Tooltip$1, TooltipTrigger, TooltipContent } from '@docyrus/ui-pro-shared/components/tooltip';
@@ -2520,7 +2520,116 @@ function useApiClient() {
2520
2520
  }, [config3]);
2521
2521
  }
2522
2522
 
2523
- // src/hooks/use-assistant-api.ts
2523
+ // src/hooks/use-agents-data.ts
2524
+ function resolveAvatar(agent) {
2525
+ for (const key of ["agentAvatar", "avatar", "agentsAvatar"]) {
2526
+ const val = agent[key];
2527
+ if (val && typeof val === "object" && "signed_url" in val) {
2528
+ const url = val.signed_url;
2529
+ if (url) return url;
2530
+ }
2531
+ if (typeof val === "string" && val) return val;
2532
+ }
2533
+ return null;
2534
+ }
2535
+ function extractCapabilities(agent) {
2536
+ return {
2537
+ supportWebSearch: agent.supportWebSearch ?? false,
2538
+ supportDocumentSearch: agent.documentSearch ?? false,
2539
+ supportDeepResearch: agent.supportDeepResearch ?? false,
2540
+ supportThinking: agent.supportThinking ?? false,
2541
+ supportWorkCanvas: agent.featureWorks ?? false,
2542
+ supportFiles: agent.supportFiles ?? false
2543
+ };
2544
+ }
2545
+ function toAgentTriggerData(id, data) {
2546
+ const agent = data.agent ?? data;
2547
+ return {
2548
+ id,
2549
+ name: agent.agent_name || agent.name || "",
2550
+ avatar: resolveAvatar(agent),
2551
+ welcomeMessage: agent.welcomeMessage || agent.welcome_message || null,
2552
+ description: agent.description ?? null,
2553
+ capabilities: extractCapabilities(agent),
2554
+ models: agent.models ?? [],
2555
+ standardSuggestions: agent.standardSuggestions ?? agent.standard_suggestions ?? []
2556
+ };
2557
+ }
2558
+ function useAgentsData(agentIds) {
2559
+ const apiClient = useApiClient();
2560
+ const apiClientRef = useRef(apiClient);
2561
+ apiClientRef.current = apiClient;
2562
+ const [agents, setAgents] = useState([]);
2563
+ const [isLoading, setIsLoading] = useState(false);
2564
+ const [error, setError] = useState(null);
2565
+ const [retryCount, setRetryCount] = useState(0);
2566
+ const idsKey = agentIds.join(",");
2567
+ useEffect(() => {
2568
+ let cancelled = false;
2569
+ const run = async () => {
2570
+ const ids = idsKey.split(",").filter(Boolean);
2571
+ if (ids.length === 0) {
2572
+ setAgents([]);
2573
+ return;
2574
+ }
2575
+ setIsLoading(true);
2576
+ setError(null);
2577
+ try {
2578
+ const BATCH_SIZE = 3;
2579
+ const BATCH_DELAY = 200;
2580
+ const resolved = [];
2581
+ const client = apiClientRef.current;
2582
+ for (let start = 0; start < ids.length; start += BATCH_SIZE) {
2583
+ if (cancelled) return;
2584
+ if (start > 0) {
2585
+ await new Promise((resolve) => {
2586
+ const timer = setTimeout(resolve, BATCH_DELAY);
2587
+ if (cancelled) clearTimeout(timer);
2588
+ });
2589
+ }
2590
+ const batch = ids.slice(start, start + BATCH_SIZE);
2591
+ const results = await Promise.allSettled(
2592
+ batch.map((id) => client.get(`/ai/agent-deployments/base/${id}`))
2593
+ );
2594
+ for (let i = 0; i < batch.length; i++) {
2595
+ const result = results[i];
2596
+ if (result.status === "fulfilled" && result.value.success && result.value.data) {
2597
+ resolved.push(
2598
+ toAgentTriggerData(batch[i], result.value.data)
2599
+ );
2600
+ }
2601
+ }
2602
+ }
2603
+ if (!cancelled) {
2604
+ setAgents(resolved);
2605
+ }
2606
+ } catch (err) {
2607
+ if (!cancelled) {
2608
+ setError(
2609
+ err instanceof Error ? err : new Error("Failed to fetch agents")
2610
+ );
2611
+ }
2612
+ } finally {
2613
+ if (!cancelled) {
2614
+ setIsLoading(false);
2615
+ }
2616
+ }
2617
+ };
2618
+ void run();
2619
+ return () => {
2620
+ cancelled = true;
2621
+ };
2622
+ }, [idsKey, retryCount]);
2623
+ const retry = useCallback(() => {
2624
+ setRetryCount((c) => c + 1);
2625
+ }, []);
2626
+ return {
2627
+ agents,
2628
+ isLoading,
2629
+ error,
2630
+ retry
2631
+ };
2632
+ }
2524
2633
  function useAssistantApi({
2525
2634
  tenantAiAgentId,
2526
2635
  deploymentId,
@@ -24567,6 +24676,7 @@ var DocyAssistant = ({
24567
24676
  agentSelectorUrl = "/ai/agent-deployments",
24568
24677
  baseAgentSelectorUrl = "/ai/agent-deployments/base",
24569
24678
  onAgentChange,
24679
+ initialPrompt,
24570
24680
  ...props
24571
24681
  }) => {
24572
24682
  const config3 = useAssistantConfig();
@@ -24602,6 +24712,7 @@ var DocyAssistant = ({
24602
24712
  const selectedSessionIdRef = useRef(null);
24603
24713
  const authTokenRef = useRef("");
24604
24714
  const messageOptionsRef = useRef(null);
24715
+ const initialPromptSentRef = useRef(false);
24605
24716
  useEffect(() => {
24606
24717
  selectedSessionIdRef.current = sessionState.selectedSessionId;
24607
24718
  }, [sessionState.selectedSessionId]);
@@ -24909,6 +25020,14 @@ var DocyAssistant = ({
24909
25020
  }
24910
25021
  });
24911
25022
  };
25023
+ useEffect(() => {
25024
+ if (!initialPrompt || initialPromptSentRef.current) return;
25025
+ initialPromptSentRef.current = true;
25026
+ setInput(initialPrompt);
25027
+ setTimeout(() => {
25028
+ handleSendMessage();
25029
+ }, 300);
25030
+ }, [initialPrompt]);
24912
25031
  const handleInputChange = useCallback((e) => {
24913
25032
  setInput(e.target.value);
24914
25033
  }, []);
@@ -25513,7 +25632,630 @@ var DocyAssistant = ({
25513
25632
  assistantDialogs
25514
25633
  ] });
25515
25634
  };
25635
+ function computeVisibleSlots(agents, index) {
25636
+ const len = agents.length;
25637
+ if (len === 0) return [];
25638
+ if (len === 1) return [
25639
+ null,
25640
+ null,
25641
+ agents[0],
25642
+ null,
25643
+ null
25644
+ ];
25645
+ if (len === 2) {
25646
+ const prev3 = index === 0 ? 1 : 0;
25647
+ return [
25648
+ null,
25649
+ agents[prev3],
25650
+ agents[index],
25651
+ agents[prev3],
25652
+ null
25653
+ ];
25654
+ }
25655
+ if (len === 3) {
25656
+ const prev3 = (index - 1 + len) % len;
25657
+ const next3 = (index + 1) % len;
25658
+ return [
25659
+ null,
25660
+ agents[prev3],
25661
+ agents[index],
25662
+ agents[next3],
25663
+ null
25664
+ ];
25665
+ }
25666
+ if (len === 4) {
25667
+ const prev22 = (index - 2 + len) % len;
25668
+ const prev3 = (index - 1 + len) % len;
25669
+ const next3 = (index + 1) % len;
25670
+ return [
25671
+ agents[prev22],
25672
+ agents[prev3],
25673
+ agents[index],
25674
+ agents[next3],
25675
+ agents[prev22]
25676
+ ];
25677
+ }
25678
+ const prev2 = (index - 2 + len) % len;
25679
+ const prev = (index - 1 + len) % len;
25680
+ const next = (index + 1) % len;
25681
+ const next2 = (index + 2) % len;
25682
+ return [
25683
+ agents[prev2],
25684
+ agents[prev],
25685
+ agents[index],
25686
+ agents[next],
25687
+ agents[next2]
25688
+ ];
25689
+ }
25690
+ var SLOT_OUTER_CLASS = {
25691
+ 0: "z-0 mx-2",
25692
+ 1: "z-5 mx-4",
25693
+ 2: "z-10 mx-6",
25694
+ 3: "z-5 mx-4",
25695
+ 4: "z-0 mx-2"
25696
+ };
25697
+ var SLOT_CIRCLE_CLASS = {
25698
+ 0: "size-12 bg-muted opacity-40",
25699
+ 1: "size-20 bg-muted opacity-70",
25700
+ 2: "size-28 bg-gradient-to-br from-sky-100 to-indigo-100 ring-4 ring-sky-400 dark:from-sky-900/30 dark:to-indigo-900/30 dark:ring-sky-600",
25701
+ 3: "size-20 bg-muted opacity-70",
25702
+ 4: "size-12 bg-muted opacity-40"
25703
+ };
25704
+ var SLOT_IMG_CLASS = {
25705
+ 0: "size-10",
25706
+ 1: "size-16",
25707
+ 2: "size-24",
25708
+ 3: "size-16",
25709
+ 4: "size-10"
25710
+ };
25711
+ var SLOT_BOT_CLASS = {
25712
+ 0: "size-8 text-slate-400",
25713
+ 1: "size-12 text-slate-500",
25714
+ 2: "size-16 text-sky-600",
25715
+ 3: "size-12 text-slate-500",
25716
+ 4: "size-8 text-slate-400"
25717
+ };
25718
+ function isImageUrl(url) {
25719
+ if (!url) return false;
25720
+ return url.startsWith("http") || url.startsWith("/") || url.startsWith("data:");
25721
+ }
25722
+ function AgentCarousel({
25723
+ agents,
25724
+ selectedIndex,
25725
+ onSelect,
25726
+ onNavigate
25727
+ }) {
25728
+ const visibleSlots = computeVisibleSlots(agents, selectedIndex);
25729
+ const handleKeyDown = useCallback(
25730
+ (e) => {
25731
+ const target = e.target;
25732
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)
25733
+ return;
25734
+ if (e.key === "ArrowLeft") {
25735
+ e.preventDefault();
25736
+ onNavigate(-1);
25737
+ } else if (e.key === "ArrowRight") {
25738
+ e.preventDefault();
25739
+ onNavigate(1);
25740
+ }
25741
+ },
25742
+ [onNavigate]
25743
+ );
25744
+ if (agents.length === 0) return null;
25745
+ return /* @__PURE__ */ jsxs(
25746
+ "div",
25747
+ {
25748
+ className: "flex h-32 items-center justify-center gap-6",
25749
+ onKeyDown: handleKeyDown,
25750
+ tabIndex: 0,
25751
+ children: [
25752
+ /* @__PURE__ */ jsx(
25753
+ "button",
25754
+ {
25755
+ type: "button",
25756
+ className: "flex size-12 shrink-0 items-center justify-center rounded-full bg-muted transition-colors hover:bg-muted/80 disabled:cursor-not-allowed disabled:opacity-50",
25757
+ disabled: agents.length <= 1,
25758
+ onClick: () => onNavigate(-1),
25759
+ "aria-label": "Previous agent",
25760
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-6 text-muted-foreground" })
25761
+ }
25762
+ ),
25763
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: visibleSlots.map((slot, i) => slot ? /* @__PURE__ */ jsx(
25764
+ "div",
25765
+ {
25766
+ className: cn(
25767
+ "shrink-0 cursor-pointer transition-all duration-500 ease-out",
25768
+ SLOT_OUTER_CLASS[i]
25769
+ ),
25770
+ onClick: () => {
25771
+ const idx = agents.findIndex((a) => a.id === slot.id);
25772
+ if (idx !== -1) onSelect(idx);
25773
+ },
25774
+ children: /* @__PURE__ */ jsx(
25775
+ "div",
25776
+ {
25777
+ className: cn(
25778
+ "flex items-center justify-center rounded-full shadow-lg transition-all duration-500 ease-out",
25779
+ SLOT_CIRCLE_CLASS[i]
25780
+ ),
25781
+ children: slot.avatar && isImageUrl(slot.avatar) ? /* @__PURE__ */ jsx(
25782
+ "img",
25783
+ {
25784
+ src: slot.avatar,
25785
+ alt: slot.name,
25786
+ className: cn(
25787
+ "rounded-full object-cover transition-all duration-500 ease-out",
25788
+ SLOT_IMG_CLASS[i]
25789
+ )
25790
+ }
25791
+ ) : /* @__PURE__ */ jsx(Bot, { className: SLOT_BOT_CLASS[i] })
25792
+ }
25793
+ )
25794
+ },
25795
+ slot.id
25796
+ ) : /* @__PURE__ */ jsx("div", { className: "size-12 shrink-0" }, `empty-slot-${i === 0 ? "far-left" : i === 1 ? "left" : i === 3 ? "right" : "far-right"}`)) }),
25797
+ /* @__PURE__ */ jsx(
25798
+ "button",
25799
+ {
25800
+ type: "button",
25801
+ className: "flex size-12 shrink-0 items-center justify-center rounded-full bg-muted transition-colors hover:bg-muted/80 disabled:cursor-not-allowed disabled:opacity-50",
25802
+ disabled: agents.length <= 1,
25803
+ onClick: () => onNavigate(1),
25804
+ "aria-label": "Next agent",
25805
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-6 text-muted-foreground" })
25806
+ }
25807
+ )
25808
+ ]
25809
+ }
25810
+ );
25811
+ }
25812
+ var CAPABILITY_TOGGLES = [
25813
+ {
25814
+ key: "webSearch",
25815
+ capKey: "supportWebSearch",
25816
+ icon: Globe,
25817
+ labelKey: "tools.web_search"
25818
+ },
25819
+ {
25820
+ key: "thinking",
25821
+ capKey: "supportThinking",
25822
+ icon: Brain,
25823
+ labelKey: "tools.thinking"
25824
+ },
25825
+ {
25826
+ key: "deepResearch",
25827
+ capKey: "supportDeepResearch",
25828
+ icon: Lightbulb,
25829
+ labelKey: "tools.deep_research"
25830
+ },
25831
+ {
25832
+ key: "documentSearch",
25833
+ capKey: "supportDocumentSearch",
25834
+ icon: BookOpen,
25835
+ labelKey: "tools.document_search"
25836
+ },
25837
+ {
25838
+ key: "workCanvas",
25839
+ capKey: "supportWorkCanvas",
25840
+ icon: PenTool,
25841
+ labelKey: "tools.work_canvas"
25842
+ },
25843
+ {
25844
+ key: "files",
25845
+ capKey: "supportFiles",
25846
+ icon: FileUp,
25847
+ labelKey: "tools.file_upload"
25848
+ }
25849
+ ];
25850
+ function ToggleSwitch({
25851
+ checked,
25852
+ onChange,
25853
+ label
25854
+ }) {
25855
+ return /* @__PURE__ */ jsx(
25856
+ "button",
25857
+ {
25858
+ type: "button",
25859
+ role: "switch",
25860
+ "aria-checked": checked,
25861
+ "aria-label": label,
25862
+ onClick: onChange,
25863
+ className: cn(
25864
+ "relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2",
25865
+ checked ? "bg-sky-500" : "bg-gray-300 dark:bg-gray-600"
25866
+ ),
25867
+ children: /* @__PURE__ */ jsx(
25868
+ "span",
25869
+ {
25870
+ className: cn(
25871
+ "inline-block size-3 rounded-full bg-white transition-transform",
25872
+ checked ? "translate-x-5" : "translate-x-1"
25873
+ )
25874
+ }
25875
+ )
25876
+ }
25877
+ );
25878
+ }
25879
+ function useClickOutside(ref, open, onClose) {
25880
+ useEffect(() => {
25881
+ if (!open) return;
25882
+ const handler = (e) => {
25883
+ if (ref.current && !ref.current.contains(e.target)) {
25884
+ onClose();
25885
+ }
25886
+ };
25887
+ document.addEventListener("mousedown", handler);
25888
+ return () => document.removeEventListener("mousedown", handler);
25889
+ }, [ref, open, onClose]);
25890
+ }
25891
+ function AgentTriggerPrompt({
25892
+ capabilities,
25893
+ models,
25894
+ suggestions,
25895
+ placeholder,
25896
+ onSubmit
25897
+ }) {
25898
+ const { t } = useAssistantTranslation();
25899
+ const [prompt, setPrompt] = useState("");
25900
+ const [selectedModel, setSelectedModel] = useState(
25901
+ models[0]
25902
+ );
25903
+ const [features, setFeatures] = useState({
25904
+ webSearch: false,
25905
+ thinking: false,
25906
+ deepResearch: false,
25907
+ documentSearch: false,
25908
+ workCanvas: false,
25909
+ files: false
25910
+ });
25911
+ const [settingsOpen, setSettingsOpen] = useState(false);
25912
+ const [modelDropdownOpen, setModelDropdownOpen] = useState(false);
25913
+ const [reasoningDropdownOpen, setReasoningDropdownOpen] = useState(false);
25914
+ const [reasoningOverride, setReasoningOverride] = useState(null);
25915
+ const settingsRef = useRef(null);
25916
+ const modelRef = useRef(null);
25917
+ const reasoningRef = useRef(null);
25918
+ useClickOutside(settingsRef, settingsOpen, () => setSettingsOpen(false));
25919
+ useClickOutside(modelRef, modelDropdownOpen, () => setModelDropdownOpen(false));
25920
+ useClickOutside(reasoningRef, reasoningDropdownOpen, () => setReasoningDropdownOpen(false));
25921
+ const hasThinking = capabilities?.supportThinking || selectedModel?.supportThinking;
25922
+ const reasoningLevels = useMemo(
25923
+ () => hasThinking ? selectedModel?.reasoningLevels ?? [] : [],
25924
+ [hasThinking, selectedModel?.reasoningLevels]
25925
+ );
25926
+ const selectedReasoningLevel = useMemo(() => {
25927
+ if (reasoningLevels.length === 0) return null;
25928
+ if (reasoningOverride && reasoningLevels.some((l) => l.id === reasoningOverride.id)) {
25929
+ return reasoningOverride;
25930
+ }
25931
+ const defaultLevel = reasoningLevels.find((l) => l.default === true);
25932
+ return defaultLevel ?? reasoningLevels[0];
25933
+ }, [reasoningLevels, reasoningOverride]);
25934
+ const toggleFeature = useCallback((key) => {
25935
+ setFeatures((prev) => ({ ...prev, [key]: !prev[key] }));
25936
+ }, []);
25937
+ const handleSubmit = useCallback(() => {
25938
+ const trimmed = prompt.trim();
25939
+ if (!trimmed) return;
25940
+ onSubmit(trimmed, features, selectedModel?.id);
25941
+ setPrompt("");
25942
+ }, [
25943
+ prompt,
25944
+ features,
25945
+ selectedModel,
25946
+ onSubmit
25947
+ ]);
25948
+ const handleKeyDown = useCallback(
25949
+ (e) => {
25950
+ if (e.key === "Enter" && !e.shiftKey) {
25951
+ e.preventDefault();
25952
+ handleSubmit();
25953
+ }
25954
+ },
25955
+ [handleSubmit]
25956
+ );
25957
+ const handleSuggestionClick = useCallback(
25958
+ (suggestion) => {
25959
+ setPrompt(suggestion);
25960
+ },
25961
+ []
25962
+ );
25963
+ const availableToggles = capabilities ? CAPABILITY_TOGGLES.filter((toggle) => {
25964
+ if (!capabilities[toggle.capKey]) return false;
25965
+ if (toggle.key === "thinking" && reasoningLevels.length > 0) return false;
25966
+ return true;
25967
+ }) : [];
25968
+ return /* @__PURE__ */ jsxs("div", { className: "mt-4 mb-1 w-full max-w-[54rem]", children: [
25969
+ suggestions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
25970
+ /* @__PURE__ */ jsx(
25971
+ "button",
25972
+ {
25973
+ type: "button",
25974
+ title: t("common.generate_suggestions") || "Generate Suggestions",
25975
+ className: "flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground",
25976
+ children: /* @__PURE__ */ jsx(Plus, { className: "size-4" })
25977
+ }
25978
+ ),
25979
+ /* @__PURE__ */ jsx("div", { className: "suggestions-container flex items-center gap-2 overflow-x-auto", children: suggestions.map((s) => /* @__PURE__ */ jsx(
25980
+ "button",
25981
+ {
25982
+ type: "button",
25983
+ title: s,
25984
+ className: "max-w-64 shrink-0 truncate rounded-lg border border-border bg-muted/50 px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
25985
+ onClick: () => handleSuggestionClick(s),
25986
+ children: s
25987
+ },
25988
+ s
25989
+ )) })
25990
+ ] }),
25991
+ /* @__PURE__ */ jsxs("div", { className: "overflow-visible rounded-lg bg-muted/50 text-foreground shadow-md focus-within:ring-2 focus-within:ring-sky-600", children: [
25992
+ /* @__PURE__ */ jsx(
25993
+ "textarea",
25994
+ {
25995
+ value: prompt,
25996
+ onChange: (e) => setPrompt(e.target.value),
25997
+ onKeyDown: handleKeyDown,
25998
+ placeholder: placeholder ?? t("placeholders.type_message"),
25999
+ className: "max-h-34 min-h-20 w-full resize-none bg-transparent py-4 pl-3 pr-4 text-sm outline-none placeholder:text-muted-foreground sm:text-base",
26000
+ rows: 2
26001
+ }
26002
+ ),
26003
+ /* @__PURE__ */ jsxs("div", { className: "flex h-10 items-center justify-between px-2", children: [
26004
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
26005
+ capabilities?.supportFiles && /* @__PURE__ */ jsx(
26006
+ "button",
26007
+ {
26008
+ type: "button",
26009
+ title: t("tools.file_upload"),
26010
+ className: "flex size-7 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground",
26011
+ children: /* @__PURE__ */ jsx(Plus, { className: "size-5" })
26012
+ }
26013
+ ),
26014
+ availableToggles.length > 0 && /* @__PURE__ */ jsxs("div", { ref: settingsRef, className: "relative", children: [
26015
+ /* @__PURE__ */ jsx(
26016
+ "button",
26017
+ {
26018
+ type: "button",
26019
+ title: t("common.settings") || "Settings",
26020
+ onClick: () => setSettingsOpen((prev) => !prev),
26021
+ className: "flex size-7 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground",
26022
+ children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-5" })
26023
+ }
26024
+ ),
26025
+ settingsOpen && /* @__PURE__ */ jsx("div", { className: "absolute bottom-full left-0 z-50 mb-2 min-w-[250px] rounded-lg border border-border bg-background p-3 shadow-lg", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: availableToggles.map((toggle) => {
26026
+ const Icon = toggle.icon;
26027
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
26028
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
26029
+ /* @__PURE__ */ jsx(Icon, { className: "size-4 text-muted-foreground" }),
26030
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t(toggle.labelKey) })
26031
+ ] }),
26032
+ /* @__PURE__ */ jsx(
26033
+ ToggleSwitch,
26034
+ {
26035
+ checked: features[toggle.key],
26036
+ onChange: () => toggleFeature(toggle.key),
26037
+ label: t(toggle.labelKey)
26038
+ }
26039
+ )
26040
+ ] }, toggle.key);
26041
+ }) }) })
26042
+ ] }),
26043
+ models.length > 1 && selectedModel && /* @__PURE__ */ jsxs("div", { ref: modelRef, className: "relative ml-1", children: [
26044
+ /* @__PURE__ */ jsxs(
26045
+ "button",
26046
+ {
26047
+ type: "button",
26048
+ onClick: () => setModelDropdownOpen((prev) => !prev),
26049
+ className: "flex items-center gap-1.5 rounded-full bg-muted px-2 py-1 text-xs text-foreground transition-colors hover:bg-muted/80",
26050
+ children: [
26051
+ selectedModel.providerLogoUrl && /* @__PURE__ */ jsx(
26052
+ "img",
26053
+ {
26054
+ src: selectedModel.providerLogoUrl,
26055
+ alt: "",
26056
+ className: "size-4 rounded-full object-cover"
26057
+ }
26058
+ ),
26059
+ /* @__PURE__ */ jsx("span", { className: "max-w-[8rem] truncate", children: selectedModel.name }),
26060
+ /* @__PURE__ */ jsx(ChevronDown, { className: "size-3 text-muted-foreground" })
26061
+ ]
26062
+ }
26063
+ ),
26064
+ modelDropdownOpen && /* @__PURE__ */ jsx("div", { className: "absolute bottom-full left-0 z-50 mb-2 min-w-[15rem] rounded-lg border border-border bg-background py-1 shadow-lg", children: models.map((m) => /* @__PURE__ */ jsxs(
26065
+ "button",
26066
+ {
26067
+ type: "button",
26068
+ onClick: () => {
26069
+ setSelectedModel(m);
26070
+ setModelDropdownOpen(false);
26071
+ },
26072
+ className: cn(
26073
+ "flex w-full items-center gap-2 px-3 py-2 text-left text-sm transition-colors hover:bg-muted",
26074
+ m.id === selectedModel.id && "bg-muted/60"
26075
+ ),
26076
+ children: [
26077
+ m.providerLogoUrl && /* @__PURE__ */ jsx(
26078
+ "img",
26079
+ {
26080
+ src: m.providerLogoUrl,
26081
+ alt: "",
26082
+ className: "size-4 rounded-full object-cover"
26083
+ }
26084
+ ),
26085
+ /* @__PURE__ */ jsx("span", { children: m.name })
26086
+ ]
26087
+ },
26088
+ m.id
26089
+ )) })
26090
+ ] }),
26091
+ reasoningLevels.length > 0 && /* @__PURE__ */ jsxs("div", { ref: reasoningRef, className: "relative ml-1", children: [
26092
+ /* @__PURE__ */ jsxs(
26093
+ "button",
26094
+ {
26095
+ type: "button",
26096
+ title: t("common.reasoning") || "Use reasoning model to solve complex tasks",
26097
+ onClick: () => setReasoningDropdownOpen((prev) => !prev),
26098
+ className: "flex items-center gap-1.5 rounded-full bg-indigo-100 px-2.5 py-1 text-xs font-medium text-indigo-700 transition-colors hover:bg-indigo-200 dark:bg-indigo-950 dark:text-indigo-300 dark:hover:bg-indigo-900",
26099
+ children: [
26100
+ /* @__PURE__ */ jsx(Brain, { className: "size-3.5" }),
26101
+ selectedReasoningLevel && /* @__PURE__ */ jsx("span", { children: selectedReasoningLevel.name })
26102
+ ]
26103
+ }
26104
+ ),
26105
+ reasoningDropdownOpen && /* @__PURE__ */ jsx("div", { className: "absolute bottom-full left-0 z-50 mb-2 min-w-[12rem] rounded-lg border border-border bg-background py-1 shadow-lg", children: reasoningLevels.map((level) => /* @__PURE__ */ jsx(
26106
+ "button",
26107
+ {
26108
+ type: "button",
26109
+ onClick: () => {
26110
+ setReasoningOverride(level);
26111
+ setReasoningDropdownOpen(false);
26112
+ },
26113
+ className: cn(
26114
+ "flex w-full items-center px-3 py-2 text-left text-sm transition-colors hover:bg-muted",
26115
+ selectedReasoningLevel?.id === level.id && "bg-indigo-50 dark:bg-indigo-950/50"
26116
+ ),
26117
+ children: /* @__PURE__ */ jsx("span", { children: level.name })
26118
+ },
26119
+ level.id
26120
+ )) })
26121
+ ] })
26122
+ ] }),
26123
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx(
26124
+ "button",
26125
+ {
26126
+ type: "button",
26127
+ className: "flex size-7 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground",
26128
+ children: /* @__PURE__ */ jsx(Mic, { className: "size-5" })
26129
+ }
26130
+ ) })
26131
+ ] })
26132
+ ] })
26133
+ ] });
26134
+ }
26135
+ function AgentTriggerWidget({
26136
+ agentIds,
26137
+ className,
26138
+ placeholder,
26139
+ onSubmit
26140
+ }) {
26141
+ const { t } = useAssistantTranslation();
26142
+ const {
26143
+ agents,
26144
+ isLoading,
26145
+ error,
26146
+ retry
26147
+ } = useAgentsData(agentIds);
26148
+ const [carouselIndex, setCarouselIndex] = useState(0);
26149
+ const containerRef = useRef(null);
26150
+ const currentAgent = agents[carouselIndex] ?? null;
26151
+ const navigateCarousel = useCallback(
26152
+ (direction) => {
26153
+ if (agents.length <= 1) return;
26154
+ setCarouselIndex(
26155
+ (prev) => (prev + direction + agents.length) % agents.length
26156
+ );
26157
+ },
26158
+ [agents.length]
26159
+ );
26160
+ const handlePromptSubmit = useCallback(
26161
+ (prompt, features, modelId) => {
26162
+ if (!currentAgent) return;
26163
+ onSubmit?.(currentAgent.id, prompt, features, modelId);
26164
+ },
26165
+ [currentAgent, onSubmit]
26166
+ );
26167
+ const welcomeText = useMemo(() => {
26168
+ if (!currentAgent?.welcomeMessage) return "";
26169
+ return currentAgent.welcomeMessage;
26170
+ }, [currentAgent?.welcomeMessage]);
26171
+ if (isLoading) {
26172
+ return /* @__PURE__ */ jsxs(
26173
+ "div",
26174
+ {
26175
+ className: cn(
26176
+ "flex flex-1 flex-col items-center justify-center gap-3",
26177
+ className
26178
+ ),
26179
+ children: [
26180
+ /* @__PURE__ */ jsx(Loader2, { className: "size-8 animate-spin text-muted-foreground" }),
26181
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("common.loading") || "Loading..." })
26182
+ ]
26183
+ }
26184
+ );
26185
+ }
26186
+ if (error) {
26187
+ return /* @__PURE__ */ jsxs(
26188
+ "div",
26189
+ {
26190
+ className: cn(
26191
+ "flex flex-1 flex-col items-center justify-center gap-3",
26192
+ className
26193
+ ),
26194
+ children: [
26195
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error.message }),
26196
+ /* @__PURE__ */ jsx(
26197
+ "button",
26198
+ {
26199
+ type: "button",
26200
+ onClick: retry,
26201
+ className: "rounded-md border border-border px-3 py-1.5 text-sm text-foreground transition-colors hover:bg-muted",
26202
+ children: t("common.retry") || "Retry"
26203
+ }
26204
+ )
26205
+ ]
26206
+ }
26207
+ );
26208
+ }
26209
+ if (agents.length === 0) {
26210
+ return /* @__PURE__ */ jsx(
26211
+ "div",
26212
+ {
26213
+ className: cn(
26214
+ "flex flex-1 flex-col items-center justify-center",
26215
+ className
26216
+ ),
26217
+ children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("messages.no_agents") || "No agents available" })
26218
+ }
26219
+ );
26220
+ }
26221
+ return /* @__PURE__ */ jsxs(
26222
+ "div",
26223
+ {
26224
+ ref: containerRef,
26225
+ className: cn(
26226
+ "relative mx-auto flex h-full w-full max-w-4xl flex-col focus:outline-none",
26227
+ className
26228
+ ),
26229
+ tabIndex: 0,
26230
+ children: [
26231
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center space-y-4 px-8 pt-6", children: [
26232
+ /* @__PURE__ */ jsx("h3", { className: "truncate font-mono text-xl font-semibold uppercase tracking-tight text-foreground", children: currentAgent?.name ?? "" }),
26233
+ /* @__PURE__ */ jsx(
26234
+ AgentCarousel,
26235
+ {
26236
+ agents,
26237
+ selectedIndex: carouselIndex,
26238
+ onSelect: setCarouselIndex,
26239
+ onNavigate: navigateCarousel
26240
+ }
26241
+ ),
26242
+ /* @__PURE__ */ jsx("div", { className: "mt-2 text-center", children: welcomeText ? /* @__PURE__ */ jsx("p", { className: "line-clamp-2 min-h-10 max-w-lg text-sm text-muted-foreground", children: welcomeText }) : /* @__PURE__ */ jsx("div", { className: "min-h-10" }) })
26243
+ ] }),
26244
+ /* @__PURE__ */ jsx("div", { className: "flex h-fit w-full grow items-end justify-center px-6 pb-6", children: /* @__PURE__ */ jsx(
26245
+ AgentTriggerPrompt,
26246
+ {
26247
+ capabilities: currentAgent?.capabilities ?? null,
26248
+ models: currentAgent?.models ?? [],
26249
+ suggestions: currentAgent?.standardSuggestions ?? [],
26250
+ placeholder,
26251
+ onSubmit: handlePromptSubmit
26252
+ }
26253
+ ) })
26254
+ ]
26255
+ }
26256
+ );
26257
+ }
25516
26258
 
25517
- export { AssistantI18nProvider, AssistantProvider, DocyAssistant, useAssistantConfig, useAssistantTranslation };
26259
+ export { AgentTriggerWidget, AssistantI18nProvider, AssistantProvider, DocyAssistant, useAssistantConfig, useAssistantTranslation };
25518
26260
  //# sourceMappingURL=index.js.map
25519
26261
  //# sourceMappingURL=index.js.map