diff --git a/apps/ui/src/store/app-store.ts b/apps/ui/src/store/app-store.ts index ca415ed6..85d7b782 100644 --- a/apps/ui/src/store/app-store.ts +++ b/apps/ui/src/store/app-store.ts @@ -689,6 +689,7 @@ export interface AppState { codexModelsLoading: boolean; codexModelsError: string | null; codexModelsLastFetched: number | null; + codexModelsLastFailedAt: number | null; // Pipeline Configuration (per-project, keyed by project path) pipelineConfigByProject: Record; @@ -1286,6 +1287,7 @@ const initialState: AppState = { codexModelsLoading: false, codexModelsError: null, codexModelsLastFetched: null, + codexModelsLastFailedAt: null, pipelineConfigByProject: {}, worktreePanelVisibleByProject: {}, showInitScriptIndicatorByProject: {}, @@ -3113,11 +3115,21 @@ export const useAppStore = create()((set, get) => ({ // Codex Models actions fetchCodexModels: async (forceRefresh = false) => { - const { codexModelsLastFetched, codexModelsLoading } = get(); + const { codexModelsLastFetched, codexModelsLoading, codexModelsLastFailedAt } = get(); // Skip if already loading if (codexModelsLoading) return; + // Skip if recently failed (< 30 seconds ago) and not forcing refresh + const FAILURE_COOLDOWN = 30000; // 30 seconds + if ( + !forceRefresh && + codexModelsLastFailedAt && + Date.now() - codexModelsLastFailedAt < FAILURE_COOLDOWN + ) { + return; + } + // Skip if recently fetched (< 5 minutes ago) and not forcing refresh if (!forceRefresh && codexModelsLastFetched && Date.now() - codexModelsLastFetched < 300000) { return; @@ -3142,12 +3154,14 @@ export const useAppStore = create()((set, get) => ({ codexModelsLastFetched: Date.now(), codexModelsLoading: false, codexModelsError: null, + codexModelsLastFailedAt: null, // Clear failure on success }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; set({ codexModelsError: errorMessage, codexModelsLoading: false, + codexModelsLastFailedAt: Date.now(), // Record failure time for cooldown }); } },