diff --git a/frontend/src/components/Chat/InputArea.tsx b/frontend/src/components/Chat/InputArea.tsx index 4b718ee8..1f77b171 100644 --- a/frontend/src/components/Chat/InputArea.tsx +++ b/frontend/src/components/Chat/InputArea.tsx @@ -23,6 +23,7 @@ export function InputArea() { const updateLastAssistant = useAppStore((s) => s.updateLastAssistant); const setStreamState = useAppStore((s) => s.setStreamState); const resetStream = useAppStore((s) => s.resetStream); + const modelLoading = useAppStore((s) => s.modelLoading); const { state: speechState, available: speechAvailable, startRecording, stopRecording } = useSpeech(); @@ -272,7 +273,7 @@ export function InputArea() { rows={1} className="flex-1 bg-transparent outline-none resize-none text-sm leading-relaxed" style={{ color: 'var(--color-text)', maxHeight: '200px' }} - disabled={streamState.isStreaming} + disabled={streamState.isStreaming || modelLoading} /> {streamState.isStreaming ? ( { + const handleSelect = async (modelId: string) => { + const previousModel = selectedModel; setSelectedModel(modelId); setCommandPaletteOpen(false); + + // Preload the model if switching to a different one + if (modelId !== previousModel) { + const { setModelLoading, addLogEntry } = useAppStore.getState(); + setModelLoading(true); + addLogEntry({ timestamp: Date.now(), level: 'info', category: 'model', message: `Switching to ${modelId}...` }); + try { + await preloadModel(modelId); + addLogEntry({ timestamp: Date.now(), level: 'info', category: 'model', message: `${modelId} loaded` }); + } catch (e: any) { + addLogEntry({ timestamp: Date.now(), level: 'error', category: 'model', message: `Failed to load ${modelId}: ${e.message}` }); + } finally { + setModelLoading(false); + } + } }; const refreshModels = async () => { diff --git a/frontend/src/components/Sidebar/Sidebar.tsx b/frontend/src/components/Sidebar/Sidebar.tsx index 77cfae8f..905911e8 100644 --- a/frontend/src/components/Sidebar/Sidebar.tsx +++ b/frontend/src/components/Sidebar/Sidebar.tsx @@ -14,6 +14,7 @@ import { Sun, Moon, Monitor, + Loader2, } from 'lucide-react'; import { ConversationList } from './ConversationList'; import { useAppStore } from '../../lib/store'; @@ -29,6 +30,7 @@ export function Sidebar() { const selectedModel = useAppStore((s) => s.selectedModel); const serverInfo = useAppStore((s) => s.serverInfo); const setCommandPaletteOpen = useAppStore((s) => s.setCommandPaletteOpen); + const modelLoading = useAppStore((s) => s.modelLoading); const settings = useAppStore((s) => s.settings); const updateSettings = useAppStore((s) => s.updateSettings); @@ -120,16 +122,29 @@ export function Sidebar() { onMouseEnter={(e) => (e.currentTarget.style.background = 'var(--color-bg-tertiary)')} onMouseLeave={(e) => (e.currentTarget.style.background = 'var(--color-bg-secondary)')} > - - - {selectedModel || serverInfo?.model || 'Select model'} - - - ⌘K - + {modelLoading ? ( + + ) : ( + + )} + + + {selectedModel || serverInfo?.model || 'Select model'} + + {modelLoading && ( + + Loading model... + + )} + + {!modelLoading && ( + + ⌘K + + )} {/* Search */}