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.
Contributor
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — The PR is a localized fix that preserves model traits when users re-select the current model, with tests and no schema or deployment changes. It also changes how product and text-generation defaults are persisted, so the default-setting behavior warrants human review. You can add or adjust custom eligibility rules. Learn more. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.