fix: model catalog follows the session's backend (TUI)#22
Conversation
Same class of bug as the web fix: switching a session's backend left the `/model` picker + validation showing the OLD backend's models. Worse here — the TUI's `models.list` frame had NO provider field at all, and the catalog was fetched exactly once at connect, so it always showed the daemon's default backend (claude) for the whole session, regardless of `/provider` switches or which session was focused. - protocol: `ClientMessage::ModelsList` gains `provider: Option<String>` (wire-additive); `DaemonMessage::ModelsListResult` exposes `provider` so the client can drop a stale result after a fast switch. - `fetch_models()` sends the FOCUSED session's backend, and runs on connect, on focus change, and after a `/provider` switch. - the result handler drops a catalog whose backend no longer matches the focused session (fast-switch race); legacy daemons omit `provider`, so those results are accepted (can't guard) — unchanged behavior. - `/provider` optimistically stamps the new backend onto the focused session before refetching, so the fetch + its guard both key off the new backend without waiting for the daemon's info_update frame; it also clears the stale catalog so the picker can't flash the old models. A never-used backend still shows an empty catalog until its first turn (models are genuinely unknown until the backend spawns). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🤖 Gemini code reviewThis PR fixes a bug in the TUI where the model catalog failed to update upon switching backends (/provider switches or session focus changes). It adds a Findings: 🔴 0 · 🟠 0 · 🟡 0 · 🟢 0 Tokens spent · ⬆️ Input: 4,265 · ⬇️ Output: 105 · Σ Total: 7,525 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #22 +/- ##
==========================================
+ Coverage 71.82% 72.15% +0.32%
==========================================
Files 31 31
Lines 8434 8559 +125
==========================================
+ Hits 6058 6176 +118
- Misses 2376 2383 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
|
The TUI half of the model-catalog-doesn't-refresh-on-backend-switch bug (web half: saucam/codeoid#160).
Root cause — worse than the web
The TUI's
models.listframe had no provider field at all, and the catalog was fetched exactly once at connect. So it always showed the daemon's default backend (claude) for the entire session —/providerswitches and focus changes never refetched. A session on codex showed claude's models permanently.Fix
codeoid-protocol):ClientMessage::ModelsListgainsprovider: Option<String>(wire-additive,skip_serializing_if None);DaemonMessage::ModelsListResultexposesproviderso the client can drop a stale result.fetch_models()sends the focused session's backend and runs on connect, on focus change, and after a/providerswitch.provider→ accepted (can't guard), preserving old behavior./provideroptimistic update: the switch stamps the new backend onto the focused session locally before refetching, so both the fetch and its guard key off the new backend without waiting for the daemon'ssession.info_updateframe (a separate message that may arrive after the switch response). It also clears the stale catalog so the picker can't flash the old models.A never-used backend shows an empty catalog until its first turn (models genuinely unknown until the backend spawns) — same honest behavior as the web fix.
Tests
models.listframe carries the provider (and omits it when None).cargo test --workspace: 269 tui + 13 protocol + 10 client green;fmt --checkclean.Depends on the daemon already keying
models.listby provider (shipped in the provider-extension work) — no daemon change needed.🤖 Generated with Claude Code