interactive: snap to bottom after /sessions load

Loading a session via the /sessions dialog used to park the viewport
on the last user turn, intended to show "where you left off". In
practice users open /sessions to resume work and expect to land at
the live tail of the conversation, not somewhere mid-scroll.

Replace the scrollToLastTurn call in applySessionSelection with
scrollToBottom so a /sessions resume snaps to the latest message.
The CLI startup paths (--continue, --resume, --session) still park
on the last turn since they're a different entry point with a
different mental model (boot into a saved session vs. switch
sessions during an active run).
This commit is contained in:
patriceckhart 2026-04-27 15:31:09 +02:00
parent 8e92c62e54
commit 4b2bce3fb2

View file

@ -2264,15 +2264,8 @@ func totalTurnsLocked(msgs []provider.Message) int {
}
// applySessionSelection loads the given session via the cli-provided
// callback and parks the viewport on the last turn so the user lands
// looking at where the conversation left off (their last prompt at the
// top of the chat, the assistant's last reply right below). Older
// history is one scroll up; pgdn or end snaps to the current tail.
//
// Without this, scrollOffset stayed at 0 (pinned to the live tail),
// which on a long resumed session showed only the last few rows of
// the final assistant message — the user read that as "only one liner
// happened, the resume didn't work".
// callback and snaps the viewport to the bottom (the latest message)
// so the user lands at the live tail of the resumed conversation.
func (i *Interactive) applySessionSelection(path string) {
if i.cfg.LoadSession == nil {
i.mu.Lock()
@ -2293,17 +2286,12 @@ func (i *Interactive) applySessionSelection(path string) {
i.parkedTurn = 0
i.parkedTotal = 0
i.view.InvalidateRenderCache()
// Pull the freshly-loaded transcript into the view so the anchor
// math below sees the post-resume messages, not the empty pre-load
// state. redraw() does the same on its next pass; we just front-run
// it here to compute the scroll target.
if i.agent != nil {
i.view.Messages = i.agent.Messages()
}
msgs := i.view.Messages
i.mu.Unlock()
i.scrollToLastTurn(msgs)
i.scrollToBottom()
}
// scrollToLastTurn parks the viewport at the most recent user turn,