Skip to content

fix(vscode): restore per-mode model memory to match CLI TUI behavior#9146

Merged
kirillk merged 7 commits intomainfrom
chip-ermine
Apr 20, 2026
Merged

fix(vscode): restore per-mode model memory to match CLI TUI behavior#9146
kirillk merged 7 commits intomainfrom
chip-ermine

Conversation

@kirillk
Copy link
Copy Markdown
Contributor

@kirillk kirillk commented Apr 17, 2026

Summary

The CLI TUI remembers which model you last picked for each mode (code/ask/plan) and restores it when you switch back. The VS Code extension did not — model selections were lost on mode switch and webview reload. This PR brings the extension to parity with the CLI by reading and writing the same ~/.local/state/kilo/model.json file.

What was broken

When a session was active, applyModel() only wrote the model choice to a per-session override. Switching modes cleared that override, and the selection was gone. There was also no persistence — even the in-memory per-mode map was lost on webview reload.

How it works now

  • Picking a model always saves it per-mode (in memory and to model.json), regardless of whether a session is active.
  • On startup, persisted per-mode selections are loaded from model.json so choices survive restarts.
  • The extension reads/writes the same model.json the CLI TUI uses, so picks made in either client are visible to the other.
Screen Shot 2026-04-17 at 3 09 01 PM

Model resolution priority (unchanged)

This PR does not change the resolution order. Both CLI and extension use:

  1. User override — last model picked in the UI (persisted in model.json)
  2. Agent-specific model — per-mode config setting (e.g. agent.code.model)
  3. Global model — top-level model in config
  4. Kilo defaultkilo-auto/free

The user override takes precedence over config. The reset button (visible when the model differs from config default) clears the override so the config setting takes effect again.

Trade-off: no opencode changes

The per-mode model persistence is a Kilo-specific feature implemented in the TUI client layer (local.tsx), not in the server. The cleanest fix would add a shared module in packages/opencode/ with server routes so both TUI and extension call the same code. We opted for direct file I/O from the extension host instead — the duplicated logic is trivially small (JSON read-modify-write on one key) and this avoids server route additions, SDK regeneration, and upstream diff churn.

Persist per-mode model selections to the CLI's model.json so switching
modes restores the previously chosen model, matching CLI TUI behavior.
Comment thread packages/kilo-vscode/src/KiloProvider.ts Outdated
Comment thread packages/kilo-vscode/webview-ui/src/context/session.tsx Outdated
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 17, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0

Fix these issues in Kilo Cloud

Issue Details (click to expand)

No new issues found in the incremental diff.

Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
packages/kilo-vscode/src/kilo-provider/model-state.ts 66 The race condition still exists after extraction: persistModelSelection and clearModelSelection read and build the full model object before entering the shared write queue, so concurrent updates can still overwrite each other.
Files Reviewed (5 files)
  • .github/workflows/publish.yml
  • packages/kilo-docs/pages/code-with-ai/agents/model-selection.md
  • packages/kilo-docs/pages/customize/custom-modes.md
  • packages/opencode/src/tool/bash.ts
  • packages/opencode/test/kilocode/bash-permission-metadata.test.ts

Reviewed by gpt-5.4-20260305 · 1,481,964 tokens

kirillk added 4 commits April 17, 2026 13:50
…lace semantics

Serialize model.json writes through a promise chain to prevent concurrent
read-modify-write races from losing data.

Use reconcile() for modelSelectionsLoaded so a reset (empty payload)
clears stale entries instead of leaving them in memory.
…lections

Fix session-model-store.ts applyModel() to match the session.tsx fix
(always write to modelSelections, not just sessionOverrides). Update
existing tests for new behavior and add tests for mode-switch restore,
independent per-mode tracking, and validateModelSelections edge cases.
Move model.json read/write and message handling into
kilo-provider/model-state.ts to keep KiloProvider within its
max-lines (3353) and complexity (140) ESLint limits.
@kirillk kirillk changed the title fix(vscode): remember last selected model per mode fix(vscode): restore per-mode model memory to match CLI TUI behavior Apr 19, 2026
Copy link
Copy Markdown
Contributor

@lambertjosh lambertjosh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved from my POV, but please update docs along with this change.

Add missing behavior to model-selection.md VSCode tab: 'last picked per
agent' level in precedence chain, and a note that the model selector
remembers picks across sessions with reset button to restore config.

Add the same note to custom-modes.md for both the VSCode and CLI tabs
under the model property reference (previously only documented in the
VSCode Legacy tab as 'Sticky Models').
@kirillk
Copy link
Copy Markdown
Contributor Author

kirillk commented Apr 20, 2026

Approved from my POV, but please update docs along with this change.

Done, ty

@kirillk kirillk enabled auto-merge April 20, 2026 14:48
@kirillk kirillk merged commit 4e0e2d5 into main Apr 20, 2026
17 checks passed
@kirillk kirillk deleted the chip-ermine branch April 20, 2026 14:55
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.

2 participants