From f1516d92281c27ba5971c8da4a2356e5f084b0db Mon Sep 17 00:00:00 2001 From: that-lucas <138673432+that-lucas@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:21:26 +0100 Subject: [PATCH] fix: auto-refresh model list when switching post-processing providers (#854) * fix: auto-refresh model list when switching post-processing providers Clear cached model options and auto-fetch available models when the user switches providers or changes the Custom provider's base URL. Prevents stale model values from silently causing 404s at runtime. * fix: address PR review feedback - Fix race condition in updatePostProcessBaseUrl: persist base_url before clearing models so a failed write doesn't wipe the model - Fix indentation in handleProviderSelect callback body - Add guard before auto-fetching models: skip when provider has no API key or Custom has no base_url to avoid unnecessary errors * fix: check result status before clearing models, run Prettier - Check changePostProcessBaseUrlSetting and changePostProcessModelSetting result status before proceeding; bail on error to avoid partial state - Clear cached model options only after both backend writes succeed - Run Prettier to fix line-length violations (dependency array, destructuring) --- .../usePostProcessProviderState.ts | 26 ++++++++- src/stores/settingsStore.ts | 55 ++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/components/settings/PostProcessingSettingsApi/usePostProcessProviderState.ts b/src/components/settings/PostProcessingSettingsApi/usePostProcessProviderState.ts index ab6c33c..676fba0 100644 --- a/src/components/settings/PostProcessingSettingsApi/usePostProcessProviderState.ts +++ b/src/components/settings/PostProcessingSettingsApi/usePostProcessProviderState.ts @@ -89,9 +89,31 @@ export const usePostProcessProviderState = (): PostProcessProviderState => { } } - void setPostProcessProvider(providerId); + await setPostProcessProvider(providerId); + + // Auto-fetch available models for the new provider so the model dropdown + // reflects what's actually valid. Without this, a stale model value from + // a previous provider/base_url can persist and silently 404 at runtime. + // Skip when the provider isn't configured yet (no API key / empty base URL) + // to avoid unnecessary backend errors. + if (providerId !== APPLE_PROVIDER_ID) { + const provider = providers.find((p) => p.id === providerId); + const apiKey = settings?.post_process_api_keys?.[providerId] ?? ""; + const hasBaseUrl = (provider?.base_url ?? "").trim() !== ""; + const hasApiKey = apiKey.trim() !== ""; + + if (provider?.id === "custom" ? hasBaseUrl : hasApiKey) { + void fetchPostProcessModels(providerId); + } + } }, - [selectedProviderId, setPostProcessProvider], + [ + selectedProviderId, + setPostProcessProvider, + fetchPostProcessModels, + providers, + settings, + ], ); const handleBaseUrlChange = useCallback( diff --git a/src/stores/settingsStore.ts b/src/stores/settingsStore.ts index 462dbf9..3de95f9 100644 --- a/src/stores/settingsStore.ts +++ b/src/stores/settingsStore.ts @@ -374,7 +374,12 @@ export const useSettingsStore = create()( }, setPostProcessProvider: async (providerId) => { - const { settings, setUpdating, refreshSettings } = get(); + const { + settings, + setUpdating, + refreshSettings, + setPostProcessModelOptions, + } = get(); const updateKey = "post_process_provider_id"; const previousId = settings?.post_process_provider_id ?? null; @@ -388,6 +393,10 @@ export const useSettingsStore = create()( })); } + // Clear cached model options for the new provider so the dropdown + // doesn't show stale models from a previous fetch or base_url. + setPostProcessModelOptions(providerId, []); + try { await commands.setPostProcessProvider(providerId); await refreshSettings(); @@ -436,7 +445,49 @@ export const useSettingsStore = create()( }, updatePostProcessBaseUrl: async (providerId, baseUrl) => { - return get().updatePostProcessSetting("base_url", providerId, baseUrl); + const { setUpdating, refreshSettings } = get(); + const updateKey = `post_process_base_url:${providerId}`; + + setUpdating(updateKey, true); + + try { + // Persist the new base URL first. + const urlResult = await commands.changePostProcessBaseUrlSetting( + providerId, + baseUrl, + ); + if (urlResult.status === "error") { + console.error("Failed to persist base URL:", urlResult.error); + return; + } + + // Reset the stored model since the previous value is almost certainly + // invalid for the new endpoint (e.g. switching Custom from Groq to + // Cerebras). Only proceed if the reset succeeds. + const modelResult = await commands.changePostProcessModelSetting( + providerId, + "", + ); + if (modelResult.status === "error") { + console.error("Failed to reset model setting:", modelResult.error); + return; + } + + // Clear cached model options only after both backend writes succeed. + set((state) => ({ + postProcessModelOptions: { + ...state.postProcessModelOptions, + [providerId]: [], + }, + })); + + // Single refresh after both backend writes. + await refreshSettings(); + } catch (error) { + console.error("Failed to update post-process base URL:", error); + } finally { + setUpdating(updateKey, false); + } }, updatePostProcessApiKey: async (providerId, apiKey) => {