From d20d1fa36fd65c8023fdbad97e6e0149e6744c74 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Wed, 2 Sep 2026 12:40:18 +0200 Subject: [PATCH] ui : extract the model params badge fallback into a hook Move the option's fallback logic into useModelParamsFallback and reuse it for the dropdown and sheet trigger badges. Assisted-by: pi:zai-org/GLM-5.3 --- .../app/models/ModelsSelectorDropdown.svelte | 15 ++++- .../app/models/ModelsSelectorOption.svelte | 58 ++-------------- .../app/models/ModelsSelectorSheet.svelte | 18 ++++- .../hooks/use-model-params-fallback.svelte.ts | 66 +++++++++++++++++++ 4 files changed, 101 insertions(+), 56 deletions(-) create mode 100644 tools/ui/src/lib/hooks/use-model-params-fallback.svelte.ts diff --git a/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte b/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte index 581e535b12..7b667e42bf 100644 --- a/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte @@ -14,6 +14,7 @@ import * as Tooltip from '$lib/components/ui/tooltip'; import { MODEL_SELECTOR_ICON, SETTINGS_KEYS } from '$lib/constants'; import { KeyboardKey, ServerModelStatus } from '$lib/enums'; + import { useModelParamsFallback } from '$lib/hooks/use-model-params-fallback.svelte'; import { useModelsSelector } from '$lib/hooks/use-models-selector.svelte'; import { useReasoningMenu } from '$lib/hooks/use-reasoning-menu.svelte'; import { modelsStore, settingsStore } from '$lib/stores'; @@ -65,6 +66,15 @@ const reasoning = useReasoningMenu(); + const selectedOption = $derived(ms.getDisplayOption()); + const triggerModel = $derived(selectedOption?.model ?? null); + + // Params badge fallback for trigger ids that carry no params token. + const { paramsFallback } = useModelParamsFallback({ + modelId: () => triggerModel, + metaParams: () => selectedOption?.meta?.n_params + }); + const showOrgNameInTrigger = $derived( settingsStore.config[SETTINGS_KEYS.SHOW_MODEL_ORG_NAME_IN_TRIGGER] ?? false ); @@ -179,8 +189,6 @@

No models available.

