Summary
When a new prompt arrives while the previous turn left a trailing user leaf, OpenClaw merges that orphaned user content into the next prompt and moves the in-memory SessionManager leaf back to the parent. The file-backed transcript is not rewritten at that point.
That can leave the .jsonl transcript on disk with stale/orphaned user entries that no longer match the active in-memory branch. Later transcript rewrites or branch projections may then produce a current transcript with missing assistant turns or long runs of consecutive user messages, even though earlier backup files still contain those assistant turns.
Observed behavior
In a file-backed agent session:
- the session registry entry and session
.jsonl existed
- the current transcript contained multiple consecutive
user message entries
- assistant replies that had previously been persisted were no longer present in the active
.jsonl
- backup
.jsonl.bak-* files still contained some of the missing assistant entries
- logs included the orphaned-user repair path:
Merged and removed orphaned user message to prevent consecutive user turns.
Root cause
In src/agents/pi-embedded-runner/run/attempt.ts, the orphaned trailing user repair currently changes only the in-memory leaf:
sessionManager.branch(leafEntry.parentId)
// or sessionManager.resetLeaf()
That does not remove the stale leaf from the persisted transcript file. The next run can start from disk state that still contains the orphan, so disk state, active branch state, and later rewrite/projection behavior diverge.
Expected behavior
When the orphaned user leaf is intentionally removed, the persisted SessionManager state should be updated immediately as well, so the active branch and .jsonl file stay consistent.
Fix direction
Remove the leaf entry from the underlying file-backed SessionManager entries and call its rewrite hook when available. Keep the previous in-memory branch/reset fallback for nonstandard managers.
Summary
When a new prompt arrives while the previous turn left a trailing
userleaf, OpenClaw merges that orphaned user content into the next prompt and moves the in-memorySessionManagerleaf back to the parent. The file-backed transcript is not rewritten at that point.That can leave the
.jsonltranscript on disk with stale/orphaned user entries that no longer match the active in-memory branch. Later transcript rewrites or branch projections may then produce a current transcript with missing assistant turns or long runs of consecutive user messages, even though earlier backup files still contain those assistant turns.Observed behavior
In a file-backed agent session:
.jsonlexistedusermessage entries.jsonl.jsonl.bak-*files still contained some of the missing assistant entriesRoot cause
In
src/agents/pi-embedded-runner/run/attempt.ts, the orphaned trailing user repair currently changes only the in-memory leaf:That does not remove the stale leaf from the persisted transcript file. The next run can start from disk state that still contains the orphan, so disk state, active branch state, and later rewrite/projection behavior diverge.
Expected behavior
When the orphaned user leaf is intentionally removed, the persisted
SessionManagerstate should be updated immediately as well, so the active branch and.jsonlfile stay consistent.Fix direction
Remove the leaf entry from the underlying file-backed
SessionManagerentries and call its rewrite hook when available. Keep the previous in-memory branch/reset fallback for nonstandard managers.