diff --git a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte
index 679d1eef39..a59ef89636 100644
--- a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte
+++ b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActions.svelte
@@ -13,7 +13,8 @@
import { modelsStore, modelOptions, selectedModelId } from '$lib/stores/models.svelte';
import { isRouterMode } from '$lib/stores/server.svelte';
import { chatStore } from '$lib/stores/chat.svelte';
- import { activeMessages } from '$lib/stores/conversations.svelte';
+ import { activeMessages, usedModalities } from '$lib/stores/conversations.svelte';
+ import { useModelChangeValidation } from '$lib/hooks/use-model-change-validation.svelte';
import type { ChatUploadedFile } from '$lib/types/chat';
interface Props {
@@ -157,6 +158,15 @@
export function openModelSelector() {
selectorModelRef?.open();
}
+
+ const { handleModelChange } = useModelChangeValidation({
+ getRequiredModalities: () => usedModalities(),
+ onValidationFailure: async (previousModelId) => {
+ if (previousModelId) {
+ await modelsStore.selectModelById(previousModelId);
+ }
+ }
+ });
@@ -173,6 +183,7 @@
currentModel={conversationModel}
forceForegroundText={true}
useGlobalSelection={true}
+ onModelChange={handleModelChange}
/>
{#if isLoading}
diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte
index fbcb024c17..71b0f79813 100644
--- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte
+++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageAssistant.svelte
@@ -9,6 +9,7 @@
SelectorModel
} from '$lib/components/app';
import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';
+ import { useModelChangeValidation } from '$lib/hooks/use-model-change-validation.svelte';
import { isLoading } from '$lib/stores/chat.svelte';
import autoResizeTextarea from '$lib/utils/autoresize-textarea';
import { fade } from 'svelte/transition';
@@ -18,8 +19,8 @@
import { INPUT_CLASSES } from '$lib/constants/input-classes';
import Label from '$lib/components/ui/label/label.svelte';
import { config } from '$lib/stores/settings.svelte';
+ import { conversationsStore } from '$lib/stores/conversations.svelte';
import { isRouterMode } from '$lib/stores/server.svelte';
- import { modelsStore } from '$lib/stores/models.svelte';
import { copyToClipboard } from '$lib/utils/copy';
import type { ApiChatCompletionToolCall } from '$lib/types/api';
@@ -93,7 +94,6 @@
let currentConfig = $derived(config());
let isRouter = $derived(isRouterMode());
let displayedModel = $derived((): string | null => {
- // Only show model from streaming data, no fallbacks to server props
if (message.model) {
return message.model;
}
@@ -101,16 +101,10 @@
return null;
});
- async function handleModelChange(modelId: string, modelName: string) {
- try {
- await modelsStore.selectModelById(modelId);
-
- // Pass the selected model name for regeneration
- onRegenerate(modelName);
- } catch (error) {
- console.error('Failed to change model:', error);
- }
- }
+ const { handleModelChange } = useModelChangeValidation({
+ getRequiredModalities: () => conversationsStore.getModalitiesUpToMessage(message.id),
+ onSuccess: (modelName) => onRegenerate(modelName)
+ });
function handleCopyModel() {
const model = displayedModel();
@@ -258,6 +252,7 @@
currentModel={displayedModel()}
onModelChange={handleModelChange}
disabled={isLoading()}
+ upToMessageId={message.id}
/>
{:else}
diff --git a/tools/server/webui/src/lib/components/app/misc/SelectorModel.svelte b/tools/server/webui/src/lib/components/app/misc/SelectorModel.svelte
index e1a850ba71..1b1326fefb 100644
--- a/tools/server/webui/src/lib/components/app/misc/SelectorModel.svelte
+++ b/tools/server/webui/src/lib/components/app/misc/SelectorModel.svelte
@@ -1,6 +1,7 @@