diff --git a/tools/ui/src/lib/components/app/dialogs/DialogManageModels.svelte b/tools/ui/src/lib/components/app/dialogs/DialogManageModels.svelte index c9603f1231..13af001d9d 100644 --- a/tools/ui/src/lib/components/app/dialogs/DialogManageModels.svelte +++ b/tools/ui/src/lib/components/app/dialogs/DialogManageModels.svelte @@ -58,9 +58,11 @@ $effect(() => { if (!uiStore.discoverModelsOpen) return; - uiStore.discoverModelsOpen = false; - view = 'discover'; - handleOpenChange(true); + untrack(() => { + uiStore.discoverModelsOpen = false; + view = 'discover'; + handleOpenChange(true); + }); }); function handleOpenChange(value: boolean) { diff --git a/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManager.svelte b/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManager.svelte index 7e8f5714cb..cb4e4f09ba 100644 --- a/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManager.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManager.svelte @@ -8,12 +8,15 @@ loadOverrides, type ModalityKey, modelContextLength, + modelDraftsFor, type ModelOverride, type ModelQuantGroup, type ModelsTableGroup, + modelSupports, saveOverrides } from './utils'; import { LOCAL_BACKEND_ID } from '$lib/constants'; + import { ModelCapability } from '$lib/enums'; import { backendsStore, conversationsStore, modelsStore, uiStore } from '$lib/stores'; import type { ModelOption } from '$lib/types/models'; import { getBackend } from '$lib/utils/api-base'; @@ -35,6 +38,8 @@ let providerFilter = $state([]); let contextLimit = $state(0); let modalityFilter = $state([]); + let capabilityFilter = $state([]); + let draftFilter = $state(false); let selectedId = $state(null); let overrides = $state>(loadOverrides()); @@ -42,18 +47,28 @@ let isFavorite = $derived((option: ModelOption) => modelsStore.favoriteModelIds.has(option.model) ); - // the rail counts follow the active view and filter, so it always says how many - // models each provider contributes to what the table is showing - let visible = $derived.by(() => { + // every filter but the provider one, so a provider count does not fall to zero + // the moment that provider is the one being looked at + let matching = $derived.by(() => { const term = filter.trim().toLowerCase(); return allModels.filter((option) => { if (term && !`${option.name} ${option.model}`.toLowerCase().includes(term)) return false; - if (providerFilter.length > 0) { - const backendId = option.backendId ?? LOCAL_BACKEND_ID; + // every capability asked for has to be there: tools and reasoning are + // features a model either has or does not, unlike modalities + if ( + capabilityFilter.length > 0 && + !capabilityFilter.every((capability) => modelSupports(option, capability)) + ) { + return false; + } - if (!providerFilter.includes(backendId)) return false; + if ( + draftFilter && + modelDraftsFor(option, overrides[option.id]?.load?.speculativeDecoding).length === 0 + ) { + return false; } // a model whose modalities are unknown cannot be shown to match @@ -64,6 +79,24 @@ return contextLimit === 0 || modelContextLength(option) >= contextLimit; }); }); + let visible = $derived.by(() => + providerFilter.length === 0 + ? matching + : matching.filter((option) => providerFilter.includes(option.backendId ?? LOCAL_BACKEND_ID)) + ); + // the rail counts follow the active view and filter, so it always says how many + // repos each provider contributes to what the table is showing + let providerCounts = $derived.by(() => { + const counts: Record = {}; + + for (const entry of groupModelQuants(matching)) { + const backendId = entry.base.backendId ?? LOCAL_BACKEND_ID; + + counts[backendId] = (counts[backendId] ?? 0) + 1; + } + + return counts; + }); // recently used models lead their section, the rest keep the server's order const rank = new SvelteMap(); @@ -356,7 +389,9 @@
(selectedId = option.id)} onUseAsDraft={useAsDraft} {overrides} + {providerCounts} {selectedId} toolbarEnd={toolbarEndRegion} /> diff --git a/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManagerFilters.svelte b/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManagerFilters.svelte index 956acf20af..055de72200 100644 --- a/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManagerFilters.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsManager/ModelsManagerFilters.svelte @@ -1,29 +1,40 @@