fix(tui): preserve streaming scroll-follow across Ctrl+T thinking toggle#239
Open
alejandro-ao wants to merge 2 commits into
Open
fix(tui): preserve streaming scroll-follow across Ctrl+T thinking toggle#239alejandro-ao wants to merge 2 commits into
alejandro-ao wants to merge 2 commits into
Conversation
Pressing Ctrl+T to toggle thinking-token display during an active stream called the full _refresh redraw, which remounted every transcript block, tore down the live assistant/thinking StreamingTranscriptMessageWidget, and reflowed the layout so watch_scroll_y flipped _follow_output and snapped the viewport back to the bottom. This re-regressed the smooth bottom-follow scroll restored in #175 / PR #177. While an agent turn is running, toggle thinking incrementally instead: TranscriptView.apply_thinking_visibility reconciles only the thinking widgets against state.items, never remounting the active assistant streaming widget, and preserves _follow_output across the reflow via a suppress guard plus a deferred settle-follow-scroll callback. The idle toggle still uses the full _refresh redraw. Adds regression tests for follow-scroll, user scrollback, multi-block thinking, and the end-to-end streaming event path.
Explains the #175 re-regression, root cause (full redraw on toggle during streaming), the incremental apply_thinking_visibility fix, and how to test the regression suite.
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
Fix a re-regression of #175: pressing Ctrl+T to toggle thinking-token display during an active stream broke the smooth bottom-following scroll restored by #175 / PR #177. The toggle now reconciles thinking widgets incrementally while streaming instead of triggering a full transcript redraw.
Motivation / problem
While an assistant message is streaming and the viewport is pinned to the bottom, pressing Ctrl+T to show/hide thinking tokens stopped the smooth auto-follow scroll: the viewport either stopped following or jumped/snapped, and only recovered after the turn ended.
action_toggle_thinkingalways called_refresh()→TranscriptView.update_from_state()→_redraw(), which does a fullremove_children()+ remount of every transcript block. During an active turn that:_active_assistant_widget/_active_thinking_widget(reset toNone), so the next streamed delta mounts a fresh assistant widget (visible jump / lost incremental markdown stream) — the "thinking stream appears in a different way" symptom.scroll_y, andTranscriptView.watch_scroll_yinterprets that as a user scrollback and flips_follow_output = False, snapping the viewport back to the bottom.This is exactly the "scroll state reset during token deltas" failure mode #175 warned about. The earlier "Reduce transcript toggle latency" change (
ae42fd0f) optimized the toggle for the idle transcript and didn't account for the toggle firing mid-stream.What changed
TranscriptView.apply_thinking_visibility(state, theme)reconciles only the thinking-related widgets againststate.itemsthinking blocks, never remounting the active assistant streaming widget so its incremental markdown stream stays intact.TranscriptMessageWidgetblocks, liveStreamingTranscriptMessageWidgetblocks, and the hidden-thinking placeholder), then mount a fresh widget for eachthinkingitem ordered ahead of the assistant widget.StreamingTranscriptMessageWidget(item)re-renders the fullitem.texton mount, and the next thinking delta continues appending to the freshly assigned active widget._follow_outputis snapshotted,_suppress_follow_updatemakeswatch_scroll_yignore layout-induced scroll movement during the reconcile, and acall_after_refreshcallback restores_follow_outputand re-requests the bottom-follow scroll after layout settles. A mid-stream toggle therefore does not change follow mode.action_toggle_thinkinguses the incremental path whilestate.running, and keeps the full_refresh()redraw for the idle case. The reconcile is synchronous (fire-and-forgetmount/remove_children, matching_redraw) so it stays atomic with respect to the streaming worker.Acceptance criteria / verification
Regression tests in
tests/test_tui_app.py:test_tui_thinking_toggle_during_stream_preserves_follow_scrolltest_tui_thinking_toggle_during_stream_preserves_user_scrollbacktest_tui_thinking_toggle_during_stream_keeps_all_thinking_blockstest_tui_thinking_toggle_via_event_stream_preserves_assistant_widgetAll 610 tests pass, ruff + mypy clean.
Related files or areas
src/tau_coding/tui/widgets.py—TranscriptView.apply_thinking_visibility,_show_streaming_thinking,_hide_streaming_thinking,_remove_thinking_widgets,watch_scroll_y,_suppress_follow_updatesrc/tau_coding/tui/app.py—action_toggle_thinkingtests/test_tui_app.py— new regression testsdev-notes/architecture/fix-thinking-toggle-stream-scroll.mdNotes
ae42fd0f,cb488805/a5dff600/19e4c498.