From e7514c08cc95eb955bb41d1a27bea3fbdc77440c Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Tue, 2 Jun 2026 12:28:26 -0400 Subject: [PATCH] feat(models): expose refreshClaudeModels to bust cache and re-fetch from 9router --- .../chat/hooks/useChatProviderState.ts | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/components/chat/hooks/useChatProviderState.ts b/src/components/chat/hooks/useChatProviderState.ts index 3b4e633..ff87e2b 100644 --- a/src/components/chat/hooks/useChatProviderState.ts +++ b/src/components/chat/hooks/useChatProviderState.ts @@ -90,32 +90,37 @@ export function useChatProviderState({ selectedSession }: UseChatProviderStateAr load('gemini', setGeminiModelState, GEMINI_MODELS.DEFAULT); }, [selectedSession?.id]); - // Fetch live Claude model list and validate the current claude model - useEffect(() => { - authenticatedFetch('/api/models') - .then((res) => { - if (!res.ok) return; - return res.json(); - }) - .then((data) => { - if (!Array.isArray(data?.claude) || data.claude.length === 0) return; - const options: ModelOption[] = data.claude; - setClaudeModelOptions(options); + // Fetch and apply live Claude model list, validating the current selection. + const fetchAndSetClaudeModels = useCallback(async () => { + const res = await authenticatedFetch('/api/models'); + if (!res.ok) return; + const data = await res.json(); + if (!Array.isArray(data?.claude) || data.claude.length === 0) return; + const options: ModelOption[] = data.claude; + setClaudeModelOptions(options); + setClaudeModelState((current) => { + const valid = options.some((o) => o.value === current); + if (valid) return current; + const fallback = options[0]?.value ?? CLAUDE_MODELS.DEFAULT; + localStorage.setItem(globalModelKey('claude'), fallback); + if (selectedSession?.id) { + localStorage.setItem(sessionModelKey('claude', selectedSession.id), fallback); + } + return fallback; + }); + }, [selectedSession?.id]); - setClaudeModelState((current) => { - const valid = options.some((o) => o.value === current); - if (valid) return current; - const fallback = options[0]?.value ?? CLAUDE_MODELS.DEFAULT; - localStorage.setItem(globalModelKey('claude'), fallback); - if (selectedSession?.id) { - localStorage.setItem(sessionModelKey('claude', selectedSession.id), fallback); - } - return fallback; - }); - }) - .catch(() => { - // Static fallback already in place - }); + // Bust the server-side cache then re-fetch the model list. + const refreshClaudeModels = useCallback(async () => { + await authenticatedFetch('/api/models/refresh', { method: 'POST' }); + await fetchAndSetClaudeModels(); + }, [fetchAndSetClaudeModels]); + + // Fetch live Claude model list on mount + useEffect(() => { + fetchAndSetClaudeModels().catch(() => { + // Static fallback already in place + }); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -209,5 +214,6 @@ export function useChatProviderState({ selectedSession }: UseChatProviderStateAr pendingPermissionRequests, setPendingPermissionRequests, cyclePermissionMode, + refreshClaudeModels, }; }