@docyrus/ui-pro-ai-assistant 0.2.4 → 0.2.6

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,87 @@ 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 [agents, setAgents] = useState([]);
2561
+ const [isLoading, setIsLoading] = useState(false);
2562
+ const [error, setError] = useState(null);
2563
+ const idsKey = agentIds.join(",");
2564
+ const fetchAgents = useCallback(async () => {
2565
+ const ids = idsKey.split(",").filter(Boolean);
2566
+ if (ids.length === 0) {
2567
+ setAgents([]);
2568
+ return;
2569
+ }
2570
+ setIsLoading(true);
2571
+ setError(null);
2572
+ try {
2573
+ const results = await Promise.allSettled(
2574
+ ids.map((id) => apiClient.get(`/ai/agent-deployments/base/${id}`))
2575
+ );
2576
+ const resolved = [];
2577
+ for (let i = 0; i < ids.length; i++) {
2578
+ const result = results[i];
2579
+ if (result.status === "fulfilled" && result.value.success && result.value.data) {
2580
+ resolved.push(
2581
+ toAgentTriggerData(ids[i], result.value.data)
2582
+ );
2583
+ }
2584
+ }
2585
+ setAgents(resolved);
2586
+ } catch (err) {
2587
+ setError(
2588
+ err instanceof Error ? err : new Error("Failed to fetch agents")
2589
+ );
2590
+ } finally {
2591
+ setIsLoading(false);
2592
+ }
2593
+ }, [apiClient, idsKey]);
2594
+ useEffect(() => {
2595
+ void fetchAgents();
2596
+ }, [fetchAgents]);
2597
+ return {
2598
+ agents,
2599
+ isLoading,
2600
+ error,
2601
+ retry: fetchAgents
2602
+ };
2603
+ }
2524
2604
  function useAssistantApi({
2525
2605
  tenantAiAgentId,
2526
2606
  deploymentId,
@@ -24567,6 +24647,7 @@ var DocyAssistant = ({
24567
24647
  agentSelectorUrl = "/ai/agent-deployments",
24568
24648
  baseAgentSelectorUrl = "/ai/agent-deployments/base",
24569
24649
  onAgentChange,
24650
+ initialPrompt,
24570
24651
  ...props
24571
24652
  }) => {
24572
24653
  const config3 = useAssistantConfig();
@@ -24602,6 +24683,7 @@ var DocyAssistant = ({
24602
24683
  const selectedSessionIdRef = useRef(null);
24603
24684
  const authTokenRef = useRef("");
24604
24685
  const messageOptionsRef = useRef(null);
24686
+ const initialPromptSentRef = useRef(false);
24605
24687
  useEffect(() => {
24606
24688
  selectedSessionIdRef.current = sessionState.selectedSessionId;
24607
24689
  }, [sessionState.selectedSessionId]);
@@ -24909,6 +24991,14 @@ var DocyAssistant = ({
24909
24991
  }
24910
24992
  });
24911
24993
  };
24994
+ useEffect(() => {
24995
+ if (!initialPrompt || initialPromptSentRef.current) return;
24996
+ initialPromptSentRef.current = true;
24997
+ setInput(initialPrompt);
24998
+ setTimeout(() => {
24999
+ handleSendMessage();
25000
+ }, 300);
25001
+ }, [initialPrompt]);
24912
25002
  const handleInputChange = useCallback((e) => {
24913
25003
  setInput(e.target.value);
24914
25004
  }, []);
@@ -25513,7 +25603,630 @@ var DocyAssistant = ({
25513
25603
  assistantDialogs
25514
25604
  ] });
25515
25605
  };
25606
+ function computeVisibleSlots(agents, index) {
25607
+ const len = agents.length;
25608
+ if (len === 0) return [];
25609
+ if (len === 1) return [
25610
+ null,
25611
+ null,
25612
+ agents[0],
25613
+ null,
25614
+ null
25615
+ ];
25616
+ if (len === 2) {
25617
+ const prev3 = index === 0 ? 1 : 0;
25618
+ return [
25619
+ null,
25620
+ agents[prev3],
25621
+ agents[index],
25622
+ agents[prev3],
25623
+ null
25624
+ ];
25625
+ }
25626
+ if (len === 3) {
25627
+ const prev3 = (index - 1 + len) % len;
25628
+ const next3 = (index + 1) % len;
25629
+ return [
25630
+ null,
25631
+ agents[prev3],
25632
+ agents[index],
25633
+ agents[next3],
25634
+ null
25635
+ ];
25636
+ }
25637
+ if (len === 4) {
25638
+ const prev22 = (index - 2 + len) % len;
25639
+ const prev3 = (index - 1 + len) % len;
25640
+ const next3 = (index + 1) % len;
25641
+ return [
25642
+ agents[prev22],
25643
+ agents[prev3],
25644
+ agents[index],
25645
+ agents[next3],
25646
+ agents[prev22]
25647
+ ];
25648
+ }
25649
+ const prev2 = (index - 2 + len) % len;
25650
+ const prev = (index - 1 + len) % len;
25651
+ const next = (index + 1) % len;
25652
+ const next2 = (index + 2) % len;
25653
+ return [
25654
+ agents[prev2],
25655
+ agents[prev],
25656
+ agents[index],
25657
+ agents[next],
25658
+ agents[next2]
25659
+ ];
25660
+ }
25661
+ var SLOT_OUTER_CLASS = {
25662
+ 0: "z-0 mx-2",
25663
+ 1: "z-5 mx-4",
25664
+ 2: "z-10 mx-6",
25665
+ 3: "z-5 mx-4",
25666
+ 4: "z-0 mx-2"
25667
+ };
25668
+ var SLOT_CIRCLE_CLASS = {
25669
+ 0: "size-12 bg-muted opacity-40",
25670
+ 1: "size-20 bg-muted opacity-70",
25671
+ 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",
25672
+ 3: "size-20 bg-muted opacity-70",
25673
+ 4: "size-12 bg-muted opacity-40"
25674
+ };
25675
+ var SLOT_IMG_CLASS = {
25676
+ 0: "size-10",
25677
+ 1: "size-16",
25678
+ 2: "size-24",
25679
+ 3: "size-16",
25680
+ 4: "size-10"
25681
+ };
25682
+ var SLOT_BOT_CLASS = {
25683
+ 0: "size-8 text-slate-400",
25684
+ 1: "size-12 text-slate-500",
25685
+ 2: "size-16 text-sky-600",
25686
+ 3: "size-12 text-slate-500",
25687
+ 4: "size-8 text-slate-400"
25688
+ };
25689
+ function isImageUrl(url) {
25690
+ if (!url) return false;
25691
+ return url.startsWith("http") || url.startsWith("/") || url.startsWith("data:");
25692
+ }
25693
+ function AgentCarousel({
25694
+ agents,
25695
+ selectedIndex,
25696
+ onSelect,
25697
+ onNavigate
25698
+ }) {
25699
+ const visibleSlots = computeVisibleSlots(agents, selectedIndex);
25700
+ const handleKeyDown = useCallback(
25701
+ (e) => {
25702
+ const target = e.target;
25703
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)
25704
+ return;
25705
+ if (e.key === "ArrowLeft") {
25706
+ e.preventDefault();
25707
+ onNavigate(-1);
25708
+ } else if (e.key === "ArrowRight") {
25709
+ e.preventDefault();
25710
+ onNavigate(1);
25711
+ }
25712
+ },
25713
+ [onNavigate]
25714
+ );
25715
+ if (agents.length === 0) return null;
25716
+ return /* @__PURE__ */ jsxs(
25717
+ "div",
25718
+ {
25719
+ className: "flex h-32 items-center justify-center gap-6",
25720
+ onKeyDown: handleKeyDown,
25721
+ tabIndex: 0,
25722
+ children: [
25723
+ /* @__PURE__ */ jsx(
25724
+ "button",
25725
+ {
25726
+ type: "button",
25727
+ 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",
25728
+ disabled: agents.length <= 1,
25729
+ onClick: () => onNavigate(-1),
25730
+ "aria-label": "Previous agent",
25731
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-6 text-muted-foreground" })
25732
+ }
25733
+ ),
25734
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: visibleSlots.map((slot, i) => slot ? /* @__PURE__ */ jsx(
25735
+ "div",
25736
+ {
25737
+ className: cn(
25738
+ "shrink-0 cursor-pointer transition-all duration-500 ease-out",
25739
+ SLOT_OUTER_CLASS[i]
25740
+ ),
25741
+ onClick: () => {
25742
+ const idx = agents.findIndex((a) => a.id === slot.id);
25743
+ if (idx !== -1) onSelect(idx);
25744
+ },
25745
+ children: /* @__PURE__ */ jsx(
25746
+ "div",
25747
+ {
25748
+ className: cn(
25749
+ "flex items-center justify-center rounded-full shadow-lg transition-all duration-500 ease-out",
25750
+ SLOT_CIRCLE_CLASS[i]
25751
+ ),
25752
+ children: slot.avatar && isImageUrl(slot.avatar) ? /* @__PURE__ */ jsx(
25753
+ "img",
25754
+ {
25755
+ src: slot.avatar,
25756
+ alt: slot.name,
25757
+ className: cn(
25758
+ "rounded-full object-cover transition-all duration-500 ease-out",
25759
+ SLOT_IMG_CLASS[i]
25760
+ )
25761
+ }
25762
+ ) : /* @__PURE__ */ jsx(Bot, { className: SLOT_BOT_CLASS[i] })
25763
+ }
25764
+ )
25765
+ },
25766
+ slot.id
25767
+ ) : /* @__PURE__ */ jsx("div", { className: "size-12 shrink-0" }, `empty-slot-${i === 0 ? "far-left" : i === 1 ? "left" : i === 3 ? "right" : "far-right"}`)) }),
25768
+ /* @__PURE__ */ jsx(
25769
+ "button",
25770
+ {
25771
+ type: "button",
25772
+ 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",
25773
+ disabled: agents.length <= 1,
25774
+ onClick: () => onNavigate(1),
25775
+ "aria-label": "Next agent",
25776
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-6 text-muted-foreground" })
25777
+ }
25778
+ )
25779
+ ]
25780
+ }
25781
+ );
25782
+ }
25783
+ var CAPABILITY_TOGGLES = [
25784
+ {
25785
+ key: "webSearch",
25786
+ capKey: "supportWebSearch",
25787
+ icon: Globe,
25788
+ labelKey: "tools.web_search"
25789
+ },
25790
+ {
25791
+ key: "thinking",
25792
+ capKey: "supportThinking",
25793
+ icon: Brain,
25794
+ labelKey: "tools.thinking"
25795
+ },
25796
+ {
25797
+ key: "deepResearch",
25798
+ capKey: "supportDeepResearch",
25799
+ icon: Lightbulb,
25800
+ labelKey: "tools.deep_research"
25801
+ },
25802
+ {
25803
+ key: "documentSearch",
25804
+ capKey: "supportDocumentSearch",
25805
+ icon: BookOpen,
25806
+ labelKey: "tools.document_search"
25807
+ },
25808
+ {
25809
+ key: "workCanvas",
25810
+ capKey: "supportWorkCanvas",
25811
+ icon: PenTool,
25812
+ labelKey: "tools.work_canvas"
25813
+ },
25814
+ {
25815
+ key: "files",
25816
+ capKey: "supportFiles",
25817
+ icon: FileUp,
25818
+ labelKey: "tools.file_upload"
25819
+ }
25820
+ ];
25821
+ function ToggleSwitch({
25822
+ checked,
25823
+ onChange,
25824
+ label
25825
+ }) {
25826
+ return /* @__PURE__ */ jsx(
25827
+ "button",
25828
+ {
25829
+ type: "button",
25830
+ role: "switch",
25831
+ "aria-checked": checked,
25832
+ "aria-label": label,
25833
+ onClick: onChange,
25834
+ className: cn(
25835
+ "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",
25836
+ checked ? "bg-sky-500" : "bg-gray-300 dark:bg-gray-600"
25837
+ ),
25838
+ children: /* @__PURE__ */ jsx(
25839
+ "span",
25840
+ {
25841
+ className: cn(
25842
+ "inline-block size-3 rounded-full bg-white transition-transform",
25843
+ checked ? "translate-x-5" : "translate-x-1"
25844
+ )
25845
+ }
25846
+ )
25847
+ }
25848
+ );
25849
+ }
25850
+ function useClickOutside(ref, open, onClose) {
25851
+ useEffect(() => {
25852
+ if (!open) return;
25853
+ const handler = (e) => {
25854
+ if (ref.current && !ref.current.contains(e.target)) {
25855
+ onClose();
25856
+ }
25857
+ };
25858
+ document.addEventListener("mousedown", handler);
25859
+ return () => document.removeEventListener("mousedown", handler);
25860
+ }, [ref, open, onClose]);
25861
+ }
25862
+ function AgentTriggerPrompt({
25863
+ capabilities,
25864
+ models,
25865
+ suggestions,
25866
+ placeholder,
25867
+ onSubmit
25868
+ }) {
25869
+ const { t } = useAssistantTranslation();
25870
+ const [prompt, setPrompt] = useState("");
25871
+ const [selectedModel, setSelectedModel] = useState(
25872
+ models[0]
25873
+ );
25874
+ const [features, setFeatures] = useState({
25875
+ webSearch: false,
25876
+ thinking: false,
25877
+ deepResearch: false,
25878
+ documentSearch: false,
25879
+ workCanvas: false,
25880
+ files: false
25881
+ });
25882
+ const [settingsOpen, setSettingsOpen] = useState(false);
25883
+ const [modelDropdownOpen, setModelDropdownOpen] = useState(false);
25884
+ const [reasoningDropdownOpen, setReasoningDropdownOpen] = useState(false);
25885
+ const [reasoningOverride, setReasoningOverride] = useState(null);
25886
+ const settingsRef = useRef(null);
25887
+ const modelRef = useRef(null);
25888
+ const reasoningRef = useRef(null);
25889
+ useClickOutside(settingsRef, settingsOpen, () => setSettingsOpen(false));
25890
+ useClickOutside(modelRef, modelDropdownOpen, () => setModelDropdownOpen(false));
25891
+ useClickOutside(reasoningRef, reasoningDropdownOpen, () => setReasoningDropdownOpen(false));
25892
+ const hasThinking = capabilities?.supportThinking || selectedModel?.supportThinking;
25893
+ const reasoningLevels = useMemo(
25894
+ () => hasThinking ? selectedModel?.reasoningLevels ?? [] : [],
25895
+ [hasThinking, selectedModel?.reasoningLevels]
25896
+ );
25897
+ const selectedReasoningLevel = useMemo(() => {
25898
+ if (reasoningLevels.length === 0) return null;
25899
+ if (reasoningOverride && reasoningLevels.some((l) => l.id === reasoningOverride.id)) {
25900
+ return reasoningOverride;
25901
+ }
25902
+ const defaultLevel = reasoningLevels.find((l) => l.default === true);
25903
+ return defaultLevel ?? reasoningLevels[0];
25904
+ }, [reasoningLevels, reasoningOverride]);
25905
+ const toggleFeature = useCallback((key) => {
25906
+ setFeatures((prev) => ({ ...prev, [key]: !prev[key] }));
25907
+ }, []);
25908
+ const handleSubmit = useCallback(() => {
25909
+ const trimmed = prompt.trim();
25910
+ if (!trimmed) return;
25911
+ onSubmit(trimmed, features, selectedModel?.id);
25912
+ setPrompt("");
25913
+ }, [
25914
+ prompt,
25915
+ features,
25916
+ selectedModel,
25917
+ onSubmit
25918
+ ]);
25919
+ const handleKeyDown = useCallback(
25920
+ (e) => {
25921
+ if (e.key === "Enter" && !e.shiftKey) {
25922
+ e.preventDefault();
25923
+ handleSubmit();
25924
+ }
25925
+ },
25926
+ [handleSubmit]
25927
+ );
25928
+ const handleSuggestionClick = useCallback(
25929
+ (suggestion) => {
25930
+ setPrompt(suggestion);
25931
+ },
25932
+ []
25933
+ );
25934
+ const availableToggles = capabilities ? CAPABILITY_TOGGLES.filter((toggle) => {
25935
+ if (!capabilities[toggle.capKey]) return false;
25936
+ if (toggle.key === "thinking" && reasoningLevels.length > 0) return false;
25937
+ return true;
25938
+ }) : [];
25939
+ return /* @__PURE__ */ jsxs("div", { className: "mt-4 mb-1 w-full max-w-[54rem]", children: [
25940
+ suggestions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
25941
+ /* @__PURE__ */ jsx(
25942
+ "button",
25943
+ {
25944
+ type: "button",
25945
+ title: t("common.generate_suggestions") || "Generate Suggestions",
25946
+ 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",
25947
+ children: /* @__PURE__ */ jsx(Plus, { className: "size-4" })
25948
+ }
25949
+ ),
25950
+ /* @__PURE__ */ jsx("div", { className: "suggestions-container flex items-center gap-2 overflow-x-auto", children: suggestions.map((s) => /* @__PURE__ */ jsx(
25951
+ "button",
25952
+ {
25953
+ type: "button",
25954
+ title: s,
25955
+ 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",
25956
+ onClick: () => handleSuggestionClick(s),
25957
+ children: s
25958
+ },
25959
+ s
25960
+ )) })
25961
+ ] }),
25962
+ /* @__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: [
25963
+ /* @__PURE__ */ jsx(
25964
+ "textarea",
25965
+ {
25966
+ value: prompt,
25967
+ onChange: (e) => setPrompt(e.target.value),
25968
+ onKeyDown: handleKeyDown,
25969
+ placeholder: placeholder ?? t("placeholders.type_message"),
25970
+ 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",
25971
+ rows: 2
25972
+ }
25973
+ ),
25974
+ /* @__PURE__ */ jsxs("div", { className: "flex h-10 items-center justify-between px-2", children: [
25975
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
25976
+ capabilities?.supportFiles && /* @__PURE__ */ jsx(
25977
+ "button",
25978
+ {
25979
+ type: "button",
25980
+ title: t("tools.file_upload"),
25981
+ className: "flex size-7 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground",
25982
+ children: /* @__PURE__ */ jsx(Plus, { className: "size-5" })
25983
+ }
25984
+ ),
25985
+ availableToggles.length > 0 && /* @__PURE__ */ jsxs("div", { ref: settingsRef, className: "relative", children: [
25986
+ /* @__PURE__ */ jsx(
25987
+ "button",
25988
+ {
25989
+ type: "button",
25990
+ title: t("common.settings") || "Settings",
25991
+ onClick: () => setSettingsOpen((prev) => !prev),
25992
+ className: "flex size-7 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground",
25993
+ children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "size-5" })
25994
+ }
25995
+ ),
25996
+ 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) => {
25997
+ const Icon = toggle.icon;
25998
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
25999
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
26000
+ /* @__PURE__ */ jsx(Icon, { className: "size-4 text-muted-foreground" }),
26001
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: t(toggle.labelKey) })
26002
+ ] }),
26003
+ /* @__PURE__ */ jsx(
26004
+ ToggleSwitch,
26005
+ {
26006
+ checked: features[toggle.key],
26007
+ onChange: () => toggleFeature(toggle.key),
26008
+ label: t(toggle.labelKey)
26009
+ }
26010
+ )
26011
+ ] }, toggle.key);
26012
+ }) }) })
26013
+ ] }),
26014
+ models.length > 1 && selectedModel && /* @__PURE__ */ jsxs("div", { ref: modelRef, className: "relative ml-1", children: [
26015
+ /* @__PURE__ */ jsxs(
26016
+ "button",
26017
+ {
26018
+ type: "button",
26019
+ onClick: () => setModelDropdownOpen((prev) => !prev),
26020
+ 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",
26021
+ children: [
26022
+ selectedModel.providerLogoUrl && /* @__PURE__ */ jsx(
26023
+ "img",
26024
+ {
26025
+ src: selectedModel.providerLogoUrl,
26026
+ alt: "",
26027
+ className: "size-4 rounded-full object-cover"
26028
+ }
26029
+ ),
26030
+ /* @__PURE__ */ jsx("span", { className: "max-w-[8rem] truncate", children: selectedModel.name }),
26031
+ /* @__PURE__ */ jsx(ChevronDown, { className: "size-3 text-muted-foreground" })
26032
+ ]
26033
+ }
26034
+ ),
26035
+ 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(
26036
+ "button",
26037
+ {
26038
+ type: "button",
26039
+ onClick: () => {
26040
+ setSelectedModel(m);
26041
+ setModelDropdownOpen(false);
26042
+ },
26043
+ className: cn(
26044
+ "flex w-full items-center gap-2 px-3 py-2 text-left text-sm transition-colors hover:bg-muted",
26045
+ m.id === selectedModel.id && "bg-muted/60"
26046
+ ),
26047
+ children: [
26048
+ m.providerLogoUrl && /* @__PURE__ */ jsx(
26049
+ "img",
26050
+ {
26051
+ src: m.providerLogoUrl,
26052
+ alt: "",
26053
+ className: "size-4 rounded-full object-cover"
26054
+ }
26055
+ ),
26056
+ /* @__PURE__ */ jsx("span", { children: m.name })
26057
+ ]
26058
+ },
26059
+ m.id
26060
+ )) })
26061
+ ] }),
26062
+ reasoningLevels.length > 0 && /* @__PURE__ */ jsxs("div", { ref: reasoningRef, className: "relative ml-1", children: [
26063
+ /* @__PURE__ */ jsxs(
26064
+ "button",
26065
+ {
26066
+ type: "button",
26067
+ title: t("common.reasoning") || "Use reasoning model to solve complex tasks",
26068
+ onClick: () => setReasoningDropdownOpen((prev) => !prev),
26069
+ 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",
26070
+ children: [
26071
+ /* @__PURE__ */ jsx(Brain, { className: "size-3.5" }),
26072
+ selectedReasoningLevel && /* @__PURE__ */ jsx("span", { children: selectedReasoningLevel.name })
26073
+ ]
26074
+ }
26075
+ ),
26076
+ 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(
26077
+ "button",
26078
+ {
26079
+ type: "button",
26080
+ onClick: () => {
26081
+ setReasoningOverride(level);
26082
+ setReasoningDropdownOpen(false);
26083
+ },
26084
+ className: cn(
26085
+ "flex w-full items-center px-3 py-2 text-left text-sm transition-colors hover:bg-muted",
26086
+ selectedReasoningLevel?.id === level.id && "bg-indigo-50 dark:bg-indigo-950/50"
26087
+ ),
26088
+ children: /* @__PURE__ */ jsx("span", { children: level.name })
26089
+ },
26090
+ level.id
26091
+ )) })
26092
+ ] })
26093
+ ] }),
26094
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx(
26095
+ "button",
26096
+ {
26097
+ type: "button",
26098
+ className: "flex size-7 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground",
26099
+ children: /* @__PURE__ */ jsx(Mic, { className: "size-5" })
26100
+ }
26101
+ ) })
26102
+ ] })
26103
+ ] })
26104
+ ] });
26105
+ }
26106
+ function AgentTriggerWidget({
26107
+ agentIds,
26108
+ className,
26109
+ placeholder,
26110
+ onSubmit
26111
+ }) {
26112
+ const { t } = useAssistantTranslation();
26113
+ const {
26114
+ agents,
26115
+ isLoading,
26116
+ error,
26117
+ retry
26118
+ } = useAgentsData(agentIds);
26119
+ const [carouselIndex, setCarouselIndex] = useState(0);
26120
+ const containerRef = useRef(null);
26121
+ const currentAgent = agents[carouselIndex] ?? null;
26122
+ const navigateCarousel = useCallback(
26123
+ (direction) => {
26124
+ if (agents.length <= 1) return;
26125
+ setCarouselIndex(
26126
+ (prev) => (prev + direction + agents.length) % agents.length
26127
+ );
26128
+ },
26129
+ [agents.length]
26130
+ );
26131
+ const handlePromptSubmit = useCallback(
26132
+ (prompt, features, modelId) => {
26133
+ if (!currentAgent) return;
26134
+ onSubmit?.(currentAgent.id, prompt, features, modelId);
26135
+ },
26136
+ [currentAgent, onSubmit]
26137
+ );
26138
+ const welcomeText = useMemo(() => {
26139
+ if (!currentAgent?.welcomeMessage) return "";
26140
+ return currentAgent.welcomeMessage;
26141
+ }, [currentAgent?.welcomeMessage]);
26142
+ if (isLoading) {
26143
+ return /* @__PURE__ */ jsxs(
26144
+ "div",
26145
+ {
26146
+ className: cn(
26147
+ "flex flex-1 flex-col items-center justify-center gap-3",
26148
+ className
26149
+ ),
26150
+ children: [
26151
+ /* @__PURE__ */ jsx(Loader2, { className: "size-8 animate-spin text-muted-foreground" }),
26152
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("common.loading") || "Loading..." })
26153
+ ]
26154
+ }
26155
+ );
26156
+ }
26157
+ if (error) {
26158
+ return /* @__PURE__ */ jsxs(
26159
+ "div",
26160
+ {
26161
+ className: cn(
26162
+ "flex flex-1 flex-col items-center justify-center gap-3",
26163
+ className
26164
+ ),
26165
+ children: [
26166
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error.message }),
26167
+ /* @__PURE__ */ jsx(
26168
+ "button",
26169
+ {
26170
+ type: "button",
26171
+ onClick: retry,
26172
+ className: "rounded-md border border-border px-3 py-1.5 text-sm text-foreground transition-colors hover:bg-muted",
26173
+ children: t("common.retry") || "Retry"
26174
+ }
26175
+ )
26176
+ ]
26177
+ }
26178
+ );
26179
+ }
26180
+ if (agents.length === 0) {
26181
+ return /* @__PURE__ */ jsx(
26182
+ "div",
26183
+ {
26184
+ className: cn(
26185
+ "flex flex-1 flex-col items-center justify-center",
26186
+ className
26187
+ ),
26188
+ children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("messages.no_agents") || "No agents available" })
26189
+ }
26190
+ );
26191
+ }
26192
+ return /* @__PURE__ */ jsxs(
26193
+ "div",
26194
+ {
26195
+ ref: containerRef,
26196
+ className: cn(
26197
+ "relative mx-auto flex h-full w-full max-w-4xl flex-col focus:outline-none",
26198
+ className
26199
+ ),
26200
+ tabIndex: 0,
26201
+ children: [
26202
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center space-y-4 px-8 pt-6", children: [
26203
+ /* @__PURE__ */ jsx("h3", { className: "truncate font-mono text-xl font-semibold uppercase tracking-tight text-foreground", children: currentAgent?.name ?? "" }),
26204
+ /* @__PURE__ */ jsx(
26205
+ AgentCarousel,
26206
+ {
26207
+ agents,
26208
+ selectedIndex: carouselIndex,
26209
+ onSelect: setCarouselIndex,
26210
+ onNavigate: navigateCarousel
26211
+ }
26212
+ ),
26213
+ /* @__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" }) })
26214
+ ] }),
26215
+ /* @__PURE__ */ jsx("div", { className: "flex h-fit w-full grow items-end justify-center px-6 pb-6", children: /* @__PURE__ */ jsx(
26216
+ AgentTriggerPrompt,
26217
+ {
26218
+ capabilities: currentAgent?.capabilities ?? null,
26219
+ models: currentAgent?.models ?? [],
26220
+ suggestions: currentAgent?.standardSuggestions ?? [],
26221
+ placeholder,
26222
+ onSubmit: handlePromptSubmit
26223
+ }
26224
+ ) })
26225
+ ]
26226
+ }
26227
+ );
26228
+ }
25516
26229
 
25517
- export { AssistantI18nProvider, AssistantProvider, DocyAssistant, useAssistantConfig, useAssistantTranslation };
26230
+ export { AgentTriggerWidget, AssistantI18nProvider, AssistantProvider, DocyAssistant, useAssistantConfig, useAssistantTranslation };
25518
26231
  //# sourceMappingURL=index.js.map
25519
26232
  //# sourceMappingURL=index.js.map