fix(ui): /model + /preset update active model so the next card pill is fresh#385
Merged
Conversation
…s fresh (#372) `state.session.model` was set once in `initialState()` and never mutated. `/model <id>` and `/preset {auto,flash,pro}` only routed through `loop.configure({ model })`, never into the agent store — so the next `streaming.start` / `reasoning.start` / "thinking · X" card snapshotted the launch-time model id, even when the model that actually answered the turn was different. Add a typed `session.model.change` event the model handlers dispatch through `ctx.dispatch`. Reducer mutates `state.session.model` (with referential identity preserved when the id is unchanged) and the existing snapshot logic in `makeReasoningCard` / `makeStreamingCard` picks up the new value automatically. Cards already opened keep their captured model — that snapshot is intentional so mid-turn escalation doesn't relabel completed reasoning.
ChasLui
pushed a commit
to ChasLui/DeepSeek-Reasonix
that referenced
this pull request
May 23, 2026
…s fresh (esengine#372) (esengine#385) `state.session.model` was set once in `initialState()` and never mutated. `/model <id>` and `/preset {auto,flash,pro}` only routed through `loop.configure({ model })`, never into the agent store — so the next `streaming.start` / `reasoning.start` / "thinking · X" card snapshotted the launch-time model id, even when the model that actually answered the turn was different. Add a typed `session.model.change` event the model handlers dispatch through `ctx.dispatch`. Reducer mutates `state.session.model` (with referential identity preserved when the id is unchanged) and the existing snapshot logic in `makeReasoningCard` / `makeStreamingCard` picks up the new value automatically. Cards already opened keep their captured model — that snapshot is intentional so mid-turn escalation doesn't relabel completed reasoning.
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.
Closes #372.
Why
state.session.modelis set once ininitialState()and never mutated./model <id>,/preset {auto,flash,pro}only route throughloop.configure({ model })— they never feed the agent store. So the nextstreaming.start/reasoning.start/ "thinking · X" card snapshots the launch-time model id, regardless of which model actually answered the turn.Repro:
/model deepseek-v4-pro.flash.What changes
src/cli/ui/state/events.ts— new typed event:src/cli/ui/state/reducer.ts— handlessession.model.change. Returns the same state when the id is unchanged so React.memo'd consumers don't re-render needlessly.src/cli/ui/slash/handlers/model.ts—/modeland/preset {auto,flash,pro}dispatch the event afterloop.configure(...).ctx.dispatchis already plumbed viaagentStore.dispatchin App.tsx (existing wire — used by other handlers).Cards already opened keep their captured model — that snapshot at
streaming.start/reasoning.startis intentional so mid-turn auto-escalation doesn't relabel completed reasoning. Fresh cards opened after the switch render the new id.Tests
tests/ui-reducer.test.ts— 3 new cases:session.model.changeupdatesstate.session.modeland the next streaming card snapshots itTest plan
npm run verify— 133 files / 2141 passed / 1 skipped (was 2138, +3 new)/model deepseek-v4-pro→ send a message → next assistant card pill readspro/preset flash→/preset pro→ next card pill matches the active preset