Skip to content

feat(code): persist and restore last selected model on task create#2354

Open
Basit-Balogun10 wants to merge 1 commit into
PostHog:mainfrom
Basit-Balogun10:claude/flamboyant-wiles-79a9c7
Open

feat(code): persist and restore last selected model on task create#2354
Basit-Balogun10 wants to merge 1 commit into
PostHog:mainfrom
Basit-Balogun10:claude/flamboyant-wiles-79a9c7

Conversation

@Basit-Balogun10
Copy link
Copy Markdown

@Basit-Balogun10 Basit-Balogun10 commented May 25, 2026

Problem

When you pick a non-default model (e.g. Opus over Sonnet) in the task creation UI, the next task creation reverts to the server default. We already persist and restore lastUsedAdapter, lastUsedReasoningEffort, and lastUsedInitialTaskMode - but lastUsedModel was wired into the settings store and never actually used.

Closes #1839

Changes

Two files, following the exact same pattern as reasoning effort persistence:

Save (TaskInput.tsx): Call setLastUsedModel(value) in handleModelChange - same as handleThoughtChange already calls setLastUsedReasoningEffort.

Restore (usePreviewConfig.ts): After fetching config options from the server and applying mode/effort preferences, check if lastUsedModel is set and valid for the current adapter's available models. If so, use it as currentValue; otherwise fall through to the server default (handles adapter switches cleanly - a stored Claude model won't get forced onto Codex).

No new state, types, or store fields - lastUsedModel, setLastUsedModel, and the persistence config all existed already.

How did you test this?

Typecheck passes. Manual test plan:

  • Basic persistence: Pick a non-default model → create task → open new task creation → model selector shows the previously selected model
basic-model-persistence-model-posthog-code-model-persistence-on-task-creation.webm
  • No-submit persistence: Pick a model → navigate away without submitting → come back → model persists (save triggers on selection, not submit)
model-change-without-creating-a-task-posthog-code-model-persistence-on-task-creation.webm
  • Adapter switch: Pick a Claude model → switch to Codex → model falls back to Codex server default (stored model isn't valid for Codex). Also notice Codex models are also persisted on task creation UI (e. g navigating away and back keeps the same model). Switch back to Claude → also falls back to server default since lastUsedModel is now the Codex model you last picked.
switching-adapters-posthog-code-model-persistence-on-task-creation.webm
  • Mid-session change is NOT persisted: Create a task → change model mid-session via in-session selector → go to new task creation → model reflects the task-creation selection, not the mid-session change
switching-model-mid-task-doesnt-persist-on-task-creation-posthog-code-model-persistence-on-task-creation.webm

Publish to changelog?

no

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 25, 2026

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/code/src/renderer/features/task-detail/hooks/usePreviewConfig.ts:190-201
**Restored model doesn't recalculate effort options**

`withModel` updates the model's `currentValue` but leaves the effort option's `.options` array and `currentValue` as the server returned them — calibrated to the server's default model, not the restored one. Because `getReasoningEffortOptions` returns model-specific sets (e.g. `null` for `claude-haiku-4-5`, 3 entries for `claude-sonnet-4-6`, 5 for `claude-opus-4-6`), a user who last picked `claude-haiku-4-5` will see the effort selector the server injected for the default model, and a user who last picked `claude-sonnet-4-6` when the server defaulted to an Opus model will see `xhigh`/`max` effort choices that Sonnet doesn't support. The interactive path in `setConfigOption` already handles this correctly by calling `getReasoningEffortOptions(adapter, value)` — the same call needs to happen here after the model is resolved, updating `options` and clamping `currentValue` (or removing the effort option entirely when the restored model returns `null`).

Reviews (1): Last reviewed commit: "feat(code): persist and restore last sel..." | Re-trigger Greptile

Comment on lines +190 to +201
const withModel = withEffort.map((opt) => {
if (opt.category !== "model" || opt.type !== "select") return opt;
if (!lastUsedModel) return opt;
const validValues = flattenValues(
opt.options as Array<{
value?: string;
options?: Array<{ value: string }>;
}>,
);
if (!validValues.includes(lastUsedModel)) return opt;
return { ...opt, currentValue: lastUsedModel } as SessionConfigOption;
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Restored model doesn't recalculate effort options

withModel updates the model's currentValue but leaves the effort option's .options array and currentValue as the server returned them — calibrated to the server's default model, not the restored one. Because getReasoningEffortOptions returns model-specific sets (e.g. null for claude-haiku-4-5, 3 entries for claude-sonnet-4-6, 5 for claude-opus-4-6), a user who last picked claude-haiku-4-5 will see the effort selector the server injected for the default model, and a user who last picked claude-sonnet-4-6 when the server defaulted to an Opus model will see xhigh/max effort choices that Sonnet doesn't support. The interactive path in setConfigOption already handles this correctly by calling getReasoningEffortOptions(adapter, value) — the same call needs to happen here after the model is resolved, updating options and clamping currentValue (or removing the effort option entirely when the restored model returns null).

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/task-detail/hooks/usePreviewConfig.ts
Line: 190-201

Comment:
**Restored model doesn't recalculate effort options**

`withModel` updates the model's `currentValue` but leaves the effort option's `.options` array and `currentValue` as the server returned them — calibrated to the server's default model, not the restored one. Because `getReasoningEffortOptions` returns model-specific sets (e.g. `null` for `claude-haiku-4-5`, 3 entries for `claude-sonnet-4-6`, 5 for `claude-opus-4-6`), a user who last picked `claude-haiku-4-5` will see the effort selector the server injected for the default model, and a user who last picked `claude-sonnet-4-6` when the server defaulted to an Opus model will see `xhigh`/`max` effort choices that Sonnet doesn't support. The interactive path in `setConfigOption` already handles this correctly by calling `getReasoningEffortOptions(adapter, value)` — the same call needs to happen here after the model is resolved, updating `options` and clamping `currentValue` (or removing the effort option entirely when the restored model returns `null`).

How can I resolve this? If you propose a fix, please make it concise.

Wire up the existing but unused `lastUsedModel` / `setLastUsedModel` in
settingsStore so the model picker remembers the user's choice across
task creations — same pattern already used for reasoning effort and mode.

Closes PostHog#1839
@Basit-Balogun10 Basit-Balogun10 force-pushed the claude/flamboyant-wiles-79a9c7 branch from 3791f7c to e76fdb2 Compare May 25, 2026 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

store and reuse last selected model on task create

1 participant