diff --git a/shared/modelConstants.js b/shared/modelConstants.js index c476955b..514a1772 100644 --- a/shared/modelConstants.js +++ b/shared/modelConstants.js @@ -13,14 +13,14 @@ export const CLAUDE_MODELS = { // Models in SDK format (what the actual SDK accepts) OPTIONS: [ - { value: 'sonnet', label: 'Sonnet' }, - { value: 'opus', label: 'Opus' }, - { value: 'haiku', label: 'Haiku' }, - { value: 'opusplan', label: 'Opus Plan' }, - { value: 'sonnet[1m]', label: 'Sonnet [1M]' } + { value: "sonnet", label: "Sonnet" }, + { value: "opus", label: "Opus" }, + { value: "haiku", label: "Haiku" }, + { value: "opusplan", label: "Opus Plan" }, + { value: "sonnet[1m]", label: "Sonnet [1M]" }, ], - DEFAULT: 'sonnet' + DEFAULT: "sonnet", }; /** @@ -28,28 +28,28 @@ export const CLAUDE_MODELS = { */ export const CURSOR_MODELS = { OPTIONS: [ - { value: 'opus-4.6-thinking', label: 'Claude 4.6 Opus (Thinking)' }, - { value: 'gpt-5.3-codex', label: 'GPT-5.3' }, - { value: 'gpt-5.2-high', label: 'GPT-5.2 High' }, - { value: 'gemini-3-pro', label: 'Gemini 3 Pro' }, - { value: 'opus-4.5-thinking', label: 'Claude 4.5 Opus (Thinking)' }, - { value: 'gpt-5.2', label: 'GPT-5.2' }, - { value: 'gpt-5.1', label: 'GPT-5.1' }, - { value: 'gpt-5.1-high', label: 'GPT-5.1 High' }, - { value: 'composer-1', label: 'Composer 1' }, - { value: 'auto', label: 'Auto' }, - { value: 'sonnet-4.5', label: 'Claude 4.5 Sonnet' }, - { value: 'sonnet-4.5-thinking', label: 'Claude 4.5 Sonnet (Thinking)' }, - { value: 'opus-4.5', label: 'Claude 4.5 Opus' }, - { value: 'gpt-5.1-codex', label: 'GPT-5.1 Codex' }, - { value: 'gpt-5.1-codex-high', label: 'GPT-5.1 Codex High' }, - { value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max' }, - { value: 'gpt-5.1-codex-max-high', label: 'GPT-5.1 Codex Max High' }, - { value: 'opus-4.1', label: 'Claude 4.1 Opus' }, - { value: 'grok', label: 'Grok' } + { value: "opus-4.6-thinking", label: "Claude 4.6 Opus (Thinking)" }, + { value: "gpt-5.3-codex", label: "GPT-5.3" }, + { value: "gpt-5.2-high", label: "GPT-5.2 High" }, + { value: "gemini-3-pro", label: "Gemini 3 Pro" }, + { value: "opus-4.5-thinking", label: "Claude 4.5 Opus (Thinking)" }, + { value: "gpt-5.2", label: "GPT-5.2" }, + { value: "gpt-5.1", label: "GPT-5.1" }, + { value: "gpt-5.1-high", label: "GPT-5.1 High" }, + { value: "composer-1", label: "Composer 1" }, + { value: "auto", label: "Auto" }, + { value: "sonnet-4.5", label: "Claude 4.5 Sonnet" }, + { value: "sonnet-4.5-thinking", label: "Claude 4.5 Sonnet (Thinking)" }, + { value: "opus-4.5", label: "Claude 4.5 Opus" }, + { value: "gpt-5.1-codex", label: "GPT-5.1 Codex" }, + { value: "gpt-5.1-codex-high", label: "GPT-5.1 Codex High" }, + { value: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" }, + { value: "gpt-5.1-codex-max-high", label: "GPT-5.1 Codex Max High" }, + { value: "opus-4.1", label: "Claude 4.1 Opus" }, + { value: "grok", label: "Grok" }, ], - DEFAULT: 'gpt-5-3-codex' + DEFAULT: "gpt-5-3-codex", }; /** @@ -57,17 +57,16 @@ export const CURSOR_MODELS = { */ export const CODEX_MODELS = { OPTIONS: [ - { value: 'gpt-5.4', label: 'GPT-5.4' }, - { value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' }, - { value: 'gpt-5.3-codex', label: 'GPT-5.3 Codex' }, - { value: 'gpt-5.2-codex', label: 'GPT-5.2 Codex' }, - { value: 'gpt-5.2', label: 'GPT-5.2' }, - { value: 'gpt-5.1-codex-max', label: 'GPT-5.1 Codex Max' }, - { value: 'o3', label: 'O3' }, - { value: 'o4-mini', label: 'O4-mini' } + { value: "gpt-5.4", label: "GPT-5.4" }, + { value: "gpt-5.3-codex", label: "GPT-5.3 Codex" }, + { value: "gpt-5.2-codex", label: "GPT-5.2 Codex" }, + { value: "gpt-5.2", label: "GPT-5.2" }, + { value: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" }, + { value: "o3", label: "O3" }, + { value: "o4-mini", label: "O4-mini" }, ], - DEFAULT: 'gpt-5.4' + DEFAULT: "gpt-5.4", }; /** @@ -75,16 +74,19 @@ export const CODEX_MODELS = { */ export const GEMINI_MODELS = { OPTIONS: [ - { value: 'gemini-3.1-pro-preview', label: 'Gemini 3.1 Pro Preview' }, - { value: 'gemini-3-pro-preview', label: 'Gemini 3 Pro Preview' }, - { value: 'gemini-3-flash-preview', label: 'Gemini 3 Flash Preview' }, - { value: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash' }, - { value: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro' }, - { value: 'gemini-2.0-flash-lite', label: 'Gemini 2.0 Flash Lite' }, - { value: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash' }, - { value: 'gemini-2.0-pro-exp', label: 'Gemini 2.0 Pro Experimental' }, - { value: 'gemini-2.0-flash-thinking-exp', label: 'Gemini 2.0 Flash Thinking' } + { value: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro Preview" }, + { value: "gemini-3-pro-preview", label: "Gemini 3 Pro Preview" }, + { value: "gemini-3-flash-preview", label: "Gemini 3 Flash Preview" }, + { value: "gemini-2.5-flash", label: "Gemini 2.5 Flash" }, + { value: "gemini-2.5-pro", label: "Gemini 2.5 Pro" }, + { value: "gemini-2.0-flash-lite", label: "Gemini 2.0 Flash Lite" }, + { value: "gemini-2.0-flash", label: "Gemini 2.0 Flash" }, + { value: "gemini-2.0-pro-exp", label: "Gemini 2.0 Pro Experimental" }, + { + value: "gemini-2.0-flash-thinking-exp", + label: "Gemini 2.0 Flash Thinking", + }, ], - DEFAULT: 'gemini-2.5-flash' + DEFAULT: "gemini-2.5-flash", }; diff --git a/src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx b/src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx index 646e26b9..792b12c7 100644 --- a/src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx +++ b/src/components/chat/view/subcomponents/ProviderSelectionEmptyState.tsx @@ -1,12 +1,17 @@ -import React from 'react'; -import { Check, ChevronDown } from 'lucide-react'; -import { useTranslation } from 'react-i18next'; -import SessionProviderLogo from '../../../llm-logo-provider/SessionProviderLogo'; -import { CLAUDE_MODELS, CURSOR_MODELS, CODEX_MODELS, GEMINI_MODELS } from '../../../../../shared/modelConstants'; -import type { ProjectSession, SessionProvider } from '../../../../types/app'; -import { NextTaskBanner } from '../../../task-master'; +import React from "react"; +import { Check, ChevronDown } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import SessionProviderLogo from "../../../llm-logo-provider/SessionProviderLogo"; +import { + CLAUDE_MODELS, + CURSOR_MODELS, + CODEX_MODELS, + GEMINI_MODELS, +} from "../../../../../shared/modelConstants"; +import type { ProjectSession, SessionProvider } from "../../../../types/app"; +import { NextTaskBanner } from "../../../task-master"; -interface ProviderSelectionEmptyStateProps { +type ProviderSelectionEmptyStateProps = { selectedSession: ProjectSession | null; currentSessionId: string | null; provider: SessionProvider; @@ -24,7 +29,7 @@ interface ProviderSelectionEmptyStateProps { isTaskMasterInstalled: boolean | null; onShowAllTasks?: (() => void) | null; setInput: React.Dispatch>; -} +}; type ProviderDef = { id: SessionProvider; @@ -37,50 +42,56 @@ type ProviderDef = { const PROVIDERS: ProviderDef[] = [ { - id: 'claude', - name: 'Claude Code', - infoKey: 'providerSelection.providerInfo.anthropic', - accent: 'border-primary', - ring: 'ring-primary/15', - check: 'bg-primary text-primary-foreground', + id: "claude", + name: "Claude Code", + infoKey: "providerSelection.providerInfo.anthropic", + accent: "border-primary", + ring: "ring-primary/15", + check: "bg-primary text-primary-foreground", }, { - id: 'cursor', - name: 'Cursor', - infoKey: 'providerSelection.providerInfo.cursorEditor', - accent: 'border-violet-500 dark:border-violet-400', - ring: 'ring-violet-500/15', - check: 'bg-violet-500 text-white', + id: "cursor", + name: "Cursor", + infoKey: "providerSelection.providerInfo.cursorEditor", + accent: "border-violet-500 dark:border-violet-400", + ring: "ring-violet-500/15", + check: "bg-violet-500 text-white", }, { - id: 'codex', - name: 'Codex', - infoKey: 'providerSelection.providerInfo.openai', - accent: 'border-emerald-600 dark:border-emerald-400', - ring: 'ring-emerald-600/15', - check: 'bg-emerald-600 dark:bg-emerald-500 text-white', + id: "codex", + name: "Codex", + infoKey: "providerSelection.providerInfo.openai", + accent: "border-emerald-600 dark:border-emerald-400", + ring: "ring-emerald-600/15", + check: "bg-emerald-600 dark:bg-emerald-500 text-white", }, { - id: 'gemini', - name: 'Gemini', - infoKey: 'providerSelection.providerInfo.google', - accent: 'border-blue-500 dark:border-blue-400', - ring: 'ring-blue-500/15', - check: 'bg-blue-500 text-white', + id: "gemini", + name: "Gemini", + infoKey: "providerSelection.providerInfo.google", + accent: "border-blue-500 dark:border-blue-400", + ring: "ring-blue-500/15", + check: "bg-blue-500 text-white", }, ]; function getModelConfig(p: SessionProvider) { - if (p === 'claude') return CLAUDE_MODELS; - if (p === 'codex') return CODEX_MODELS; - if (p === 'gemini') return GEMINI_MODELS; + if (p === "claude") return CLAUDE_MODELS; + if (p === "codex") return CODEX_MODELS; + if (p === "gemini") return GEMINI_MODELS; return CURSOR_MODELS; } -function getModelValue(p: SessionProvider, c: string, cu: string, co: string, g: string) { - if (p === 'claude') return c; - if (p === 'codex') return co; - if (p === 'gemini') return g; +function getModelValue( + p: SessionProvider, + c: string, + cu: string, + co: string, + g: string, +) { + if (p === "claude") return c; + if (p === "codex") return co; + if (p === "gemini") return g; return cu; } @@ -103,24 +114,41 @@ export default function ProviderSelectionEmptyState({ onShowAllTasks, setInput, }: ProviderSelectionEmptyStateProps) { - const { t } = useTranslation('chat'); - const nextTaskPrompt = t('tasks.nextTaskPrompt', { defaultValue: 'Start the next task' }); + const { t } = useTranslation("chat"); + const nextTaskPrompt = t("tasks.nextTaskPrompt", { + defaultValue: "Start the next task", + }); const selectProvider = (next: SessionProvider) => { setProvider(next); - localStorage.setItem('selected-provider', next); + localStorage.setItem("selected-provider", next); setTimeout(() => textareaRef.current?.focus(), 100); }; const handleModelChange = (value: string) => { - if (provider === 'claude') { setClaudeModel(value); localStorage.setItem('claude-model', value); } - else if (provider === 'codex') { setCodexModel(value); localStorage.setItem('codex-model', value); } - else if (provider === 'gemini') { setGeminiModel(value); localStorage.setItem('gemini-model', value); } - else { setCursorModel(value); localStorage.setItem('cursor-model', value); } + if (provider === "claude") { + setClaudeModel(value); + localStorage.setItem("claude-model", value); + } else if (provider === "codex") { + setCodexModel(value); + localStorage.setItem("codex-model", value); + } else if (provider === "gemini") { + setGeminiModel(value); + localStorage.setItem("gemini-model", value); + } else { + setCursorModel(value); + localStorage.setItem("cursor-model", value); + } }; const modelConfig = getModelConfig(provider); - const currentModel = getModelValue(provider, claudeModel, cursorModel, codexModel, geminiModel); + const currentModel = getModelValue( + provider, + claudeModel, + cursorModel, + codexModel, + geminiModel, + ); /* ── New session — provider picker ── */ if (!selectedSession && !currentSessionId) { @@ -130,10 +158,10 @@ export default function ProviderSelectionEmptyState({ {/* Heading */}

- {t('providerSelection.title')} + {t("providerSelection.title")}

- {t('providerSelection.description')} + {t("providerSelection.description")}

@@ -149,23 +177,30 @@ export default function ProviderSelectionEmptyState({ relative flex flex-col items-center gap-2.5 rounded-xl border-[1.5px] px-2 pb-4 pt-5 transition-all duration-150 active:scale-[0.97] - ${active - ? `${p.accent} ${p.ring} bg-card shadow-sm ring-2` - : 'border-border bg-card/60 hover:border-border/80 hover:bg-card' + ${ + active + ? `${p.accent} ${p.ring} bg-card shadow-sm ring-2` + : "border-border bg-card/60 hover:border-border/80 hover:bg-card" } `} >
-

{p.name}

-

{t(p.infoKey)}

+

+ {p.name} +

+

+ {t(p.infoKey)} +

{/* Check badge */} {active && ( -
+
)} @@ -175,9 +210,13 @@ export default function ProviderSelectionEmptyState({
{/* Model picker — appears after provider is chosen */} -
+
- {t('providerSelection.selectModel')} + + {t("providerSelection.selectModel")} +
@@ -196,10 +239,18 @@ export default function ProviderSelectionEmptyState({

{ { - claude: t('providerSelection.readyPrompt.claude', { model: claudeModel }), - cursor: t('providerSelection.readyPrompt.cursor', { model: cursorModel }), - codex: t('providerSelection.readyPrompt.codex', { model: codexModel }), - gemini: t('providerSelection.readyPrompt.gemini', { model: geminiModel }), + claude: t("providerSelection.readyPrompt.claude", { + model: claudeModel, + }), + cursor: t("providerSelection.readyPrompt.cursor", { + model: cursorModel, + }), + codex: t("providerSelection.readyPrompt.codex", { + model: codexModel, + }), + gemini: t("providerSelection.readyPrompt.gemini", { + model: geminiModel, + }), }[provider] }

@@ -208,7 +259,10 @@ export default function ProviderSelectionEmptyState({ {/* Task banner */} {provider && tasksEnabled && isTaskMasterInstalled && (
- setInput(nextTaskPrompt)} onShowAllTasks={onShowAllTasks} /> + setInput(nextTaskPrompt)} + onShowAllTasks={onShowAllTasks} + />
)}
@@ -221,12 +275,19 @@ export default function ProviderSelectionEmptyState({ return (
-

{t('session.continue.title')}

-

{t('session.continue.description')}

+

+ {t("session.continue.title")} +

+

+ {t("session.continue.description")} +

{tasksEnabled && isTaskMasterInstalled && (
- setInput(nextTaskPrompt)} onShowAllTasks={onShowAllTasks} /> + setInput(nextTaskPrompt)} + onShowAllTasks={onShowAllTasks} + />
)}