{/if} {:else} - {@const selectedOption = ms.getDisplayOption()} - {@const triggerModel = selectedOption?.model} {@const triggerStatus = triggerModel ? modelsStore.routerModels.find((m) => m.id === triggerModel)?.status?.value : undefined} @@ -223,6 +231,7 @@ hideOrgName={!showOrgNameInTrigger} hideQuantization modelId={selectedOption.model} + params={paramsFallback} /> {:else} Select model @@ -331,7 +340,6 @@ Sticks to the bottom of the content scrollport. -->
-
{/snippet} @@ -367,6 +375,7 @@ hideOrgName={!showOrgNameInTrigger} hideQuantization modelId={selectedOption.model} + params={paramsFallback} /> {/if} diff --git a/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte b/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte index 113278737e..5714312820 100644 --- a/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte @@ -12,22 +12,13 @@ RotateCw } from '@lucide/svelte'; import { ActionIcon, ModelId } from '$lib/components/app'; - import { - HF_BASE_MODEL_TAG_REGEX, - ICON_CLASS_DEFAULT, - MODEL_ID, - PATH_SEPARATOR - } from '$lib/constants'; + import { HF_BASE_MODEL_TAG_REGEX, ICON_CLASS_DEFAULT, PATH_SEPARATOR } from '$lib/constants'; import { ModelCapability, ServerModelStatus } from '$lib/enums'; import { HuggingFaceService, ModelsService } from '$lib/services'; + import { useModelParamsFallback } from '$lib/hooks/use-model-params-fallback.svelte'; import { modelsStore } from '$lib/stores'; import type { ModelOption } from '$lib/types/models'; - import { - formatParameters, - modelLoadFraction, - modelLoadProgressText, - normalizeModelName - } from '$lib/utils'; + import { modelLoadFraction, modelLoadProgressText } from '$lib/utils'; interface Props { option: ModelOption; @@ -109,47 +100,10 @@ tools: option.capabilities.includes(ModelCapability.TOOL_USE) })); - // Params badge fallback: the id usually carries the count (`Qwen3-8B`), but - // ids like `Kimi-K3` do not. Prefer the loaded model's meta `n_params`, then - // the HF GGUF total (`gguf.total`), fetched lazily like the models hub list - // does, only when neither the id nor the meta has it. - let parsedParams = $derived(parsedId.params); - let metaParams = $derived.by(() => { - const value = option.meta?.n_params; - - return typeof value === 'number' && value > 0 ? value : null; + const { paramsFallback } = useModelParamsFallback({ + modelId: () => option.model, + metaParams: () => option.meta?.n_params }); - // HF repo id: the `org/model` part without the `:revision/quant` suffix; - // local paths and bare names are not HF repos. - let hfRepoId = $derived.by(() => { - const [repo] = option.model.split(MODEL_ID.QUANTIZATION_SEPARATOR); - const normalized = normalizeModelName(repo ?? ''); - - return normalized.includes(MODEL_ID.ORG_SEPARATOR) ? normalized : null; - }); - let fetchedParams = $state(null); - - $effect(() => { - fetchedParams = null; - - if (parsedParams || metaParams || !hfRepoId) return; - - let cancelled = false; - - void HuggingFaceService.getDetails(hfRepoId).then((info) => { - if (!cancelled && info?.gguf?.total) fetchedParams = info.gguf.total; - }); - - return () => { - cancelled = true; - }; - }); - - let paramsFallback = $derived( - !parsedParams && (metaParams ?? fetchedParams) - ? formatParameters(metaParams ?? fetchedParams) - : undefined - );
useGlobalSelection }); + const selectedOption = $derived(ms.getDisplayOption()); + const triggerModel = $derived(selectedOption?.model ?? null); + + // Params badge fallback for trigger ids that carry no params token. + const { paramsFallback } = useModelParamsFallback({ + metaParams: () => selectedOption?.meta?.n_params, + modelId: () => triggerModel + }); + export function open() { ms.handleOpenChange(true); } @@ -106,6 +116,7 @@ hideQuantization hideTags modelId={selectedOption?.model || ''} + params={paramsFallback} /> {/if} @@ -190,7 +201,12 @@ > - + {#if ms.updating} diff --git a/tools/ui/src/lib/hooks/use-model-params-fallback.svelte.ts b/tools/ui/src/lib/hooks/use-model-params-fallback.svelte.ts new file mode 100644 index 0000000000..7d79fc9239 --- /dev/null +++ b/tools/ui/src/lib/hooks/use-model-params-fallback.svelte.ts @@ -0,0 +1,66 @@ +import { MODEL_ID } from '$lib/constants'; +import { HuggingFaceService, ModelsService } from '$lib/services'; +import { formatParameters, normalizeModelName } from '$lib/utils'; + +export interface UseModelParamsFallbackOptions { + /** Model id to parse; null disables the fallback. */ + modelId: () => string | null | undefined; + /** Server-reported parameter count from the model meta, when available. */ + metaParams?: () => unknown; +} + +/** + * Params badge fallback for model ids that carry no params token (`Kimi-K3`). + * Prefers the meta `n_params`, then the HF GGUF total (`gguf.total`) fetched + * lazily like the models hub list does, only when neither the id nor the meta + * has it. Returns the formatted badge text, or undefined when unavailable. + */ +export function useModelParamsFallback(opts: UseModelParamsFallbackOptions) { + const parsedParams = $derived.by(() => { + const id = opts.modelId(); + + return id ? ModelsService.parseModelId(id).params : null; + }); + const metaParams = $derived.by(() => { + const value = opts.metaParams?.(); + + return typeof value === 'number' && value > 0 ? value : null; + }); + // HF repo id: the `org/model` part without the `:revision/quant` suffix; + // local paths and bare names are not HF repos. + const hfRepoId = $derived.by(() => { + const id = opts.modelId(); + + if (!id) return null; + + const [repo] = id.split(MODEL_ID.QUANTIZATION_SEPARATOR); + const normalized = normalizeModelName(repo ?? ''); + + return normalized.includes(MODEL_ID.ORG_SEPARATOR) ? normalized : null; + }); + let fetchedParams = $state(null); + + $effect(() => { + fetchedParams = null; + + if (parsedParams || metaParams || !hfRepoId) return; + + let cancelled = false; + + void HuggingFaceService.getDetails(hfRepoId).then((info) => { + if (!cancelled && info?.gguf?.total) fetchedParams = info.gguf.total; + }); + + return () => { + cancelled = true; + }; + }); + + const paramsFallback = $derived( + !parsedParams && (metaParams ?? fetchedParams) + ? formatParameters(metaParams ?? fetchedParams) + : undefined + ); + + return { paramsFallback }; +}