Skip to content

TUI: Long assistant responses become unreachable after scrolling out of view (virtual scroll clamp + sticky scroll interaction) #55594

Description

@HirotakeMachiyama

Bug Description
In the Hermes Desktop TUI (React Ink), long assistant responses scroll out of the visible viewport and become unreachable. The user perceives the response as having "disappeared" with no way to retrieve it.

This is the #1 reported UX frustration from daily use.

Root Cause
Three mechanisms interact to cause this:

  1. Virtual Scroll Clamp (hooks/useVirtualHistory.ts + render-node-to-output.ts)
    The ScrollBox renders a virtual window of MAX_MOUNTED=120 items at a time. The user's scroll position is clamped via setClampBounds() (render-node-to-output.ts:856-864) to stay within the mounted range. When the user scrolls faster than React can mount new items (SLIDE_STEP=12 items/commit), the clamp holds the viewport at the edge of mounted content — everything beyond renders as blank spacer.

  2. Sticky Scroll (packages/hermes-ink/src/ink/components/ScrollBox.tsx:175-187)
    Every new message triggers scrollToBottom(), setting stickyScroll=true. If a user manually scrolls up to re-read a long response, the next incoming message instantly forces the viewport back to the bottom. There is no cooldown period after manual scroll activity.

  3. History Cap (app/useMainApp.ts:54-60)
    MAX_HISTORY=800 silently drops the oldest messages when exceeded. Not the immediate issue but worsens over long sessions.

Reproduction
Ask Hermes a question that produces a multi-screen response (tables, code blocks, analysis)
Send a follow-up message
Try to scroll back to re-read the original response
The response is either clamped at the edge of the mounted range or auto-scrolled back to the bottom
Proposed Fixes
Increase MAX_MOUNTED from 120 to 300+ (or make it configurable via config.yaml)
Add a cooldown period (2-3s) after manual scroll during which sticky scroll is suppressed
Consider auto-saving long assistant responses (>1 screen) to a temp file with an in-TUI notice
Affected Files
ui-tui/src/config/limits.ts — MAX_HISTORY, MAX_MOUNTED constants
ui-tui/src/hooks/useVirtualHistory.ts — virtual window computation + clamp bounds
ui-tui/packages/hermes-ink/src/ink/render-node-to-output.ts — scroll clamp logic (lines 856-864)
ui-tui/src/app/useMainApp.ts — capHistory function (lines 54-60)
ui-tui/packages/hermes-ink/src/ink/components/ScrollBox.tsx — stickyScroll behavior (line 175)
Environment
Hermes Desktop GUI (TUI)
macOS 26.5.1
Model: deepseek-v4-flash

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/tuiTerminal UI (ui-tui/ + tui_gateway/)type/bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions