diff --git a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistant.svelte b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistant.svelte index a1d02d6ece..14f6c5ca02 100644 --- a/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistant.svelte +++ b/tools/ui/src/lib/components/app/chat/ChatMessages/ChatMessage/ChatMessageAssistant/ChatMessageAssistant.svelte @@ -180,6 +180,9 @@ let displayedModel = $derived(message.model ?? null); + // model being switched to while it loads, so the selector bar tracks it + let pendingModel = $state(null); + let isCurrentlyLoading = $derived(isLoading()); let isStreaming = $derived(isChatStreaming()); let hasNoContent = $derived(!message?.content?.trim()); @@ -318,13 +321,19 @@ > {#if isRouter} { const status = modelsStore.getModelStatus(modelId); if (status !== ServerModelStatus.LOADED) { - await modelsStore.loadModel(modelId); + pendingModel = modelId; + + try { + await modelsStore.loadModel(modelId); + } finally { + pendingModel = null; + } } onRegenerate(modelName); diff --git a/tools/ui/src/lib/components/app/models/ModelLoadHighlight.svelte b/tools/ui/src/lib/components/app/models/ModelLoadHighlight.svelte new file mode 100644 index 0000000000..fa9a02108a --- /dev/null +++ b/tools/ui/src/lib/components/app/models/ModelLoadHighlight.svelte @@ -0,0 +1,11 @@ + + + +
+
+
diff --git a/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte b/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte index 40006a4c93..720963a8db 100644 --- a/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsSelectorDropdown.svelte @@ -2,8 +2,10 @@ import { ChevronDown, Loader2, Package } from '@lucide/svelte'; import * as DropdownMenu from '$lib/components/ui/dropdown-menu'; import * as Tooltip from '$lib/components/ui/tooltip'; - import { KeyboardKey } from '$lib/enums'; + import { KeyboardKey, ServerModelStatus } from '$lib/enums'; import { useModelsSelector } from '$lib/hooks/use-models-selector.svelte'; + import { modelsStore, routerModels } from '$lib/stores/models.svelte'; + import { modelLoadFraction } from '$lib/utils'; import { DialogModelInformation, DropdownMenuSearchable, @@ -11,6 +13,7 @@ ModelsSelectorList, ModelsSelectorOption } from '$lib/components/app'; + import ModelLoadHighlight from './ModelLoadHighlight.svelte'; import type { ModelItem } from './utils'; interface Props { @@ -113,6 +116,17 @@ {/if} {:else} {@const selectedOption = ms.getDisplayOption()} + {@const triggerModel = selectedOption?.model} + {@const triggerStatus = triggerModel + ? routerModels().find((m) => m.id === triggerModel)?.status?.value + : undefined} + {@const triggerLoading = + !!triggerModel && + (triggerStatus === ServerModelStatus.LOADING || + modelsStore.isModelOperationInProgress(triggerModel))} + {@const triggerLoadPercent = triggerLoading + ? Math.round(modelLoadFraction(modelsStore.getLoadProgress(triggerModel)) * 100) + : 0} {#if ms.isRouter} @@ -123,7 +137,7 @@ {/if} + + {#if triggerLoading} + + {/if} {/snippet} diff --git a/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte b/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte index f2a024d31d..981111e201 100644 --- a/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsSelectorOption.svelte @@ -10,6 +10,7 @@ RotateCw } from '@lucide/svelte'; import { ActionIcon, ModelId } from '$lib/components/app'; + import ModelLoadHighlight from './ModelLoadHighlight.svelte'; import type { ModelOption } from '$lib/types/models'; import { ServerModelStatus } from '$lib/enums'; import { modelsStore, routerModels } from '$lib/stores/models.svelte'; @@ -119,11 +120,11 @@ {#if isLoading} -
+
{:else if isFailed} -
+
@@ -140,7 +141,7 @@
{:else if isSleeping} -
+
@@ -159,7 +160,7 @@
{:else if isLoaded} -
+
@@ -176,7 +177,7 @@
{:else} -
+
@@ -196,13 +197,6 @@
{#if isLoading} -
-
-
+ {/if}
diff --git a/tools/ui/src/lib/components/app/models/ModelsSelectorSheet.svelte b/tools/ui/src/lib/components/app/models/ModelsSelectorSheet.svelte index e5920a2a0f..a9e9ea1c8d 100644 --- a/tools/ui/src/lib/components/app/models/ModelsSelectorSheet.svelte +++ b/tools/ui/src/lib/components/app/models/ModelsSelectorSheet.svelte @@ -8,6 +8,10 @@ ModelsSelectorList, SearchInput } from '$lib/components/app'; + import ModelLoadHighlight from './ModelLoadHighlight.svelte'; + import { ServerModelStatus } from '$lib/enums'; + import { modelsStore, routerModels } from '$lib/stores/models.svelte'; + import { modelLoadFraction } from '$lib/utils'; interface Props { class?: string; @@ -61,12 +65,23 @@

No models available.

{:else} {@const selectedOption = ms.getDisplayOption()} + {@const triggerModel = selectedOption?.model} + {@const triggerStatus = triggerModel + ? routerModels().find((m) => m.id === triggerModel)?.status?.value + : undefined} + {@const triggerLoading = + !!triggerModel && + (triggerStatus === ServerModelStatus.LOADING || + modelsStore.isModelOperationInProgress(triggerModel))} + {@const triggerLoadPercent = triggerLoading + ? Math.round(modelLoadFraction(modelsStore.getLoadProgress(triggerModel)) * 100) + : 0} {#if ms.isRouter}