Fix: keep each tab's model across a restart - #57
Merged
Merged
Conversation
Restoring a workspace starts every tab at once, and a tab boots on the default model before InitTabAsync moves it onto its own saved one. SaveWorkspace records the current model of EVERY tab, and it is reached constantly during startup: StateChanged raises UpdateHeader, which raises HeaderChanged, which saves. Any of those firing mid-restore stamped the default over a tab that had not switched yet, and that tab came back on the default next launch with nothing to recover from. Workspace writes are now suppressed until the last tab finishes restoring, and the tab that finishes last performs one save with every model settled. A tab whose restore never completes is still sitting on the default it was seeded with, so persisting that would discard the user's choice for good. ModelRestorePending keeps the saved model in the workspace until RestoreTabAsync runs to completion; it is cleared after the await rather than in the finally, so a throw part way through leaves the saved model protected. This matters more now that the final save is guaranteed rather than incidental.
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.
Summary
An agent whose model you had switched could come back on the default model after restarting the app, with the switch permanently lost. This holds each tab's model across a restart.
What was happening
Restoring a workspace starts every tab initializing at the same time, and each tab boots on the default model before being moved onto the model it was saved with.
The workspace file records the current model of every tab, not just the one that changed — and it gets written constantly during startup, because ordinary UI refreshes (connection status, model validation, MCP startup) all funnel into a save. A save landing in that window wrote the default over the model of every tab that had not switched yet.
The saved value was then gone. That tab came back on the default on the next launch, and the launch after that, with nothing left to recover from.
This is why it only appeared after a restart, and why it could look intermittent: whether the damage stuck depended on which tab won the race.
What changed
Scope and risk
Low, and confined to workspace persistence at startup. No change to how models are chosen, applied, or validated; per-agent settings and the saved default were already correct and are untouched. The worst case if the new guard misbehaved is a workspace write being skipped, which leaves the previous saved state in place rather than losing anything.
Verification
Not covered by automated tests — this needs a live window and a real workspace file, which no test harness creates. It was checked manually instead, including watching the workspace file during startup to confirm a single write occurs after the tabs settle rather than several with defaults in them.
Note for reviewers
Investigation ruled out the more obvious suspect: per-agent config is deep-cloned from the defaults, only one class may write the config file, and the model field on the defaults is never assigned anywhere in Desktop. Switching a model in one agent has never affected the saved default or any other agent. The bug was entirely in what the workspace file recorded during restore.