Repository navigation
Fix: Make Enter in the agents picker always scope to the highlighted row - #1224
Conversation
Enter on the agent already scoped cleared the scope instead of applying it again, so one row in the picker meant "show me everything" while every other row meant "show me this agent". Picking claude-code while already scoped to it switched to every agent's sessions and spend. The footer did say `[↵] all agents` on that row, but it read as a description of the current view, not as what the key would do. Enter now always applies the highlighted row. A new first row, All agents, is the one way to clear the scope. It is added when the table is built rather than to pickerRows, which stays the partition of the sessions list that the two-agent gate and the Other row reason about. Its figures are blank: the band above already shows the window's total, and summed across agents billing in different units it would only read as mixed. At startup the cursor now opens on All agents, so Enter there keeps every agent in view, the same as esc. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 25 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (8)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
mrsabath
left a comment
There was a problem hiding this comment.
Good fix for a genuine UX trap, and the reasoning in the new allAgentsLabel doc comment is the kind that makes the next change to this pane safe.
What I verified independently:
- The off-by-one is correct.
selectedAgentScopemapsi == 0to the cleared scope andiin[1, len(picker)]topicker[i-1], with the upper bound asi > len(picker)rather than>=— right, since indexlen(picker)is the last valid element. All eight shifted test fixtures line up. - The row placement is the load-bearing decision, and it is right.
agentsPaneAppliesgates onm.agents, not on table rows. Had All agents gone intopickerRowsinstead, a single-agent deployment would have had two rows and the picker would have begun opening at startup for every user — precisely the cost that function's doc says it exists to avoid. Putting it inrebuildAgentsTable, one layer further out than the Other row, is coherent: Other partitions the sessions list, All agents partitions nothing. - No stale callers. Both production callers of the renamed
selectedAgentLabelare updated, and nothing else referenced it.
Tests are assertive rather than decorative: EnterOnAllAgentsClearsTheScope checks both the first row's label and len(m.agents)+1, which guards the off-by-one directly.
One small test-coverage regression
The old TestAgentsPane_FooterSaysWhichWayEnterWillGo carried a negative assertion — an unscoped row must not say "all agents". The replacement FooterSaysWhatEnterWillShow is positive-only, so it would still pass if the footer somehow said both strings at once. Cheap to restore as a notWant field on the table.
On the startup change
The cursor opening on All agents is documented in both the README and the commit message, and it is defensible — ↵ and Esc now agree on that row. Worth watching for feedback, since picking an agent at startup is the common case and now costs an extra ↓.
Areas reviewed: Go (agentop TUI: picker rows, key handling, footer, help overlay), tests, docs, commit conventions
Commits: 1, signed off ✅
CI status: all passing (26 pass, 1 skipped)
| all = append(all, "") | ||
| } | ||
| rows = append(rows, all) | ||
| for _, a := range picker { |
There was a problem hiding this comment.
suggestion: this row is now index 0, and the cursor is preserved across rebuilds by index — rebuildAgentsTable ends in setCursorVisible(&m.agentsTbl, cursor). Meanwhile agentRowsFromBuckets orders rows by usage.SortSeriesLabels (cost-ranked), so the order genuinely changes as spend accrues, and app.go:1385 rebuilds on a background refresh while the reader is standing on the pane.
Before this change that drift was harmless: it moved the cursor between agents, and Enter still scoped to whatever was highlighted. Now index 0 is a semantically different action, so drift can leave a reader on All agents where Enter clears the scope — the same surprise this PR removes, reached by another route. It is also reachable via Esc-then-A, since enterAgentsOrRefuse does not reset the cursor either.
Narrow, pre-existing in its mechanism, and still better than the toggle it replaces, so not blocking. But it might be worth re-anchoring the cursor on the currently scoped agent when the pane opens, which would make Esc-then-A-then-Enter a no-op the way a reader would expect.
| all := table.Row{allAgentsLabel, "", "", ""} | ||
| if withSessions { | ||
| all = append(all, "") | ||
| } |
There was a problem hiding this comment.
nit: the All agents row appends the SESSIONS cell at the end, while the agent rows below insert it at position 1 (append(r[:1:1], append(table.Row{...}, r[1:]...)...)). Both render identically today because every added cell here is "", so this is cosmetic only — but the two rows in one table being built against different column orders is the kind of thing that stops being harmless the moment one of these cells gains content.
Summary
In agentop's AGENTS picker, Enter on the agent already scoped cleared the scope instead of applying it again. So one row meant "show me everything" while every other row meant "show me this agent". Picking claude-code while already scoped to it switched to every agent's sessions and a spend band that included Bobcoins. The footer did say
[↵] all agentson that row, but it read as a description of the current view, not as what the key would do.Enter now always applies the highlighted row, and a new first row, All agents, is the one way to clear the scope.
Changes
tui/agents_pane.go:rebuildAgentsTableadds the All agents row.selectedAgentLabelbecomesselectedAgentScope() (scope string, ok bool), where cursor 0 is"".pickerRows.pickerRowsstays the partition of the sessions list thatagentsPaneAppliesand the Other row reason about, and this row partitions nothing.tui/keys.go: Enter setsagentScopeto the highlighted row's scope, and the toggle branch is gone. The footer reads[↵] all agentsonly on the All agents row and[↵] scope to this agenton every agent row, including the scoped one.tui/help_overlay.go,README.md: the binding now reads "scope to this agent; All agents clears".Behaviour change at startup: the picker's cursor now opens on All agents, so Enter there keeps every agent in view, the same as esc. Picking an agent at startup takes one ↓ first.
Tests
TestAgentsPane_EnterOnTheScopedAgentClearsTheScopeis replaced by…KeepsTheScope. There are also newTestAgentsPane_EnterOnAllAgentsClearsTheScopeandTestAgentsPane_FooterSaysWhatEnterWillShow(covering the scoped agent, another agent and All agents).GOWORK=off go vet ./...andgo test ./...pass forcmd/agentop, andgofmt -lis clean. As in Fix: Add IBM Bob's rate to configs written before the preset had it #1219,TestRunExec_BeforeFirstStartRunsAndSaysWhatIsLostfails in a shell withSSL_CERT_FILEset by an installed Cortex and passes with it unset; that is unrelated to this change.Also run against a live local proxy by driving the built binary through a pty. Picking claude-code, then pressing Enter on it again, stayed on
agent=claude-codewith a USD-only band. Enter on All agents brought back the bob-shell session and the Bobcoins.Assisted-By: Claude (Anthropic AI) noreply@anthropic.com