1import { modelsStore } from '$lib/stores/models.svelte';
  2import { isRouterMode } from '$lib/stores/server.svelte';
  3import { toast } from 'svelte-sonner';
  4
  5interface UseModelChangeValidationOptions {
  6	/**
  7	 * Function to get required modalities for validation.
  8	 * For ChatForm: () => usedModalities() - all messages
  9	 * For ChatMessageAssistant: () => getModalitiesUpToMessage(messageId) - messages before
 10	 */
 11	getRequiredModalities: () => ModelModalities;
 12
 13	/**
 14	 * Optional callback to execute after successful validation.
 15	 * For ChatForm: undefined - just select model
 16	 * For ChatMessageAssistant: (modelName) => onRegenerate(modelName)
 17	 */
 18	onSuccess?: (modelName: string) => void;
 19
 20	/**
 21	 * Optional callback for rollback on validation failure.
 22	 * For ChatForm: (previousId) => selectModelById(previousId)
 23	 * For ChatMessageAssistant: undefined - no rollback needed
 24	 */
 25	onValidationFailure?: (previousModelId: string | null) => Promise<void>;
 26}
 27
 28export function useModelChangeValidation(options: UseModelChangeValidationOptions) {
 29	const { getRequiredModalities, onSuccess, onValidationFailure } = options;
 30
 31	let previousSelectedModelId: string | null = null;
 32	const isRouter = $derived(isRouterMode());
 33
 34	async function handleModelChange(modelId: string, modelName: string): Promise<boolean> {
 35		try {
 36			// Store previous selection for potential rollback
 37			if (onValidationFailure) {
 38				previousSelectedModelId = modelsStore.selectedModelId;
 39			}
 40
 41			// Load model if not already loaded (router mode only)
 42			let hasLoadedModel = false;
 43			const isModelLoadedBefore = modelsStore.isModelLoaded(modelName);
 44
 45			if (isRouter && !isModelLoadedBefore) {
 46				try {
 47					await modelsStore.loadModel(modelName);
 48					hasLoadedModel = true;
 49				} catch {
 50					toast.error(`Failed to load model "${modelName}"`);
 51					return false;
 52				}
 53			}
 54
 55			// Fetch model props to validate modalities
 56			const props = await modelsStore.fetchModelProps(modelName);
 57
 58			if (props?.modalities) {
 59				const requiredModalities = getRequiredModalities();
 60
 61				// Check if model supports required modalities
 62				const missingModalities: string[] = [];
 63				if (requiredModalities.vision && !props.modalities.vision) {
 64					missingModalities.push('vision');
 65				}
 66				if (requiredModalities.audio && !props.modalities.audio) {
 67					missingModalities.push('audio');
 68				}
 69
 70				if (missingModalities.length > 0) {
 71					toast.error(
 72						`Model "${modelName}" doesn't support required modalities: ${missingModalities.join(', ')}. Please select a different model.`
 73					);
 74
 75					// Unload the model if we just loaded it
 76					if (isRouter && hasLoadedModel) {
 77						try {
 78							await modelsStore.unloadModel(modelName);
 79						} catch (error) {
 80							console.error('Failed to unload incompatible model:', error);
 81						}
 82					}
 83
 84					// Execute rollback callback if provided
 85					if (onValidationFailure && previousSelectedModelId) {
 86						await onValidationFailure(previousSelectedModelId);
 87					}
 88
 89					return false;
 90				}
 91			}
 92
 93			// Select the model (validation passed)
 94			await modelsStore.selectModelById(modelId);
 95
 96			// Execute success callback if provided
 97			if (onSuccess) {
 98				onSuccess(modelName);
 99			}
100
101			return true;
102		} catch (error) {
103			console.error('Failed to change model:', error);
104			toast.error('Failed to validate model capabilities');
105
106			// Execute rollback callback on error if provided
107			if (onValidationFailure && previousSelectedModelId) {
108				await onValidationFailure(previousSelectedModelId);
109			}
110
111			return false;
112		}
113	}
114
115	return {
116		handleModelChange
117	};
118}