Skip to content

fix: keep the picked model and effort across an abort - #1596

Merged
bra1nDump merged 1 commit into
slopus:mainfrom
charliezong18:fix/preserve-model-on-abort
Jul 28, 2026
Merged

fix: keep the picked model and effort across an abort#1596
bra1nDump merged 1 commit into
slopus:mainfrom
charliezong18:fix/preserve-model-on-abort

Conversation

@charliezong18

Copy link
Copy Markdown
Contributor

Fixes #1595

Problem

Pick a non-default model in the picker, abort a turn, then send another message — the next turn runs the session's launch default (opus) instead, and the picker keeps showing the model you picked. Same for reasoning effort (reverts to medium). Nothing in the UI indicates the switch.

Cause

resetCurrentModeDefaults() in packages/happy-cli/src/claude/runClaude.ts is the loop's onAbort. It reset currentModel = options.model ?? DEFAULT_CLAUDE_MODEL and currentEffort likewise. options.model is undefined for app-driven sessions, so the model landed on the 'opus' constant.

The app sends meta.model / meta.effort only when the picker changes (the outgoing MessageModeMeta carries exactly permissionMode, model, modelProviderId, effort — the other fields the reset touches are never sent by the app, so resetting those is a no-op). That makes currentModel/currentEffort the only record of the user's pick — resetting them desyncs the CLI from the picker until the user re-touches it.

packages/happy-cli/src/codex/runCodex.ts had the identical reset and the identical bug.

Fix

Drop the model and effort resets from both functions. Permission mode still resets — that's deliberate post-abort safety behavior (see the comment in runCodex.ts); fallback model, system prompts and tool overrides also still reset.

Proof it works (end-to-end)

Real local happy-server (PGlite) + real seeded account + the real built CLI (happy claude --happy-starting-mode remote) under a sandbox HAPPY_HOME_DIR; the app side scripted over the same encrypted wire protocol (messages via POST /v3/sessions/:id/messages, abort via socket.io rpc-call<sessionId>:abort). Scenario: message with meta.model: claude-sonnet-4-6 → abort → message with no meta.

Before (main):

[21:51:35.308] [loop] Model updated from user message: claude-sonnet-4-6
[21:51:40.875] [claudeRemote] Result received
[21:51:41.336] [remote]: doAbort
[21:51:41.337] [loop] Reset current mode defaults after abort
[21:51:42.598] [loop] User message received with no model override, using current: opus

Turn 2's SDK subprocess ran with --model opus; its assistant stream reports "model": "claude-opus-4-8".

After (this branch, identical scenario):

[21:50:28.940] [loop] Model updated from user message: claude-sonnet-4-6
[21:50:44.037] [claudeRemote] Result received
[21:50:44.534] [remote]: doAbort
[21:50:44.534] [loop] Reset current mode defaults after abort
[21:50:45.398] [loop] User message received with no model override, using current: claude-sonnet-4-6

Turn 2 ran with --model claude-sonnet-4-6; zero opus occurrences in the logs.

Test

Added a unit regression test in runClaude.test.ts on the existing startRemoteRunClaudeHarness: message with meta.model + meta.effort → fire onAbort → message with empty meta → the queued mode still carries the original model and effort. Fails on main with model: 'opus', effort: 'medium'; passes with the fix.

runCodex has no comparable unit harness in this package, so the Codex half is covered by the parity of the change only.

🤖 Generated with Claude Code

`resetCurrentModeDefaults()` runs on abort and reverted `currentModel` /
`currentEffort` to the session launch defaults. Since the app only sends
`meta.model` / `meta.effort` when the user changes the picker, every turn
after an abort silently ran the launch default while the picker still
showed the user's choice.

Both the Claude and the Codex loop had the same reset. Permission mode,
system prompts and tool overrides still reset as before.

Fixes slopus#1595

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
@bra1nDump
bra1nDump merged commit 23c1ea2 into slopus:main Jul 28, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aborting a turn silently reverts the session model and effort to launch defaults

2 participants