Repository navigation
feat(app): add session turn navigator - #54088
Closed
opencode-agent[bot] wants to merge 7 commits into
Closed
opencode-agent[bot] wants to merge 7 commits into
opencode-agent[bot] wants to merge 7 commits into
Conversation
1 task done
This was referenced Oct 11, 2026
Open
Contributor
|
Pushed
|
Brendonovich
force-pushed
the
turn-navigator
branch
from
October 14, 2026 13:56
9659f85 to
ff3c4a0
Compare
Brendonovich
enabled auto-merge (squash)
October 14, 2026 13:57
1 task done
1 task done
This was referenced Oct 21, 2026
This was referenced Oct 27, 2026
Closed
auto-merge was automatically disabled
November 6, 2026 10:27
Pull request was closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a turn navigator to the left edge of the session timeline: one tick per user turn. Hovering a tick previews the prompt and the end of the agent's latest reply. Clicking a tick jumps to the turn. The tick for the turn you're reading is highlighted as you scroll. Hovering the rail widens it: the hover area grows from 20px to 36px, every tick doubles in length, and the hovered tick is longest. Tick spacing stays fixed, so the tick under the cursor doesn't move away.
Data loading
GET /api/session/:id/message?type=user(asc, 200 per page). The filter runs in SQL on the existing(session_id, type, seq)index, so the rail lists every turn without fetching the whole transcript. When the loaded tail already reaches the start of the session, no index request is made.assistantMessagesByParentprojection.type=assistant&before=<next turn's user message>&limit=1. Replies are cached per turn, and sweeping across the rail fetches nothing.beforequery parameter onGET /api/session/:id/message: it returns the newest-first page of messages preceding a message (exclusive). The store already supports this through its cursor anchor, so the handler mapsbeforeonto the existing{ id, direction: "next" }cursor. Combining it withcursorororder=ascreturnsInvalidCursorError. The client is regenerated.packages/protocol/openapi.jsonis not regenerated because it is already about 1,100 lines out of date onv2and regenerating it would add unrelated churn.loadMoreuntil the turn arrives, then scrolls to it. This is the same cost as scrolling there today. It needs no new server API.Notes
aria-hiddenand does nothing without a mouse. Keyboard users already have the previous/next message commands (mod+alt+[/mod+alt+]).activeUserMessageID. It's computed from the row at a reading line just below the sticky header, on scroll, with onegetVirtualItemForOffsetbinary search.type-filtered message lists, withbefore, through a newmessageIndexhook. Without the hook, typed lists return nothing, so existing paging assertions are unaffected.Possible follow-ups
around=<messageID>, plus a client store that can hold separate loaded ranges, would let a jump to an old turn skip the pages in between.files[].datawith the index.Testing
bun run typecheckandbun test ./src/sessioninpackages/apppass.packages/server/test/message.test.ts: added cases forbeforewith type filters, the continuation cursor, an anchor with no earlier matches, and rejection when combined withcursorororder=asc.timeline-historykeeper suite covers:timeline-historysuite passes on the final revision. Thetimeline-cache,timeline-geometry,timeline-stream,session-timeline-accessibility,mobile-timeline-scroll,session-headerandcommand-palettesuites passed on an earlier revision.bench:entryandbench:tabsscenarios, built app, interleaved base/after runs, 12 repeats each, on a shared, noisy host. Final medians,firstCorrectObservedMs:firstCorrectObservedMsthenstableObservedMs: cold entry 363 / 444 ms, cold tab switch 181 / 220 ms, warm tab switch with review open 64 / 115 ms. The interleaved base runs above were 367 / 453, 191 / 220 and 61–67 / 110–128 ms.Requested by: @Brendonovich (Brendan via Slack)