Skip to content

chat: the /model menu's current model wears no band and the picker owns the wheel - #1696

Merged
AbirAbbas merged 5 commits into
devfrom
zeropoint95/model-menu-current-row-and-wheel
Oct 1, 2026
Merged

AbirAbbas merged 5 commits into
devfrom
zeropoint95/model-menu-current-row-and-wheel

Conversation

@ZeroPoint95

@ZeroPoint95 ZeroPoint95 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Ready to review (still marked draft on GitHub). The reviewer's fixes are in commit 3e73b0cec, and CI is running on it. This replaces #1693 with the same change, minus senior-dev's wip commits.

Three /model menu fixes

# Before After
1 The model in use had a full-width highlight band, so it looked like a second cursor. The model in use is bold and accent-coloured, with no band. Only the cursor's row has a band.
2 Scrolling the mouse wheel scrolled the conversation behind the menu. The wheel moves the menu's cursor, and it stops at the first and last rows.
3 The menu could open with no highlighted row, and the cursor disappeared near the bottom of the list. The menu opens with the cursor on the first row, and the cursor's row always stays on screen.
1696

Try it

  1. Run make build, then bin/codeaf.
  2. Type /model. The cursor is on the first row, and the model in use is bold with no band.
  3. Scroll the wheel past the bottom. The cursor stops on the last row and the conversation behind doesn't move.

How it works

  1. No band: a new flag, palette.frontUnlifted, is set only by the model picker. That covers /model, the settings slots, home's draft and alt+o. Every other list keeps its old look.
  2. Wheel: tea.MouseWheelMsg now has a branch for the picker, like the other menus. It reuses picker.move, which already stops at both ends.
  3. Cursor visible: picker.follow now counts screen lines, including service headings and "why" lines, instead of list rows. That's the same count picker.height uses to size the menu.

These still open with the cursor on the row they hold, not on the first row: a settings slot, a role, a task's model word, home's draft and alt+o. ctrl+u still returns the emptied box to the model in use.

Tests

  • New: modelmenu_test.go tests the no-band row, the wheel and the stops at both ends. modelcursor_test.go tests that the menu opens on the first row and the cursor stays visible at the bottom.
  • Full suites: go test ./internal/tui3 and ./internal/manual pass on d418fcaac, according to the reviewer. On 3e73b0cec, the focused model and picker runs and ./internal/manual pass.
  • Updated: tests that relied on the menu opening on the model in use now move the cursor there first. Two tests were adjusted for the no-band row; what they check is unchanged.

Docs

  • Commit 3e73b0cec fixes what the review found. models-and-cost.md still said the list opens on the model in use, which contradicted commands.md. Two code comments still cited that old rule. picker.follow now explains why keystroke-time calls can pass a row count as their budget.
  • Manual: keys.md covers the wheel, commands.md says the cursor opens on the first row, and models-and-cost.md describes how the model in use looks.
  • Change entries: 1696-model-menu-front-mark-and-wheel.md and 1696-model-menu-cursor-first-row.md.

🤖 Generated with Claude Code

ZeroPoint95 and others added 2 commits September 30, 2026 16:24
…ns the wheel

The chosen row of the /model list used to wear the ladder's selected
ground, a full-width band that read as a highlighted row wherever the
cursor happened to be. The band on an overlay is the cursor's language,
so the menu's front mark now keeps its accent and its weight and takes
no ground: the cursor alone lifts a row (palette.frontUnlifted, the
picker's own grammar, said on its draw and nowhere else). Every other
list that draws through the shared overlay renderer keeps the ladder's
selected step for its front mark.

A wheel notch with the list up used to fall all the way through to the
transcript and scroll words nobody can see move. The picker now claims
the wheel like every modal above it, walking its cursor, which clamps at
both ends so neither the wheel nor the keys run past the list.

The picker's scroll window was counted in list rows while the drawing
spends extra lines on a service's heading, the machines' heading and a
why line, so the cursor could sit inside the logical window and still
fall past the rendered bottom edge: the highlight vanished once the list
bottomed out, and the menu opened with no highlight anywhere because
cursorToCurrent put it on the model in use at the bottom of just such a
window. picker.follow now counts screen lines (picker.rowLines, the same
costs picker.height reserves the frame with), and the menu's own door
opens with the cursor visibly on the list's first selectable row. The
doors that open to confirm (a settings slot, a role, a task's model
word, home's draft, alt+o) keep opening ON the row they hold, and ctrl+u
still returns the emptied box to the model in use.

The fold tests that mean the model in use now walk to it explicitly, and
the rendered-ground assertion pins a color palette so it holds on a
headless runner with no terminal profile. The manual's key sheet,
Scrolling section and models page name the wheel, the first-row cursor
and the mark's look.

Co-Authored-By: codeaf <agentfield-bot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>


The two change entries were written for #1693, which this pull request
replaces with the same change on a clean history, so they are renamed to
the new number and their pr field says it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
models-and-cost.md still said the list opens on the model in use, in the
picker paragraph and in the sort-key section, while commands.md said /model
opens on the first row. Both now say what the code does: /model opens on the
first row, and the doors that open to confirm open on the model they hold.
Two comments that cited the old rule are corrected, and picker.follow says
why the keystroke-time callers may pass a row count as their line budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AbirAbbas and others added 2 commits October 1, 2026 11:03
Opening /model on the first row made Enter switch models without a choice,
and a refreshed task list could replace the task's confirmation model.
Every model door now opens and refreshes on the model it holds, visibly on
screen. A missing held model falls back to the first selectable row.

The window still counts screen lines, including service and machine
headings and reason lines. Opening a fold keeps preceding context when
it fits and scrolls by the least otherwise, with the cursor kept visible.

Settings slot and role lists, home's draft list and the task composer's
list now own wheel gestures while open and leave the page beneath still.
The manual and change entries describe confirmation, refresh, wheel
ownership and the current model's bold accent without a band of its own.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AbirAbbas

Copy link
Copy Markdown
Collaborator

Taking over: checked by hand in the real binary at 120, 62 and 50 columns, with and without a second service heading. The no-band mark and the wheel work as described. One thing did not hold: after /model, pressing Enter by habit switched the conversation to the alphabetically first model (aion-labs/aion-2.0, a 131k window). The screen-line scroll alone keeps the model in use on screen. Before this branch, a heading could push it off the frame on open.

  • 5ef949a25 — /model and every model door open on the model they hold again, so Enter with nothing moved confirms the model in use. The screen-line follow keeps that row visible on the first frame. A refresh landing returns the cursor to the held model, so a task's model list no longer drifts to the first row under a refresh. A missing held model falls back to the first selectable row. The test edits that only walked the cursor to the model in use are back to their dev text. Also in this commit:
    • The wheel now walks the settings slot/role list, home's draft list and the task composer's list. Before, it moved the page underneath them: the settings cursor slid from reflex to consolidate behind an open list.
    • Opening a fold scrolls by the least instead of always jumping the model row to the top.
    • The manual pages and both change entries say all of this. The cursor entry is renamed 1696-model-menu-cursor-on-screen.md.
  • d0e867536 — merge of current dev.

Left for later: under NO_COLOR the model in use has no mark at all (no bold, no glyph). That is the same on dev and is not a regression, but it is worth a glyph from tokens.

@AbirAbbas AbirAbbas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified by hand in the real binary (120/62/50 columns, with and without a service heading). Merging.

@AbirAbbas
AbirAbbas merged commit 41ffc27 into dev Oct 1, 2026
4 checks passed
@AbirAbbas
AbirAbbas deleted the zeropoint95/model-menu-current-row-and-wheel branch October 1, 2026 15:22
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