Add persistent model selection with localStorage
## Features - **Sticky model selection**: Chosen model persists across browser sessions - **Automatic restoration**: Saved model is restored when loading models - **Validation**: Invalid saved models are automatically cleared - **Provider switching**: Model selection is reset when switching providers ## Implementation Details - Model ID saved to localStorage on selection - Model restored during loadModels() if still available - Saved selection cleared when: - Switching inference providers - Logging out - Model no longer exists in available models ## User Experience - Users no longer need to reselect their preferred model after refresh - Model selector maintains state across page reloads - Graceful handling when saved model becomes unavailable ## Technical Notes - Uses 'selected_model_id' localStorage key - Integrates with existing InferenceContext state management - Maintains backward compatibility with existing provider logic 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0266b4871e
commit
e8197fb2a5
1 changed files with 37 additions and 3 deletions
|
|
@ -42,12 +42,20 @@ export function InferenceContextProvider({ children }: InferenceProviderProps) {
|
||||||
const [provider, setProviderState] = useState<InferenceProvider | null>(null);
|
const [provider, setProviderState] = useState<InferenceProvider | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [selectedModelId, setSelectedModelId] = useState<string | undefined>(undefined);
|
const [selectedModelId, setSelectedModelId] = useState<string | undefined>(() => {
|
||||||
|
// Load saved model selection from localStorage
|
||||||
|
return localStorage.getItem('selected_model_id') || undefined;
|
||||||
|
});
|
||||||
const [_, setAuthStateVersion] = useState(0); // Force re-renders on auth changes
|
const [_, setAuthStateVersion] = useState(0); // Force re-renders on auth changes
|
||||||
|
|
||||||
const setProvider = useCallback((newProvider: InferenceProvider) => {
|
const setProvider = useCallback((newProvider: InferenceProvider) => {
|
||||||
setProviderState(newProvider);
|
setProviderState(newProvider);
|
||||||
setSelectedModelId(undefined);
|
setSelectedModelId(undefined);
|
||||||
|
|
||||||
|
// Clear saved model selection when switching providers
|
||||||
|
// (it will be restored during loadModels if still valid)
|
||||||
|
localStorage.removeItem('selected_model_id');
|
||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
setAuthStateVersion(prev => prev + 1); // Trigger re-render
|
setAuthStateVersion(prev => prev + 1); // Trigger re-render
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -58,6 +66,10 @@ export function InferenceContextProvider({ children }: InferenceProviderProps) {
|
||||||
}
|
}
|
||||||
setProviderState(null);
|
setProviderState(null);
|
||||||
setSelectedModelId(undefined);
|
setSelectedModelId(undefined);
|
||||||
|
|
||||||
|
// Clear saved model selection
|
||||||
|
localStorage.removeItem('selected_model_id');
|
||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
setAuthStateVersion(prev => prev + 1);
|
setAuthStateVersion(prev => prev + 1);
|
||||||
}, [provider]);
|
}, [provider]);
|
||||||
|
|
@ -115,6 +127,14 @@ export function InferenceContextProvider({ children }: InferenceProviderProps) {
|
||||||
try {
|
try {
|
||||||
provider.selectModel(modelId);
|
provider.selectModel(modelId);
|
||||||
setSelectedModelId(modelId);
|
setSelectedModelId(modelId);
|
||||||
|
|
||||||
|
// Persist model selection to localStorage
|
||||||
|
if (modelId) {
|
||||||
|
localStorage.setItem('selected_model_id', modelId);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem('selected_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
setError(null);
|
setError(null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMessage = err instanceof Error ? err.message : 'Failed to select model';
|
const errorMessage = err instanceof Error ? err.message : 'Failed to select model';
|
||||||
|
|
@ -133,8 +153,22 @@ export function InferenceContextProvider({ children }: InferenceProviderProps) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const models = await provider.loadModels();
|
const models = await provider.loadModels();
|
||||||
// Update selectedModelId to match what the provider selected as default
|
|
||||||
setSelectedModelId(provider.selectedModel?.id);
|
// Try to restore saved model selection
|
||||||
|
const savedModelId = localStorage.getItem('selected_model_id');
|
||||||
|
if (savedModelId && models.find(m => m.id === savedModelId)) {
|
||||||
|
// Saved model exists in the available models, select it
|
||||||
|
provider.selectModel(savedModelId);
|
||||||
|
setSelectedModelId(savedModelId);
|
||||||
|
} else {
|
||||||
|
// Use provider's default selection or clear invalid saved selection
|
||||||
|
if (savedModelId && !models.find(m => m.id === savedModelId)) {
|
||||||
|
// Remove invalid saved model
|
||||||
|
localStorage.removeItem('selected_model_id');
|
||||||
|
}
|
||||||
|
setSelectedModelId(provider.selectedModel?.id);
|
||||||
|
}
|
||||||
|
|
||||||
return models;
|
return models;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMessage = err instanceof Error ? err.message : 'Failed to load models';
|
const errorMessage = err instanceof Error ? err.message : 'Failed to load models';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue