Repository navigation
Description
Description
Title: Session history replay truncates after edit-and-resend of a message on legacy-schema long sessions (data intact, UI stops rendering earlier checkpoint)
Labels (suggestion): bug, desktop, maybe triage
Bug description
In a long-running session (2 days old, legacy storage structure predating the part migration), using the retract / edit-and-resend action on an earlier user message caused the session history replay (UI) to stop rendering at a much earlier checkpoint — every agent message after that old checkpoint is invisible in the UI, including the re-sent message itself.
Important: this is display-only. The agent's internal context kept working correctly, all subsequent tool calls and file changes happened, and everything is present in local storage (opencode.db). Nothing is lost — only the history replay in the UI no longer shows the tail of the conversation.
Reproduction in a fresh short session failed (session stored in the new part schema), which suggests the trigger is the combination of (a) legacy session_message-stream sessions and (b) the revert flow created by edit-and-resend.
Environment
- OpenCode: 2.2.5 (desktop client, latest channel)
- OS: Windows 11 x64
- Client: desktop app; HTML preview opened via Review pane
- Affected session profile: 2 days of activity, ~30 user/agent exchanges, 22+ background subagent dispatches (incl. 1 task_cancel, 1 task_revive), local sqlite
opencode.dbgrew to ~11.8 GB
Steps to reproduce
- Continue a long-running session created before the
session_part/partstorage migration (its messages live in the legacysession_messagestream table), with heavy tool/subagent activity. - Use retract / edit-and-resend on an earlier user message (a
session.revert.stage→session.revert.commitflow; the re-sent message gets a new message id). - Continue normally for 10+ exchanges (agent replies, tools run).
- Reopen the session view / scroll back through history.
- History replay stops at an agent message from before the revert; all later messages (including the re-sent one and subsequent agent replies) are missing from the UI.
Expected vs Actual
- Expected: replay shows the resent message and everything after it.
- Actual: replay stops at a stale checkpoint; tail of the conversation is invisible in UI, while the agent continues working and storage records everything.
Evidence from local storage (SQLite opencode.db, read-only queries)
For the affected session:
-- message stream intact and contiguous:
SELECT COUNT(*) FROM session_message WHERE session_id = '<affected-session-id>'; -- 503 rows, seq spans normally
-- legacy schema: no rows in the migrated structures for this session:
SELECT COUNT(*) FROM message WHERE session_id = '<affected-session-id>'; -- 0
SELECT COUNT(*) FROM session_part WHERE session_id = '<affected-session-id>'; -- 0Server log confirms the flow on the affected session:
session.revert.stage messageID=msg_<retracted-message-id> (retract action)
session.revert.commit (few minutes later)
-- subsequent exchanges got new message ids and appended to the stream normally
So the launcher-side data is complete; the replay UI does not render it.
Hypothesis (unverified)
The history replay renderer reads the migrated part-based chain (or an inconsistent subset) instead of the legacy session_message stream for sessions that still live in the old schema — reverting/branching on such a session moves the expected chain beyond what the renderer walks, so it renders up to a stale checkpoint.
Impact & workaround
- Impact: audit/history view only (display misled the user into thinking the conversation was lost). Agent execution, storage, and disk artifacts are unaffected; the current-position view (newest messages) still works while streaming.
- Suggested workaround: avoid edit-and-resend on legacy sessions; start a fresh message instead.
Activity
opencodejr commentedon Nov 2, 2026
Thanks for the detailed report. I couldn't reproduce this here: it happens in the Windows desktop app, which our automated sandbox can't run, so it needs a maintainer with the desktop app.
A possible cause: after a revert is committed, the desktop client decides where to cut the loaded history by comparing message IDs as text, not by their real order. That cuts in the wrong place in some sessions and can hide newer messages, which would match what you saw. #57581 (an open PR, not merged yet) changes this to use the real message order. One correction:
session_messageis the current table, not a legacy one, so the old-schema explanation in the report probably isn't the cause.Two things would help:
Related:
LDecem commentedon Nov 2, 2026
It happened in a master session, not a forked one. Not-relevant to any iOS app nor Android app.
Restarting or re-opening not done yet - tasks still running. Maybe later.
sayan1999 commentedon Nov 2, 2026
I have same behaviour in my Mac Os Opencode TUI
In my case observation:
Apparently the internal context stays intact and a restrat of the opencode session revives the right history on the UI as it should be at.
dhaern commentedon Nov 9, 2026
Same here on the TUI with OpenCode 2.2.6 on Linux, in long sessions that were never forked and have no iOS messages. In my case plugins are the trigger: oh-my-opencode-slim posts synthetic messages with IDs like
msg_omos_<uuid>, and magic-context posts reminders withmsg_<24 random hex>. Compared as strings, both sort after every nativemsg_<time>ID. If one of them sits anywhere before the user message you revert, the TUI hides it while the revert is staged, and on commit thesession.revert.committedhandler cuts the loaded transcript from that synthetic message onward. The server deletes byseq, so the database and the model's context stay correct, and as reported above, reopening the session restores the view. In my local database 3,061 of 14,281 user messages have an earlier message whose ID sorts after theirs, so any long session with these plugins can hit this. #57581 orders by position and covers both the TUI filter and the committed cut.