fix(desktop): reseed new chats from profile defaults, guarded against concurrent picks (supersedes #67207) - #67291
fix(desktop): reseed new chats from profile defaults, guarded against concurrent picks (supersedes #67207)#67291OutThisLife wants to merge 2 commits into
Conversation
Addresses teknium1's review of the fresh-draft reseed: refreshCurrentModel(true) bypassed both manual-state guards, so a picker selection made while the reseed's async getGlobalModelInfo() was in flight got clobbered by the resolved default — violating the AGENTS "guard against the past" invariant. Add a monotonic manual-pick token (session.ts): selectModel bumps it, and the reseed captures it before the await and bails if it moved while pending. force still overrides a PRE-EXISTING manual pick (new-chat resets to default), but a NEWER pick made mid-reseed wins. Adds a deferred-result regression test proving the post-start pick survives. Co-authored-by: Denis <276550298+deniqlab@users.noreply.github.com>
|
Closing — after weighing the UX, we're keeping the sticky-last-pick behavior (#65896) instead of resetting new chats to the profile default. Switching between existing chats is already session-scoped and unaffected; the only thing this changed was the new-chat boundary, and clobbering a deliberate manual pick on Cmd+N is worse for the "I switched models on purpose" workflow than the reset is worth. The actual reported breakage — a removed/stale default (owl-alpha, #58498) lingering and overriding config — is already fixed on The race-guard was only needed because of the force-reseed, so it's moot without it. Thanks @deniqlab for the solid work regardless. |
Summary
Salvages #67207 (@deniqlab) for #65300 — a fresh Desktop chat should seed from the
config.yamldefault, not silently reuse the previous chat's sticky composer model. Adds the race guard @teknium1's review asked for.Behavior
refreshCurrentModel(true)on fresh-draft-ready + boot-onto-fresh-draft). This is the cross-surface-consistent behavior: CLI and Telegram already seed each session from config; Desktop's localStorage stickiness was the outlier (Hermes Desktop new session ignores config.yaml default and reuses sticky composer model #65300, and the earlier owl-alpha/[Bug]: Hermes Desktop ignores OpenAI Codex provider and routes GPT-5.5 requests through Nous Portal (CLI works correctly) #58498 thread).forcepath from fix(desktop): refresh default-derived composer model (supersedes #62486) #65896 is unchanged, so boot/focus/session-event refreshes preserve an in-context selection.$activeSessionId).The race guard (teknium1's review)
@deniqlab's version used
refreshCurrentModel(true), which bypasses both manual-state guards — so a picker selection made while the reseed's asyncgetGlobalModelInfo()was in flight got overwritten by the resolved default, violatingapps/desktop/AGENTS.md's "guard against the past: a stale response must never overwrite newer intent."Fix: a monotonic manual-pick token (
session.ts).selectModelbumps it; the reseed captures it before the await and bails if it moved while pending. Soforcestill overrides a pre-existing manual pick (new chat resets to default), but a newer pick made mid-reseed wins. Added a deferred-result regression test proving the post-start pick survives.Note on the #65896 relationship
This intentionally drops #65896's cross-chat manual stickiness (a pick no longer bleeds into the next new chat) while keeping its genuinely important part — the stale-guard against incidental refreshes. Net: manual intent wins within a chat and against in-flight reseeds; a brand-new chat honors your configured default.
Test plan
vitest run --project ui— 189 files, 1530 pass / 1 skip (incl. new deferred-pick guard test +use-background-sync.test.tsx)npm run typecheck— cleaneslintchanged files — cleannpm run build— successFixes #65300