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) => {