diff --git a/packages/app/src/components/agent-status-bar.tsx b/packages/app/src/components/agent-status-bar.tsx index cc2f22917..402e1ca40 100644 --- a/packages/app/src/components/agent-status-bar.tsx +++ b/packages/app/src/components/agent-status-bar.tsx @@ -88,6 +88,7 @@ type ControlledAgentStatusBarProps = { features?: AgentFeature[]; onSetFeature?: (featureId: string, value: unknown) => void; onDropdownClose?: () => void; + onModelSelectorOpen?: () => void; }; export interface DraftAgentStatusBarProps { @@ -110,6 +111,7 @@ export interface DraftAgentStatusBarProps { features?: AgentFeature[]; onSetFeature?: (featureId: string, value: unknown) => void; onDropdownClose?: () => void; + onModelSelectorOpen?: () => void; disabled?: boolean; } @@ -217,6 +219,7 @@ function ControlledStatusBar({ features, onSetFeature, onDropdownClose, + onModelSelectorOpen, }: ControlledAgentStatusBarProps) { const { theme } = useUnistyles(); const isWeb = Platform.OS === "web"; @@ -411,6 +414,7 @@ function ControlledStatusBar({ onToggleFavorite={onToggleFavoriteModel} isLoading={isModelLoading} disabled={modelDisabled} + onOpen={onModelSelectorOpen} onClose={onDropdownClose} /> @@ -662,6 +666,7 @@ function ControlledStatusBar({ onToggleFavorite={onToggleFavoriteModel} isLoading={isModelLoading} disabled={modelDisabled} + onOpen={onModelSelectorOpen} onClose={onDropdownClose} renderTrigger={({ selectedModelLabel }) => ( { @@ -1035,6 +1041,7 @@ export function AgentStatusBar({ agentId, serverId, onDropdownClose }: AgentStat }); }} isModelLoading={snapshotIsLoading || snapshotIsFetching} + onModelSelectorOpen={invalidateSnapshot} onDropdownClose={onDropdownClose} disabled={!client} /> @@ -1061,6 +1068,7 @@ export function DraftAgentStatusBar({ features, onSetFeature, onDropdownClose, + onModelSelectorOpen, disabled = false, }: DraftAgentStatusBarProps) { const isWeb = Platform.OS === "web"; @@ -1105,6 +1113,7 @@ export function DraftAgentStatusBar({ }} isLoading={isAllModelsLoading} disabled={disabled} + onOpen={onModelSelectorOpen} onClose={onDropdownClose} /> diff --git a/packages/app/src/components/combined-model-selector.tsx b/packages/app/src/components/combined-model-selector.tsx index 745e0369a..c3dbdea3c 100644 --- a/packages/app/src/components/combined-model-selector.tsx +++ b/packages/app/src/components/combined-model-selector.tsx @@ -59,6 +59,7 @@ interface CombinedModelSelectorProps { disabled: boolean; isOpen: boolean; }) => React.ReactNode; + onOpen?: () => void; onClose?: () => void; disabled?: boolean; } @@ -517,6 +518,7 @@ export function CombinedModelSelector({ favoriteKeys = new Set(), onToggleFavorite, renderTrigger, + onOpen, onClose, disabled = false, }: CombinedModelSelectorProps) { @@ -541,12 +543,14 @@ export function CombinedModelSelector({ (open: boolean) => { setIsOpen(open); setView(singleProviderView ?? { kind: "all" }); - if (!open) { + if (open) { + onOpen?.(); + } else { setSearchQuery(""); onClose?.(); } }, - [onClose, singleProviderView], + [onOpen, onClose, singleProviderView], ); const handleSelect = useCallback( diff --git a/packages/app/src/hooks/use-agent-form-state.ts b/packages/app/src/hooks/use-agent-form-state.ts index fcf939101..e9fa25965 100644 --- a/packages/app/src/hooks/use-agent-form-state.ts +++ b/packages/app/src/hooks/use-agent-form-state.ts @@ -93,6 +93,7 @@ type UseAgentFormStateResult = { isModelLoading: boolean; modelError: string | null; refreshProviderModels: () => void; + invalidateProviderModels: () => void; setProviderAndModelFromUser: (provider: AgentProvider, modelId: string) => void; workingDirIsEmpty: boolean; persistFormPreferences: () => Promise; @@ -375,6 +376,7 @@ export function useAgentFormState(options: UseAgentFormStateOptions = {}): UseAg isFetching: snapshotIsFetching, error: snapshotError, refresh: refreshSnapshot, + invalidate: invalidateSnapshot, } = useProvidersSnapshot(formState.serverId); const allProviderEntries = useMemo(() => snapshotEntries ?? [], [snapshotEntries]); @@ -648,6 +650,10 @@ export function useAgentFormState(options: UseAgentFormStateOptions = {}): UseAg refreshSnapshot(); }, [refreshSnapshot]); + const invalidateProviderModels = useCallback(() => { + invalidateSnapshot(); + }, [invalidateSnapshot]); + const persistFormPreferences = useCallback(async () => { const resolvedModel = resolveEffectiveModel(availableModels, formState.model); const modelId = resolvedModel?.id ?? formState.model; @@ -714,6 +720,7 @@ export function useAgentFormState(options: UseAgentFormStateOptions = {}): UseAg isModelLoading, modelError, refreshProviderModels, + invalidateProviderModels, setProviderAndModelFromUser, workingDirIsEmpty, persistFormPreferences, @@ -745,6 +752,7 @@ export function useAgentFormState(options: UseAgentFormStateOptions = {}): UseAg isModelLoading, modelError, refreshProviderModels, + invalidateProviderModels, setProviderAndModelFromUser, workingDirIsEmpty, persistFormPreferences, diff --git a/packages/app/src/hooks/use-providers-snapshot.ts b/packages/app/src/hooks/use-providers-snapshot.ts index ffe23fa78..afee8096b 100644 --- a/packages/app/src/hooks/use-providers-snapshot.ts +++ b/packages/app/src/hooks/use-providers-snapshot.ts @@ -17,6 +17,7 @@ interface UseProvidersSnapshotResult { error: string | null; supportsSnapshot: boolean; refresh: () => void; + invalidate: () => void; } export function useProvidersSnapshot(serverId: string | null): UseProvidersSnapshotResult { @@ -66,6 +67,10 @@ export function useProvidersSnapshot(serverId: string | null): UseProvidersSnaps void client.refreshProvidersSnapshot(); }, [client]); + const invalidate = useCallback(() => { + void queryClient.invalidateQueries({ queryKey }); + }, [queryClient, queryKey]); + return { entries: snapshotQuery.data?.entries ?? undefined, isLoading: snapshotQuery.isLoading, @@ -73,6 +78,7 @@ export function useProvidersSnapshot(serverId: string | null): UseProvidersSnaps error: snapshotQuery.error instanceof Error ? snapshotQuery.error.message : null, supportsSnapshot, refresh, + invalidate, }; } diff --git a/packages/app/src/screens/agent/draft-agent-screen.tsx b/packages/app/src/screens/agent/draft-agent-screen.tsx index 534bf759b..696cd3705 100644 --- a/packages/app/src/screens/agent/draft-agent-screen.tsx +++ b/packages/app/src/screens/agent/draft-agent-screen.tsx @@ -226,6 +226,7 @@ function DraftAgentScreenContent({ isModelLoading, modelError, refreshProviderModels, + invalidateProviderModels, setProviderAndModelFromUser, persistFormPreferences, } = useAgentFormState({ @@ -1268,6 +1269,7 @@ function DraftAgentScreenContent({ onSelectThinkingOption: setThinkingOptionFromUser, features: draftFeatures, onSetFeature: setDraftFeatureValue, + onModelSelectorOpen: invalidateProviderModels, disabled: isSubmitting, }} /> diff --git a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx index c681c62eb..84a559cea 100644 --- a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx +++ b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx @@ -80,6 +80,7 @@ export function WorkspaceDraftAgentTab({ availableThinkingOptions, isModelLoading, setProviderAndModelFromUser, + invalidateProviderModels, persistFormPreferences, } = useAgentFormState({ initialServerId: serverId, @@ -373,6 +374,7 @@ export function WorkspaceDraftAgentTab({ features: draftFeatures, onSetFeature: handleSetFeatureWithFocus, onDropdownClose: () => focusInputRef.current?.(), + onModelSelectorOpen: invalidateProviderModels, disabled: isSubmitting, }} />