webui: fix tool selector toggle/counter, key tools by stable identity (#24065)

* webui: fix tool selector toggle/counter, key tools by stable identity

Key the disabled set, counts and toggles by a stable per-tool key
instead of bare function name, deduped from one canonical list. Per-tool
checkboxes become presentational (single row handler, no nested button),
category checkboxes drop the tristate (n/total carries partial). One
getEnabledToolsForLLM keeps normalized MCP schemas and dedupes by name.

* ui: use SvelteSet and SvelteMap for local tool collections to satisfy svelte/prefer-svelte-reactivity
This commit is contained in:
Pascal
2026-06-04 13:09:49 +02:00
committed by GitHub
parent 4d742877b2
commit 4586479852
7 changed files with 203 additions and 240 deletions
@@ -12,9 +12,9 @@ export interface UseToolsPanelReturn {
readonly activeGroups: ToolGroup[];
readonly totalToolCount: number;
readonly noToolsInfoMessage: string | null;
getGroupCheckedState(group: ToolGroup): { checked: boolean; indeterminate: boolean };
isGroupChecked(group: ToolGroup): boolean;
getEnabledToolCount(group: ToolGroup): number;
getFavicon(group: { source: ToolSource; label: string }): string | null;
getFavicon(group: ToolGroup): string | null;
isGroupDisabled(group: ToolGroup): boolean;
toggleGroupExpanded(label: string): void;
/** Toggle all tools in a group by label (avoids stale group object references). */
@@ -54,27 +54,18 @@ export function useToolsPanel(): UseToolsPanelReturn {
return `To enable Built-In Tools you need to run llama-server with ${CLI_FLAGS.TOOLS} all or ${CLI_FLAGS.TOOLS} <name> flag. To see MCP Tools you need to add / enable MCP Server(s).`;
});
function getGroupCheckedState(group: ToolGroup): { checked: boolean; indeterminate: boolean } {
return {
checked: toolsStore.isGroupFullyEnabled(group),
indeterminate: toolsStore.isGroupPartiallyEnabled(group)
};
function isGroupChecked(group: ToolGroup): boolean {
return toolsStore.isGroupFullyEnabled(group);
}
function getEnabledToolCount(group: ToolGroup): number {
return group.tools.filter((tool) => toolsStore.isToolEnabled(tool.function.name)).length;
return group.tools.filter((tool) => toolsStore.isToolEnabled(tool.key)).length;
}
function getFavicon(group: { source: ToolSource; label: string }): string | null {
if (group.source !== ToolSource.MCP) return null;
function getFavicon(group: ToolGroup): string | null {
if (group.source !== ToolSource.MCP || !group.serverId) return null;
for (const server of mcpStore.getServersSorted()) {
if (mcpStore.getServerLabel(server) === group.label) {
return mcpStore.getServerFavicon(server.id);
}
}
return null;
return mcpStore.getServerFavicon(group.serverId);
}
function isGroupDisabled(group: ToolGroup): boolean {
@@ -121,7 +112,7 @@ export function useToolsPanel(): UseToolsPanelReturn {
get noToolsInfoMessage() {
return noToolsInfoMessage;
},
getGroupCheckedState,
isGroupChecked,
getEnabledToolCount,
getFavicon,
isGroupDisabled,