hermes - ✅(Solved) Fix Bug: TUI transcript scroll can blank after virtual row height cache drift [1 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#19944Fetched 2026-05-05 06:04:13
View on GitHub
Comments
2
Participants
2
Timeline
9
Reactions
0
Author
Participants
Timeline (top)
labeled ×3commented ×2renamed ×2cross-referenced ×1

In hermes --tui, scrolling back through a long transcript can show blank regions or skip older content after the conversation continues for several more turns.

The likely issue is virtual-row height cache drift: a row can be measured while it is still in the recent full-render tail, then later render much shorter after it leaves the tail and switches to bounded-history rendering.

Root Cause

Rows inside FULL_RENDER_TAIL_ITEMS render fully. Older assistant rows render through bounded history via limitHistoryRender / boundedHistoryRenderText().

useMainApp.ts builds virtual row keys from message identity/content only, while useVirtualHistory.ts caches measured/estimated heights by that key. A long assistant row can therefore be cached at its full-tail height, then later leave the tail and render much shorter without getting a new virtual-height identity.

That stale full-height measurement makes the virtual offset map overestimate content height, which can push the viewport/clamp into spacer regions.

Relevant paths:

  • ui-tui/src/components/appLayout.tsx
  • ui-tui/src/app/useMainApp.ts
  • ui-tui/src/hooks/useVirtualHistory.ts
  • ui-tui/src/lib/virtualHeights.ts
  • ui-tui/src/config/limits.ts

Fix Action

Fixed

PR fix notes

PR #19948: fix(tui): include render-mode in virtual row key to prevent height cache drift

Description (problem / solution / changelog)

Fixes #19944

Root cause: virtualRows built row keys using only message identity (messageHeightKey + seq). When a row crossed the FULL_RENDER_TAIL_ITEMS boundary from full-tail rendering to bounded-history rendering, its key was unchanged but its true rendered height was shorter. The height cache retained the stale full-tail measurement, causing the virtual offset map to overestimate content height and push the viewport into blank spacer regions when scrolling back.

Fix: Append :t (in-tail) or :b (bounded) to each row key in the virtualRows useMemo. When a row crosses the tail boundary it gets a new cache key, forcing the height estimator to re-run with the correct limitHistory value.

Files changed:

  • ui-tui/src/app/useMainApp.ts: virtualRows key includes render-mode suffix

5 new regression tests in ui-tui/src/tests/virtualRowRenderModeKey.test.ts, all passing.

Changed files

  • plugins/kanban/dashboard/plugin_api.py (modified, +4/-4)
  • tests/plugins/test_kanban_dashboard_plugin.py (modified, +4/-4)
  • ui-tui/src/__tests__/virtualRowRenderModeKey.test.ts (added, +76/-0)
  • ui-tui/src/app/useMainApp.ts (modified, +11/-1)
RAW_BUFFERClick to expand / collapse

Hermes TUI: transcript scroll can blank after rows leave the full-render tail

Summary

In hermes --tui, scrolling back through a long transcript can show blank regions or skip older content after the conversation continues for several more turns.

The likely issue is virtual-row height cache drift: a row can be measured while it is still in the recent full-render tail, then later render much shorter after it leaves the tail and switches to bounded-history rendering.

Reproduction

  1. Start hermes --tui.
  2. Build a long conversation that includes at least one long assistant response.
  3. Continue for several more turns so older rows leave the last FULL_RENDER_TAIL_ITEMS rows.
  4. Scroll back through transcript history.

Expected

Older transcript content remains visible and scrollable. Virtual-scroll offsets continue to match the actual rendered row heights as rows move from full-tail rendering to bounded-history rendering.

Actual

Scrolling back can land in blank spacer regions or skip older content, while recent tail content remains visible.

Root cause

Rows inside FULL_RENDER_TAIL_ITEMS render fully. Older assistant rows render through bounded history via limitHistoryRender / boundedHistoryRenderText().

useMainApp.ts builds virtual row keys from message identity/content only, while useVirtualHistory.ts caches measured/estimated heights by that key. A long assistant row can therefore be cached at its full-tail height, then later leave the tail and render much shorter without getting a new virtual-height identity.

That stale full-height measurement makes the virtual offset map overestimate content height, which can push the viewport/clamp into spacer regions.

Relevant paths:

  • ui-tui/src/components/appLayout.tsx
  • ui-tui/src/app/useMainApp.ts
  • ui-tui/src/hooks/useVirtualHistory.ts
  • ui-tui/src/lib/virtualHeights.ts
  • ui-tui/src/config/limits.ts

Suggested fix

Include the row render mode in the virtual-height identity, or invalidate/re-key cached heights when a row crosses the full-render-tail boundary.

A focused regression should cover a long assistant row measured as a tail row, then aged into bounded-history mode after appending more messages, ensuring the old full-height measurement is not reused.

extent analysis

TL;DR

Update the virtual-height identity to include the row render mode to prevent stale height measurements.

Guidance

  • Review useVirtualHistory.ts and virtualHeights.ts to understand how virtual row heights are cached and updated.
  • Consider adding a render mode parameter to the virtual row key in useMainApp.ts to differentiate between full-tail and bounded-history rendering.
  • Investigate how to invalidate or re-key cached heights when a row crosses the full-render-tail boundary, as suggested in the issue.
  • Test the fix with a focused regression that covers a long assistant row measured as a tail row, then aged into bounded-history mode.

Example

No code example is provided due to the complexity of the issue and the need for a thorough understanding of the codebase.

Notes

The fix may require updates to multiple components, including appLayout.tsx, useMainApp.ts, useVirtualHistory.ts, and virtualHeights.ts. Thorough testing is necessary to ensure the fix does not introduce new issues.

Recommendation

Apply the suggested fix to update the virtual-height identity and invalidate cached heights when a row crosses the full-render-tail boundary, as this approach addresses the root cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING