You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
tui: scrolling up through a reply jumps the view into the thinking block above it #58666
When scrolling up through a session with thinking shown, the view jumps as the thinking block above a reply comes into view. A single wheel step skips the whole thinking block and lands on its "Thought" header, instead of moving a few rows like every other step. This happens every time a thinking block comes into view, and it makes it hard to keep your place while reading back through a session.
The screenshot shows three consecutive states, each one wheel step apart, left to right:
Reading the reply to turn 19.
One wheel step later, the view has moved 3 rows as expected. The "19. Cost of the limiter itself" heading is at the top.
One more wheel step, and the view jumps about 23 rows to the start of turn 19's thinking. The whole thinking block is skipped.
I first noticed this in my normal setup. It reproduces on a clean install with no plugins, where the only config change is the thinking setting below.
Plugins
None (reproduced with no plugins)
OpenCode version
2.1.4
Steps to reproduce
Set session.thinking to "show" in cli.json.
Open a session with several turns where each assistant reply has a thinking block before it.
Scroll up slowly from the bottom, one wheel step at a time.
When the thinking block above a reply comes into view, the view jumps to the start of that thinking block in a single step.
Thanks for the clear report! I could reproduce this on 2.1.4, and it still happens on the latest dev (f20760b8).
Steps: set session.thinking to "show", create a session with 20 turns where each reply has a thinking block before it, then scroll up from the bottom one wheel step at a time. For the newest ~10 turns, each step moves ~3 rows. Further back, a single step goes from the first lines of a reply straight to the start of the thinking block above it, skipping the rest of the block, and the next step shows the "Thought" header. The recording below shows the full run, and the script below reproduces it.
The jumps start where older messages begin to be loaded into the view as you scroll up, so the code that adds those rows above the current view is the likely cause. #54158 touches the same code and may be related.
recording.mp4Reproduction script (drive.ts)
// Repro for anomalyco/opencode#58666: scrolling up one wheel step at a time// jumps over the thinking block above a reply.import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"constTURNS=20constthought=(n: number)=>Array.from({length: 6},(_,k)=>`Turn ${n} thought line ${k+1}: weighing the options carefully.`).join("\n\n")constreply=(n: number)=>Array.from({length: 10},(_,k)=>`Turn ${n} reply line ${k+1}.`).join("\n\n")// Text of the transcript area's rows, to see which line is at the top after each step.constframeText=(frame: any): string[]=>frame.lines.map((l: any)=>l.spans.map((s: any)=>s.text).join(""))exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tuiConfig: {session: {thinking: "show"}},tui: {recording: true,viewport: {cols: 120,rows: 40}},}asany,({ ui, llm })=>Effect.gen(function*(){for(letn=1;n<=TURNS;n++){yield*ui.submit(`Question ${n}`)yield*llm.send(Llm.reasoning(thought(n)),Llm.text(reply(n)))yield*Effect.sleep(700)}yield*ui.screenshot("bottom")yield*Effect.sleep(1000)letprevTop=""for(letstep=1;step<=330;step++){yield*ui.mouse({action: "scroll",x: 40,y: 15,direction: "up"})yield*Effect.sleep(120)constlines=frameText(yield*ui.capture())consttop=lines.slice(1,4).map((l)=>l.trim()).filter(Boolean).join(" | ")yield*Effect.log(`step ${step}: ${top.slice(0,200)}`)prevTop=top}voidprevTop}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
I'd like to work on this. Following the triage, the jump starts where older rows get loaded above the viewport while scrolling up, so I'll look at how the scroll offset is kept when those rows are prepended (and check #54158, which touches the same code). I'll add a regression test that scrolls up one step at a time through replies with thinking blocks.
Update: I can't reproduce this on current dev. I wrote an OpenTUI renderer test (20 and 30 turns, each with a reasoning part and a text part, session.thinking: "show", 100x30 and 120x40) that scrolls up one wheel step at a time and checks each step moves the view by exactly 3 rows. Every step does, including across the point where older rows get mounted.
The triage repro was on f20760b8. Since then #59236 ("stop older history from flashing when scrolling up") changed pinAbove, the older-row reveal and rows.ts, which is likely what fixed it. The default verbosity is also low now (#63207), which folds thoughts into a collapsed group.
My test loads the history in one fetch rather than streaming it live, so it doesn't cover everything the original script does. @ganyicz could you check whether it still happens on the latest release? If it does, I'll keep digging; if not, this can probably be closed.
Activity
opencode-agent commentedon Oct 24, 2026
Thanks for the clear report! I could reproduce this on 2.1.4, and it still happens on the latest
dev(f20760b8).Steps: set
session.thinkingto"show", create a session with 20 turns where each reply has a thinking block before it, then scroll up from the bottom one wheel step at a time. For the newest ~10 turns, each step moves ~3 rows. Further back, a single step goes from the first lines of a reply straight to the start of the thinking block above it, skipping the rest of the block, and the next step shows the "Thought" header. The recording below shows the full run, and the script below reproduces it.The jumps start where older messages begin to be loaded into the view as you scroll up, so the code that adds those rows above the current view is the likely cause. #54158 touches the same code and may be related.
recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.Anthony14FR commentedon Nov 12, 2026
I'd like to work on this. Following the triage, the jump starts where older rows get loaded above the viewport while scrolling up, so I'll look at how the scroll offset is kept when those rows are prepended (and check #54158, which touches the same code). I'll add a regression test that scrolls up one step at a time through replies with thinking blocks.
Anthony14FR commentedon Nov 12, 2026
Update: I can't reproduce this on current
dev. I wrote an OpenTUI renderer test (20 and 30 turns, each with a reasoning part and a text part,session.thinking: "show", 100x30 and 120x40) that scrolls up one wheel step at a time and checks each step moves the view by exactly 3 rows. Every step does, including across the point where older rows get mounted.The triage repro was on
f20760b8. Since then #59236 ("stop older history from flashing when scrolling up") changedpinAbove, the older-row reveal androws.ts, which is likely what fixed it. The default verbosity is alsolownow (#63207), which folds thoughts into a collapsed group.My test loads the history in one fetch rather than streaming it live, so it doesn't cover everything the original script does. @ganyicz could you check whether it still happens on the latest release? If it does, I'll keep digging; if not, this can probably be closed.