diff --git a/apps/code/src/main/services/agent/schemas.ts b/apps/code/src/main/services/agent/schemas.ts index dafcaf169..5aca01366 100644 --- a/apps/code/src/main/services/agent/schemas.ts +++ b/apps/code/src/main/services/agent/schemas.ts @@ -30,6 +30,8 @@ export const sessionConfigSchema = z.object({ additionalDirectories: z.array(z.string()).optional(), /** Permission mode to use for the session (e.g. "default", "acceptEdits", "plan", "bypassPermissions") */ permissionMode: z.string().optional(), + /** Preferred model ID for the session (e.g. "claude-sonnet-4-6") */ + model: z.string().optional(), }); export type SessionConfig = z.infer; @@ -49,6 +51,7 @@ export const startSessionInput = z.object({ additionalDirectories: z.array(z.string()).optional(), customInstructions: z.string().max(2000).optional(), effort: effortLevelSchema.optional(), + model: z.string().optional(), }); export type StartSessionInput = z.infer; diff --git a/apps/code/src/main/services/agent/service.ts b/apps/code/src/main/services/agent/service.ts index 9d64c2ac9..27f2881d6 100644 --- a/apps/code/src/main/services/agent/service.ts +++ b/apps/code/src/main/services/agent/service.ts @@ -189,6 +189,8 @@ interface SessionConfig { customInstructions?: string; /** Effort level for Claude sessions */ effort?: EffortLevel; + /** Model to use for the session (e.g. "claude-sonnet-4-6") */ + model?: string; } interface ManagedSession { @@ -465,6 +467,7 @@ export class AgentService extends TypedEventEmitter { permissionMode, customInstructions, effort, + model, } = config; // Preview sessions don't need a real repo — use a temp directory @@ -644,6 +647,7 @@ export class AgentService extends TypedEventEmitter { additionalDirectories, }), ...(effort && { effort }), + ...(model && { model }), plugins, }, }, @@ -673,6 +677,7 @@ export class AgentService extends TypedEventEmitter { options: { ...(additionalDirectories?.length && { additionalDirectories }), ...(effort && { effort }), + ...(model && { model }), plugins, }, }, @@ -1362,6 +1367,7 @@ For git operations while detached: customInstructions: "customInstructions" in params ? params.customInstructions : undefined, effort: "effort" in params ? params.effort : undefined, + model: "model" in params ? params.model : undefined, }; } diff --git a/apps/code/src/renderer/features/sessions/service/service.ts b/apps/code/src/renderer/features/sessions/service/service.ts index 5eb919f47..887248989 100644 --- a/apps/code/src/renderer/features/sessions/service/service.ts +++ b/apps/code/src/renderer/features/sessions/service/service.ts @@ -548,6 +548,7 @@ export class SessionService { effort: effortLevelSchema.safeParse(reasoningLevel).success ? (reasoningLevel as EffortLevel) : undefined, + model, }); const session = this.createBaseSession(taskRun.id, taskId, taskTitle); diff --git a/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx b/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx index ad0edc9d2..09c1b6424 100644 --- a/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx +++ b/apps/code/src/renderer/features/task-detail/components/TaskInput.tsx @@ -78,6 +78,11 @@ export function TaskInput({ onTaskCreated }: TaskInputProps = {}) { null, ); + // Track the user's explicit model selection independently of the preview + // session. The preview session's config can be reset (e.g. adapter change), + // which would lose the user's choice if we only read from the store. + const [selectedModel, setSelectedModel] = useState(null); + const [selectedDirectory, setSelectedDirectory] = useState(""); const workspaceMode = lastUsedWorkspaceMode || "local"; const adapter = lastUsedAdapter; @@ -94,8 +99,10 @@ export function TaskInput({ onTaskCreated }: TaskInputProps = {}) { setLastUsedLocalWorkspaceMode(mode); } }; - const setAdapter = (newAdapter: AgentAdapter) => + const setAdapter = (newAdapter: AgentAdapter) => { setLastUsedAdapter(newAdapter); + setSelectedModel(null); + }; const { githubIntegration, repositories, isLoadingRepos } = useRepositoryIntegration(); @@ -192,8 +199,11 @@ export function TaskInput({ onTaskCreated }: TaskInputProps = {}) { // Get current values from preview session config options for task creation. // Defaults ensure values are always passed even before the preview session loads. - const currentModel = + // Prefer the user's explicit selection (local state) over the preview session value, + // since the preview session's config can be transiently reset. + const previewModel = modelOption?.type === "select" ? modelOption.currentValue : undefined; + const currentModel = selectedModel ?? previewModel; const modeFallback = defaultInitialTaskMode === "last_used" ? lastUsedInitialTaskMode : "plan"; const currentExecutionMode = @@ -461,6 +471,7 @@ export function TaskInput({ onTaskCreated }: TaskInputProps = {}) { previewTaskId={previewTaskId} onAdapterChange={setAdapter} isPreviewConnecting={isConnecting} + onModelChange={setSelectedModel} />