]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/blob
ccc35d98f87a3920d9cf6246bd6caecc37cea1eb
[pkg/ggml/sources/llama.cpp] /
1 <script lang="ts">
2 import { PencilRuler, ChevronDown, ChevronRight, Loader2, Info } from '@lucide/svelte';
3 import { Checkbox } from '$lib/components/ui/checkbox';
4 import * as Collapsible from '$lib/components/ui/collapsible';
5 import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
6 import * as Tooltip from '$lib/components/ui/tooltip';
7 import { toolsStore } from '$lib/stores/tools.svelte';
8 import { mcpStore } from '$lib/stores/mcp.svelte';
9 import { useToolsPanel } from '$lib/hooks/use-tools-panel.svelte';
10
11 const toolsPanel = useToolsPanel();
12 const hasMcpServersAvailable = $derived(mcpStore.getServersSorted().length > 0);
13 </script>
14
15 <DropdownMenu.Sub onOpenChange={(open) => open && toolsPanel.handleOpen()}>
16 <DropdownMenu.SubTrigger class="flex cursor-pointer items-center gap-2">
17 <PencilRuler class="h-4 w-4" />
18
19 <span>Tools</span>
20 </DropdownMenu.SubTrigger>
21
22 <DropdownMenu.SubContent class="w-72 p-0">
23 {#if toolsPanel.totalToolCount === 0}
24 {#if toolsStore.loading}
25 <div class="px-3 py-4 text-center text-sm text-muted-foreground">
26 <Loader2 class="mx-auto mb-1 h-4 w-4 animate-spin" />
27
28 Loading tools...
29 </div>
30 {:else if toolsStore.isToolsEndpointUnreachable}
31 <div class="grid gap-2.5 px-3 py-4 text-sm text-muted-foreground">
32 <span class="flex gap-2">
33 <Info class="mt-0.5 h-4 w-4 shrink-0" />
34
35 <span>
36 Run llama-server with <code>--tools</code> flag to enable
37
38 <strong>Built-in Tools</strong>.
39 </span>
40 </span>
41
42 <span class="flex gap-2">
43 <Info class="mt-0.5 h-4 w-4 shrink-0" />
44
45 <span>
46 {hasMcpServersAvailable ? 'Enable' : 'Add'} MCP Server(s) to access
47
48 <strong>MCP Tools</strong>.
49 </span>
50 </span>
51 </div>
52 {:else if toolsStore.error}
53 <div class="px-3 py-4 text-center text-sm text-muted-foreground">Failed to load tools</div>
54 {:else if toolsPanel.noToolsInfoMessage}
55 <div class="flex gap-2 px-3 py-4 text-sm text-muted-foreground">
56 <Info class="mt-0.5 h-4 w-4 shrink-0" />
57
58 <span>{toolsPanel.noToolsInfoMessage}</span>
59 </div>
60 {:else}
61 <div class="px-3 py-4 text-center text-sm text-muted-foreground">No tools available</div>
62 {/if}
63 {:else}
64 <div class="max-h-80 overflow-y-auto p-2 pr-1">
65 {#each toolsPanel.activeGroups as group (group.label)}
66 {@const isExpanded = toolsPanel.expandedGroups.has(group.label)}
67 {@const { checked, indeterminate } = toolsPanel.getGroupCheckedState(group)}
68 {@const favicon = toolsPanel.getFavicon(group)}
69
70 <Collapsible.Root
71 open={isExpanded}
72 onOpenChange={() => toolsPanel.toggleGroupExpanded(group.label)}
73 >
74 <div class="flex items-center gap-1">
75 <Collapsible.Trigger
76 class="flex min-w-0 flex-1 items-center gap-2 rounded px-2 py-1.5 text-sm hover:bg-muted/50"
77 >
78 {#if isExpanded}
79 <ChevronDown class="h-3.5 w-3.5 shrink-0" />
80 {:else}
81 <ChevronRight class="h-3.5 w-3.5 shrink-0" />
82 {/if}
83
84 <span class="inline-flex min-w-0 items-center gap-1.5 font-medium">
85 {#if favicon}
86 <img
87 src={favicon}
88 alt=""
89 class="h-4 w-4 shrink-0 rounded-sm"
90 onerror={(e) => {
91 (e.currentTarget as HTMLImageElement).style.display = 'none';
92 }}
93 />
94 {/if}
95
96 <span class="truncate">{group.label}</span>
97 </span>
98
99 <span class="ml-auto shrink-0 text-xs text-muted-foreground">
100 {toolsPanel.getEnabledToolCount(group)}/{group.tools.length}
101 </span>
102 </Collapsible.Trigger>
103
104 <Tooltip.Root>
105 <Tooltip.Trigger>
106 <Checkbox
107 {checked}
108 {indeterminate}
109 onCheckedChange={() => toolsStore.toggleGroup(group)}
110 class="mr-2 h-4 w-4 shrink-0"
111 />
112 </Tooltip.Trigger>
113
114 <Tooltip.Content side="right">
115 <p>
116 {checked ? 'Disable' : 'Enable'}
117 {group.tools.length} tool{group.tools.length !== 1 ? 's' : ''}
118 </p>
119 </Tooltip.Content>
120 </Tooltip.Root>
121 </div>
122
123 <Collapsible.Content>
124 <div class="ml-4 flex flex-col gap-0.5 border-l border-border/50 pl-2">
125 {#each group.tools as tool (tool.function.name)}
126 <button
127 type="button"
128 class="flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-sm transition-colors hover:bg-muted/50"
129 onclick={() => toolsStore.toggleTool(tool.function.name)}
130 >
131 <Checkbox
132 checked={toolsStore.isToolEnabled(tool.function.name)}
133 onCheckedChange={() => toolsStore.toggleTool(tool.function.name)}
134 class="h-4 w-4 shrink-0"
135 />
136
137 <span class="min-w-0 flex-1 truncate font-mono text-[12px]">
138 {tool.function.name}
139 </span>
140 </button>
141 {/each}
142 </div>
143 </Collapsible.Content>
144 </Collapsible.Root>
145 {/each}
146 </div>
147 {/if}
148 </DropdownMenu.SubContent>
149 </DropdownMenu.Sub>