Repository navigation
Conversation
The composer and the default and text generation model settings now build the picked selection through one helper, resolveModelPick, which still behaves as before. The new test shows the bug: picking the model that is already selected replaces its options with the remembered ones (or drops them), so Opus 5.5 at Medium becomes Opus 5.5 at High with no visible model change. The "changes nothing when the current model is picked again" case fails until the fix lands in the next commit.
Picking the model that is already selected, with Enter, a model jump shortcut, or a click on its row, reached the selection handlers like a real switch. The composer swapped the thread's effort and context for that model's remembered options and marked the draft explicit, so the next send could run at a setting the user never chose. On a Claude thread with background work, that send was refused as a setting change. The default and text generation model settings dropped the saved traits the same way. resolveModelPick now returns null when the pick names the current instance and model. The composer treats that as a no-op, matching mobile. Settings write the current selection back unchanged, so re-picking still pins an automatic default or unifies a mixed scope without losing traits.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (5)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review. 📝 WalkthroughWalkthroughAdded a shared helper to resolve model picks. Chat and settings now use it when selecting models, and tests cover its behavior for repeated picks and provider options. ChangesModel selection resolution
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to Re-selecting the current model should now keep its saved options in the chat composer and the settings pickers. No merge-blocking risk was found. The author did not manually click-test the current row or the text-generation picker in a client. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Problem
Choosing the model that is already selected is not a no-op on web. In the composer, pressing Enter on the current model or using a model jump shortcut replaces the thread's options with that model's remembered options from another thread, and marks them as an explicit choice. The label still names the same model, so the effort and context window change without the user noticing. On a Claude thread with background work, the next send then counts as a setting change, and the server refuses it (#14726). Settings › General › Model and the text generation model picker have the same problem: re-selecting the current default drops its saved traits.
Change
resolveModelPickinpackages/shared/src/model.tsbuilds the selection a pick produces. It returns null when the pick names the current instance and model. The callers handle that result:ChatView.onProviderModelSelectcompares the pick with the composer's current selection. On a match it only refocuses the composer. It writes no draft, no explicit flag, and no remembered options. Mobile already behaves this way (ThreadComposer.tsx).ProjectDefaultsSettingsand the text generation picker inSettingsPanelskeep the current selection, with its traits, on a re-pick. A re-pick still saves the selection, so it still pins an automatic default and unifies a mixed scope as before.Picking a different model is unchanged. The guard lives in the callers and not in the shared picker, because the picker does not know the current options and must keep multi-select and mixed-scope picks working.
Scope and approval
This is a small, focused fix for an obvious bug under the prior-approval exception. Re-selecting what is already selected should not change anything, and mobile already treats it as a no-op. Opus and Sol found the bug while triaging #16406 and listed it in this comment. It adds no settings, contracts, or server changes.
Verification
Environment. macOS 26,
vp run devfrom this branch with fresh worktree state, headless Chromium at 1280 × 800, and a syntheticdemoproject. For "before", I swapped in the commit-1 version ofpackages/shared/src/model.ts, which has the same routing without the guard.Composer. Thread A runs Claude Sonnet 5.5 at its defaults, High · 200k. In another thread I set Sonnet 5.5 to Low · 1M, so the remembered options are Low · 1M. Back in thread A, I open the picker, search "sonnet 5.5", and press Enter on the model that is already selected.
Settings › General › Model. The default is Claude Sonnet 5.5 · Low · 1M. I re-select Claude Sonnet 5.5 in the picker and press Enter.
{"model":"claude-sonnet-5-5"}Tests.
packages/shared/src/model.test.tsadds tworesolveModelPickcases. Commit2cbf6df782routes the callers through the helper without the guard. Its test fails withexpected nulland receives{ instanceId: "claudeAgent", model: "claude-opus-5-5", options: [{ id: "effort", value: "high" }] }. With the fix, 28/28 pass.vp test runonChatView.logic.test.ts,ModelPickerContent.test.ts,ProviderModelPicker.test.tsx,composerDraftStore.test.ts,modelSelection.test.tsandSettingsPanels.logic.test.tspasses, 353 tests.tsc --noEmitpasses forapps/web.I did not check a mouse click on the current row in a client. Base UI's combobox source calls
onValueChangefor it without an equality check, so it takes the same path. I also did not check the text generation picker in a client. Its code path is the same as the default model picker's.Investigated by Claude Opus 5.5, cross-checked by GPT-6.1 Sol, and implemented by Claude Opus 5.5 in Claude Code running inside T3 Code.