Skip to content

fix(tui): restore clean agent thread replay and streaming#15312

Open
fcoury wants to merge 9 commits intoopenai:mainfrom
fcoury:fix/15001-agent-thread-corruption
Open

fix(tui): restore clean agent thread replay and streaming#15312
fcoury wants to merge 9 commits intoopenai:mainfrom
fcoury:fix/15001-agent-thread-corruption

Conversation

@fcoury
Copy link
Contributor

@fcoury fcoury commented Mar 20, 2026

Summary

This fixes two independent corruption paths in agent thread views:

  • thread-snapshot replay now prefers the completed AgentMessageItem
    payload instead of rebuilding /agent views from stale legacy deltas
  • live streamed markdown now uses replaceable snapshots instead of
    incrementally appending invalidated line slices

Together, these changes stop long markdown-heavy agent outputs from
losing prefixes, path segments, or punctuation while viewing active or
replayed subagent threads.

What changed

  • ignore AgentMessageDelta during ReplayKind::ThreadSnapshot
    replay and rebuild the final agent message cell from the completed
    item payload
  • make MarkdownStreamCollector return the latest full committed render
    snapshot instead of only newly committed lines
  • update streaming controllers and commit-tick plumbing so in-flight
    message/plan output lives in active_cell until finalization
  • add regressions for replayed completed-agent-message precedence and
    for streamed markdown rewrites that previously corrupted earlier rows

Validation

  • cargo test -p codex-tui
  • just fix -p codex-tui

Note: per repo workflow, tests were run before the final just fix
pass and were not rerun afterward.

fcoury added 7 commits March 19, 2026 23:09
Prefer completed `AgentMessageItem` payloads during thread-snapshot
replay so `/agent` views rebuild from the final assistant text instead
of stale legacy delta state.

Backport the snapshot-based streaming pipeline so live agent output
replaces prior rendered content instead of appending invalidated line
slices. This keeps agent thread views stable for long markdown-heavy
messages.
Limit completed agent-message precedence to `ReplayKind::ThreadSnapshot`
so resume replays continue using streamed deltas without duplicating the
final assistant message.

Preserve pending snapshot enqueue timestamps across replacements so
catch-up mode still reflects the oldest unseen rewrite, and tighten the
terminal-title regression to exercise the real project-title path.
Request a redraw when commit ticks replace the visible streamed
cell so snapshot-based streaming updates paint immediately.

Add a compatibility fallback for `ReplayKind::ThreadSnapshot`
that uses `TurnComplete.last_agent_message` when older snapshots
lack a completed `AgentMessageItem`, while still preferring the
completed item when it exists.
Flush non-plan active cells before later plan deltas reclaim the
active slot so tool and status cells are inserted into history
instead of being overwritten by a mutable plan snapshot.

Defer a second controller snapshot when a commit tick can only show
one active cell. This keeps the pending update queued for the next
tick instead of draining and discarding it.
Track the last replayed assistant item text during thread-snapshot
replay and skip the `TurnComplete.last_agent_message` fallback when
it would insert the same content again.

This keeps compatibility for older snapshots that only preserve
`TurnComplete`, while avoiding duplicate commentary cells when both
a replayed item and echoed fallback text are present.
Flush non-stream active cells before a commit tick installs a new
stream snapshot into the active slot. This preserves transient tool and
status rows that would otherwise be overwritten by queued stream output.

Add a regression for the queued-plan then web-search path so commit
ticks keep the active search row in history before plan output reclaims
the active slot.
Flush a non-plan active cell before a finalized streamed plan takes
over the active slot. This keeps transient tool and status rows from
being overwritten when plan completion arrives.

Add a regression for the web-search plus plan-completion handoff so the
search row lands in history before the finalized plan is emitted.
Copilot AI review requested due to automatic review settings March 20, 2026 13:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes corruption in TUI agent-thread rendering by switching replay + streaming to prefer completed snapshots (instead of incremental/legacy deltas), ensuring markdown-heavy output doesn’t lose earlier text when later chunks rewrite wrapping/inline constructs.

Changes:

  • Thread-snapshot replay now ignores AgentMessageDelta and rebuilds assistant message cells from completed AgentMessageItem (or TurnComplete.last_agent_message fallback when needed).
  • Streaming markdown rendering now emits replaceable full committed snapshots; commit-tick plumbing is updated to surface a single active_cell snapshot instead of draining FIFO line queues.
  • Adds regressions covering snapshot replay precedence and streamed markdown rewrites (inline code closure + rewrap cases), plus commit-tick deferral behavior.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
codex-rs/tui/src/streaming/mod.rs Removes legacy StreamState queueing and updates module documentation/exports to reflect snapshot-based controllers.
codex-rs/tui/src/streaming/controller.rs Reworks stream/plan controllers to stage and emit full rendered snapshots; adds controller-level regression tests.
codex-rs/tui/src/streaming/commit_tick.rs Changes commit-tick output to a single active_cell snapshot with deferral between stream vs plan; adds unit tests for deferral/idle reporting.
codex-rs/tui/src/markdown_stream.rs Collector now returns the latest full committed render snapshot; updates tests and adds new rewrite regressions.
codex-rs/tui/src/chatwidget.rs Implements thread-snapshot replay rules (ignore deltas, prefer completed items), and updates active-cell/commit-tick integration.
codex-rs/tui/src/chatwidget/tests.rs Adds replay/duplication coverage and new active-cell redraw/flush sequencing tests; updates call sites for signature changes.
codex-rs/tui/src/app.rs Adds an integration-style test ensuring thread-snapshot replay prefers completed agent message items over deltas.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fcoury
Copy link
Contributor Author

fcoury commented Mar 20, 2026

@codex review

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 95500fdd6b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

fcoury added 2 commits March 20, 2026 13:04
Restore `ThreadSnapshot` replay for the trailing in-progress turn so
switching to an active agent thread still shows buffered assistant
deltas until a completed assistant payload arrives.

Port the snapshot-based streaming collector and controller behavior to
`tui_app_server` so both transcript paths share the same mutable
active-cell semantics and avoid stale incremental markdown slices.
Handle live `AgentMessageContentDelta` events as the source of truth for
assistant streaming so the transcript flushes the previous stream when a
new assistant message item begins.

This keeps live agent navigation aligned with replayed thread snapshots and
prevents the initial corruption that only corrected itself after switching
away and back. The app-server chat widget mirrors the same item-aware
behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants