Skip to content

fix(code): preserve transcript order during virtualization - #4549

Merged
Mason Daugherty (mdrxy) merged 5 commits into
mainfrom
johannes117/code/transcript-virtualization
Jul 8, 2026
Merged

fix(code): preserve transcript order during virtualization#4549
Mason Daugherty (mdrxy) merged 5 commits into
mainfrom
johannes117/code/transcript-virtualization

Conversation

@johannes117

@johannes117 Johannes du Plessis (johannes117) commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Fixes long dcode conversations so transcript virtualization preserves message order, keeps the scroll position stable when loading older history, and avoids older or newer messages disappearing when scrolling.


  • Make MessageStore the canonical source for virtualized transcript geometry with height estimates, protected live rows, and spacer-backed scroll ranges.
  • Keep rendered transcript rows chronological around spinner/queued widgets by mounting all transcript content above the bottom spacer.
  • Sync live tool state back into MessageStore so hydrated rows preserve status, output, expansion, and rejection details.
  • Hydrate the hidden tail before appending fresh output, and only advance _visible_end on append when already at the tail, so new live output never skips messages hidden below the window.

Correctness & robustness (review pass)

  • Fix scroll-anchor double-count on hydrate-above. The top spacer already shrinks by the hydrated rows' height, so scroll_y now stays put instead of jumping the viewport down by ~a screenful when scrolling up through history.
  • Keep the mounted window contiguous on partial failure. Both hydrate directions now mount from the window edge outward and stop at the first failure, so the count-based mark_hydrated/mark_hydrated_below can't desync _visible_start/_visible_end from the DOM.
  • Fail safe when syncing tool state. If a tool widget can't be serialized, its row stays protected (we can't prove it's terminal); an unknown/unmapped status no longer unprotects a still-live row. The adapter's tool-sync hook is now total (never raises), so a sync failure can't abort a turn.
  • Reason-keyed protection. MessageStore tracks protection reasons (active stream vs. live tool) independently, so releasing one source never revokes another's protection.
  • Remove dead/speculative API. Dropped MessageWindow, get_window_for_viewport, prefix_height, total_estimated_height, and get_protected_messages (unused by the feature); the live path uses estimate_height/range_height.
  • Single clamped write path for height_hint (set_height_hint), plus docstring/comment fixes for the now-populated height hints and protection semantics.

@github-actions github-actions Bot added dcode Related to `deepagents-code` fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: L 500-999 LOC labels Jul 7, 2026

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

Open in WebView Open SWE trace

Comment thread libs/code/deepagents_code/tui/widgets/message_store.py Outdated
@github-actions github-actions Bot added size: XL 1000+ LOC and removed size: L 500-999 LOC labels Jul 8, 2026
@mdrxy
Mason Daugherty (mdrxy) merged commit f6ee70c into main Jul 8, 2026
64 of 66 checks passed
@mdrxy
Mason Daugherty (mdrxy) deleted the johannes117/code/transcript-virtualization branch July 8, 2026 23:39
Mason Daugherty (mdrxy) added a commit that referenced this pull request Jul 9, 2026
> [!CAUTION]
> Merging this PR will automatically publish to **PyPI** and create a
**GitHub release**.

For the full release process, see
[`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md).

---

_Everything below this line will be the GitHub release body._

---


##
[0.1.35](deepagents-code==0.1.34...deepagents-code==0.1.35)
(2026-07-09)

### Features

* Restore interrupted prompt to input on ESC
([#4544](#4544))
([fccf037](fccf037))
* Add `[startup].mode` default approval mode
([#4573](#4573))
([7c5bf54](7c5bf54))
* Offer restart after saving Tavily key via `/auth`
([#4560](#4560))
([12df81a](12df81a))
* Reload env from `/auth` modal via Ctrl+R
([#4566](#4566))
([f07d638](f07d638))
* Toast on saved `/auth` API key
([#4558](#4558))
([ee3c264](ee3c264))

### Bug Fixes

* Harden approval content rendering
([#4581](#4581))
([38446fd](38446fd))
* Preserve transcript order during virtualization
([#4549](#4549))
([f6ee70c](f6ee70c))
* Run stdio MCP server pre-flight check off the event loop
([#4434](#4434))
([c9636e2](c9636e2))
* Avoid duplicate "criteria ready" message on `/goal` revisions
([#4559](#4559))
([1110497](1110497))
* Restore welcome banner tips
([#4528](#4528))
([3f1e55e](3f1e55e))
* Clarify managed `rg` install failures
([#4578](#4578))
([434c84a](434c84a))
* Dedupe update/install log path output
([#4553](#4553))
([1398fee](1398fee))
* Keep notification center open for API-key entry
([#4568](#4568))
([6e89417](6e89417))
* Queue `/mcp login` sent before the server connects
([#4533](#4533))
([edac82c](edac82c))
* Serialize MCP OAuth token refreshes to prevent reuse revocation
([#4565](#4565))
([c37100d](c37100d))

---

_Everything above this line will be the GitHub release body._

---

> [!NOTE]
> A **New Contributors** section is appended to the GitHub release notes
automatically at publish time (see [Release
Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline),
step 2).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Mason Daugherty (mdrxy) added a commit that referenced this pull request Jul 13, 2026
…4646)

Follow-up to #4549 (transcript virtualization).

Fixed older messages failing to load when scrolling up long
conversations in `dcode` with a trackpad, mouse wheel, or keyboard.

---

Scrolling up a long `dcode` thread with a trackpad (or wheel/keyboard)
never loaded older messages — the viewport parked in the blank top
spacer. Transcript virtualization triggered hydration only from
app-level `on_scroll_up`/`on_scroll_down` handlers bound to
`textual.scrollbar`'s `ScrollUp`/`ScrollDown` messages. Those messages
never fire for wheel/trackpad/keyboard scrolling (which scroll via
`MouseScroll*` events), and for scrollbar-track clicks they are
`bubble=False` and consumed by the `_ChatScroll` container's own handler
before they can reach the app — so hydration effectively never ran on
scroll.

Verified against Textual 8.2.7: a wheel scroll and a scrollbar-track
action both move `scroll_y` but invoke the app-level handler zero times.

This drives hydration off the actual scroll offset instead:
`_ChatScroll` posts a `Scrolled` message from `watch_scroll_y`, and the
app checks both hydration directions in `on_chat_scrolled`. That covers
every input device (wheel, trackpad, keyboard, scrollbar, programmatic)
uniformly.

Made by [Open
SWE](https://openswe.vercel.app/agents/0f94cbf2-4d61-e04a-9e7b-520902ec436d)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
…-ai#4549)

Fixes long `dcode` conversations so transcript virtualization preserves
message order, keeps the scroll position stable when loading older
history, and avoids older or newer messages disappearing when scrolling.

---

- Make `MessageStore` the canonical source for virtualized transcript
geometry with height estimates, protected live rows, and spacer-backed
scroll ranges.
- Keep rendered transcript rows chronological around spinner/queued
widgets by mounting all transcript content above the bottom spacer.
- Sync live tool state back into `MessageStore` so hydrated rows
preserve status, output, expansion, and rejection details.
- Hydrate the hidden tail before appending fresh output, and only
advance `_visible_end` on `append` when already at the tail, so new live
output never skips messages hidden below the window.

## Correctness & robustness (review pass)
- **Fix scroll-anchor double-count on hydrate-above.** The top spacer
already shrinks by the hydrated rows' height, so `scroll_y` now stays
put instead of jumping the viewport down by ~a screenful when scrolling
up through history.
- **Keep the mounted window contiguous on partial failure.** Both
hydrate directions now mount from the window edge outward and stop at
the first failure, so the count-based
`mark_hydrated`/`mark_hydrated_below` can't desync
`_visible_start`/`_visible_end` from the DOM.
- **Fail safe when syncing tool state.** If a tool widget can't be
serialized, its row stays protected (we can't prove it's terminal); an
unknown/unmapped status no longer unprotects a still-live row. The
adapter's tool-sync hook is now total (never raises), so a sync failure
can't abort a turn.
- **Reason-keyed protection.** `MessageStore` tracks protection reasons
(active stream vs. live tool) independently, so releasing one source
never revokes another's protection.
- **Remove dead/speculative API.** Dropped `MessageWindow`,
`get_window_for_viewport`, `prefix_height`, `total_estimated_height`,
and `get_protected_messages` (unused by the feature); the live path uses
`estimate_height`/`range_height`.
- **Single clamped write path for `height_hint`** (`set_height_hint`),
plus docstring/comment fixes for the now-populated height hints and
protection semantics.

---------

Co-authored-by: Mason Daugherty <mason@langchain.dev>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
> [!CAUTION]
> Merging this PR will automatically publish to **PyPI** and create a
**GitHub release**.

For the full release process, see
[`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md).

---

_Everything below this line will be the GitHub release body._

---


##
[0.1.35](langchain-ai/deepagents@deepagents-code==0.1.34...deepagents-code==0.1.35)
(2026-07-09)

### Features

* Restore interrupted prompt to input on ESC
([langchain-ai#4544](langchain-ai#4544))
([fccf037](langchain-ai@fccf037))
* Add `[startup].mode` default approval mode
([langchain-ai#4573](langchain-ai#4573))
([7c5bf54](langchain-ai@7c5bf54))
* Offer restart after saving Tavily key via `/auth`
([langchain-ai#4560](langchain-ai#4560))
([12df81a](langchain-ai@12df81a))
* Reload env from `/auth` modal via Ctrl+R
([langchain-ai#4566](langchain-ai#4566))
([f07d638](langchain-ai@f07d638))
* Toast on saved `/auth` API key
([langchain-ai#4558](langchain-ai#4558))
([ee3c264](langchain-ai@ee3c264))

### Bug Fixes

* Harden approval content rendering
([langchain-ai#4581](langchain-ai#4581))
([38446fd](langchain-ai@38446fd))
* Preserve transcript order during virtualization
([langchain-ai#4549](langchain-ai#4549))
([f6ee70c](langchain-ai@f6ee70c))
* Run stdio MCP server pre-flight check off the event loop
([langchain-ai#4434](langchain-ai#4434))
([c9636e2](langchain-ai@c9636e2))
* Avoid duplicate "criteria ready" message on `/goal` revisions
([langchain-ai#4559](langchain-ai#4559))
([1110497](langchain-ai@1110497))
* Restore welcome banner tips
([langchain-ai#4528](langchain-ai#4528))
([3f1e55e](langchain-ai@3f1e55e))
* Clarify managed `rg` install failures
([langchain-ai#4578](langchain-ai#4578))
([434c84a](langchain-ai@434c84a))
* Dedupe update/install log path output
([langchain-ai#4553](langchain-ai#4553))
([1398fee](langchain-ai@1398fee))
* Keep notification center open for API-key entry
([langchain-ai#4568](langchain-ai#4568))
([6e89417](langchain-ai@6e89417))
* Queue `/mcp login` sent before the server connects
([langchain-ai#4533](langchain-ai#4533))
([edac82c](langchain-ai@edac82c))
* Serialize MCP OAuth token refreshes to prevent reuse revocation
([langchain-ai#4565](langchain-ai#4565))
([c37100d](langchain-ai@c37100d))

---

_Everything above this line will be the GitHub release body._

---

> [!NOTE]
> A **New Contributors** section is appended to the GitHub release notes
automatically at publish time (see [Release
Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline),
step 2).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Marcelo5444 pushed a commit to Marcelo5444/deepagents that referenced this pull request Jul 30, 2026
…angchain-ai#4646)

Follow-up to langchain-ai#4549 (transcript virtualization).

Fixed older messages failing to load when scrolling up long
conversations in `dcode` with a trackpad, mouse wheel, or keyboard.

---

Scrolling up a long `dcode` thread with a trackpad (or wheel/keyboard)
never loaded older messages — the viewport parked in the blank top
spacer. Transcript virtualization triggered hydration only from
app-level `on_scroll_up`/`on_scroll_down` handlers bound to
`textual.scrollbar`'s `ScrollUp`/`ScrollDown` messages. Those messages
never fire for wheel/trackpad/keyboard scrolling (which scroll via
`MouseScroll*` events), and for scrollbar-track clicks they are
`bubble=False` and consumed by the `_ChatScroll` container's own handler
before they can reach the app — so hydration effectively never ran on
scroll.

Verified against Textual 8.2.7: a wheel scroll and a scrollbar-track
action both move `scroll_y` but invoke the app-level handler zero times.

This drives hydration off the actual scroll offset instead:
`_ChatScroll` posts a `Scrolled` message from `watch_scroll_y`, and the
app checks both hydration directions in `on_chat_scrolled`. That covers
every input device (wheel, trackpad, keyboard, scrollbar, programmatic)
uniformly.

Made by [Open
SWE](https://openswe.vercel.app/agents/0f94cbf2-4d61-e04a-9e7b-520902ec436d)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dcode Related to `deepagents-code` fix A bug fix (PATCH) internal User is a member of the `langchain-ai` GitHub organization size: XL 1000+ LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants