feat: live model list in provider state, validate saved model, expose model options
This commit is contained in:
parent
3e9c9a6672
commit
5a73ec83fc
1 changed files with 38 additions and 0 deletions
|
|
@ -4,6 +4,8 @@ import { CLAUDE_MODELS, CODEX_MODELS, CURSOR_MODELS, GEMINI_MODELS } from '../..
|
||||||
import type { PendingPermissionRequest, PermissionMode } from '../types/types';
|
import type { PendingPermissionRequest, PermissionMode } from '../types/types';
|
||||||
import type { ProjectSession, LLMProvider } from '../../../types/app';
|
import type { ProjectSession, LLMProvider } from '../../../types/app';
|
||||||
|
|
||||||
|
type ModelOption = { value: string; label: string };
|
||||||
|
|
||||||
const getPermissionModesForProvider = (provider: LLMProvider): PermissionMode[] => {
|
const getPermissionModesForProvider = (provider: LLMProvider): PermissionMode[] => {
|
||||||
if (provider === 'codex') {
|
if (provider === 'codex') {
|
||||||
return ['default', 'acceptEdits', 'bypassPermissions'];
|
return ['default', 'acceptEdits', 'bypassPermissions'];
|
||||||
|
|
@ -37,6 +39,38 @@ export function useChatProviderState({ selectedSession }: UseChatProviderStateAr
|
||||||
return localStorage.getItem('gemini-model') || GEMINI_MODELS.DEFAULT;
|
return localStorage.getItem('gemini-model') || GEMINI_MODELS.DEFAULT;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Live model lists — fall back to static constants until API responds
|
||||||
|
const [claudeModelOptions, setClaudeModelOptions] = useState<ModelOption[]>(CLAUDE_MODELS.OPTIONS);
|
||||||
|
const [codexModelOptions] = useState<ModelOption[]>(CODEX_MODELS.OPTIONS);
|
||||||
|
const [geminiModelOptions] = useState<ModelOption[]>(GEMINI_MODELS.OPTIONS);
|
||||||
|
const [cursorModelOptions] = useState<ModelOption[]>(CURSOR_MODELS.OPTIONS);
|
||||||
|
|
||||||
|
// Fetch live model list and validate the saved 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);
|
||||||
|
|
||||||
|
// Validate saved model — if it's no longer in the list, reset to default
|
||||||
|
setClaudeModel((current) => {
|
||||||
|
const valid = options.some((o) => o.value === current);
|
||||||
|
if (valid) return current;
|
||||||
|
const fallback = options[0]?.value ?? CLAUDE_MODELS.DEFAULT;
|
||||||
|
localStorage.setItem('claude-model', fallback);
|
||||||
|
return fallback;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// Static fallback already in place — nothing to do
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const lastProviderRef = useRef(provider);
|
const lastProviderRef = useRef(provider);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -118,6 +152,10 @@ export function useChatProviderState({ selectedSession }: UseChatProviderStateAr
|
||||||
setCodexModel,
|
setCodexModel,
|
||||||
geminiModel,
|
geminiModel,
|
||||||
setGeminiModel,
|
setGeminiModel,
|
||||||
|
claudeModelOptions,
|
||||||
|
codexModelOptions,
|
||||||
|
geminiModelOptions,
|
||||||
|
cursorModelOptions,
|
||||||
permissionMode,
|
permissionMode,
|
||||||
setPermissionMode,
|
setPermissionMode,
|
||||||
pendingPermissionRequests,
|
pendingPermissionRequests,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue