openclaw - 💡(How to fix) Fix Bug: WebChat transcript prompt rewrite duplicates assistant/tool entries in 2026.4.24 [1 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
openclaw/openclaw#72012Fetched 2026-04-27 05:36:08
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
closed ×1commented ×1cross-referenced ×1

After upgrading to OpenClaw 2026.4.24, WebChat / Control UI sessions can persist duplicate assistant responses in the JSONL transcript.

The duplicate is not a second model generation. The duplicated assistant entries preserve the same provider responseId and identical visible text, but receive new transcript entry ids and different parentIds.

The likely regression is the new 2026.4.24 WebChat/session transcript hygiene path that keeps runtime-only prompt context out of visible transcript history. The implementation rewrites the submitted user prompt after the model run has completed, and the current transcript rewrite helper replays the entire suffix from that user entry onward. That suffix includes the assistant response and tool results, so they are appended again.

Root Cause

Suspected root cause

Fix Action

Fix / Workaround

Alternative fix: add a single-entry in-place patch for transcript hygiene

Code Example

line 221 user      id=51fa2198 parent=c2adb219 text includes Sender metadata wrapper
line 230 assistant id=a22d872b parent=bc2f761c responseId=resp_041ae4afb7de8af80169ed9892640c81918ac0db5341577a8d textHash=14b3e5ac673c
line 231 user      id=9a3e6eb2 parent=c2adb219 same user message but cleaned, no Sender metadata wrapper
line 240 assistant id=b61cd0a4 parent=4f30efe2 responseId=resp_041ae4afb7de8af80169ed9892640c81918ac0db5341577a8d textHash=14b3e5ac673c

---

await abortable(activeSession.prompt(effectivePrompt));
rewriteSubmittedPromptTranscript({
  sessionManager,
  sessionFile: params.sessionFile,
  previousLeafId: transcriptLeafId,
  submittedPrompt: effectivePrompt,
  transcriptPrompt: params.transcriptPrompt
});
RAW_BUFFERClick to expand / collapse

Bug report: WebChat transcript prompt rewrite duplicates assistant/tool entries in 2026.4.24

Summary

After upgrading to OpenClaw 2026.4.24, WebChat / Control UI sessions can persist duplicate assistant responses in the JSONL transcript.

The duplicate is not a second model generation. The duplicated assistant entries preserve the same provider responseId and identical visible text, but receive new transcript entry ids and different parentIds.

The likely regression is the new 2026.4.24 WebChat/session transcript hygiene path that keeps runtime-only prompt context out of visible transcript history. The implementation rewrites the submitted user prompt after the model run has completed, and the current transcript rewrite helper replays the entire suffix from that user entry onward. That suffix includes the assistant response and tool results, so they are appended again.

Environment

  • OpenClaw version: 2026.4.24
  • Runtime: Gateway / WebChat Control UI
  • Agent/model observed: openai-codex/gpt-5.5
  • Session file observed locally: ~/.openclaw/agents/tino/sessions/673834c9-8f7b-4587-ace5-b7b4f9e51f18.jsonl

Why this looks like a 2026.4.24 regression

2026.4.24 release notes include:

WebChat/sessions: keep runtime-only prompt context out of visible transcript history and scrub legacy wrappers from session history surfaces.

In the installed 2026.4.24 dist, this path is present:

  • dist/get-reply-CSQ5BMwG.js
    • passes transcriptPrompt: transcriptCommandBody
  • dist/agent-runner.runtime-CbAg9IpO.js
    • forwards transcriptPrompt: params.transcriptCommandBody
  • dist/selection-C3otDzGD.js
    • defines and calls rewriteSubmittedPromptTranscript(...)
  • dist/transcript-rewrite-DEfbMkgI.js
    • implements rewriteTranscriptEntriesInSessionManager(...)

A comparison against npm package [email protected] did not show the rewriteSubmittedPromptTranscript(...) path, only older transcriptPromptTokens references.

Reproduction pattern

  1. Use WebChat / Control UI to send a user message where the actual submitted prompt contains runtime metadata / wrapper text, but the visible transcript prompt should be cleaner.
  2. The model run completes normally and appends the assistant response.
  3. After activeSession.prompt(effectivePrompt) completes, rewriteSubmittedPromptTranscript(...) runs to replace the user message text with transcriptPrompt.
  4. The transcript rewrite helper branches from the user message parent and re-appends the active branch suffix.
  5. The already-completed assistant response/tool result entries are appended again.

Observed transcript shape

Example shape from local transcript:

line 221 user      id=51fa2198 parent=c2adb219 text includes Sender metadata wrapper
line 230 assistant id=a22d872b parent=bc2f761c responseId=resp_041ae4afb7de8af80169ed9892640c81918ac0db5341577a8d textHash=14b3e5ac673c
line 231 user      id=9a3e6eb2 parent=c2adb219 same user message but cleaned, no Sender metadata wrapper
line 240 assistant id=b61cd0a4 parent=4f30efe2 responseId=resp_041ae4afb7de8af80169ed9892640c81918ac0db5341577a8d textHash=14b3e5ac673c

The assistant duplicate has:

  • same provider responseId
  • same visible assistant text hash
  • different transcript entry id
  • different transcript parent chain
  • timestamp shortly after the first append

This indicates transcript replay/append, not a second model call.

Suspected root cause

selection-C3otDzGD.js:

await abortable(activeSession.prompt(effectivePrompt));
rewriteSubmittedPromptTranscript({
  sessionManager,
  sessionFile: params.sessionFile,
  previousLeafId: transcriptLeafId,
  submittedPrompt: effectivePrompt,
  transcriptPrompt: params.transcriptPrompt
});

rewriteSubmittedPromptTranscript(...) finds the just-submitted user message and calls rewriteTranscriptEntriesInSessionManager(...).

transcript-rewrite-DEfbMkgI.js then:

  1. finds the first rewritten entry
  2. branches from firstMatchedEntry.parentId
  3. re-appends every branch entry from that index through the leaf

That behavior is safe for compacting/truncating entries when replaying a branch is intended, but it is unsafe for post-turn user-prompt hygiene after assistant/tool entries have already been appended.

Impact

  • Control UI / WebChat shows duplicated assistant replies.
  • JSONL transcripts accumulate duplicate assistant and tool entries.
  • Context size grows faster than expected.
  • Auto-compaction / context overflow can trigger earlier.
  • Debugging becomes confusing because duplicated entries have the same provider responseId, making it look like delivery/model duplication unless the transcript graph is inspected.

Suggested fix options

Preferred fix: rewrite prompt before model completion or before assistant append

Avoid post-turn branch replay after the assistant/tool suffix exists.

Possible approaches:

  1. Store the transcript-safe user message at initial append time, while sending effectivePrompt only to the provider/runtime.
  2. If the runtime must initially append effectivePrompt, perform the prompt rewrite immediately after user append and before activeSession.prompt(...) can append assistant/tool entries.

This preserves the 2026.4.24 goal — runtime-only prompt context stays out of visible history — without replaying completed assistant entries.

Alternative fix: add a single-entry in-place patch for transcript hygiene

For this specific prompt hygiene case, replace only the target user message entry without branch replaying the suffix.

This should be done carefully because JSONL transcript entries are branch-graph records, but for a same-role same-position content-only cleanup, an in-place entry replacement may be safer than replaying a completed turn.

Defensive fix: dedupe replayed assistant/tool entries by provider response identity

When replaying suffix entries, avoid re-appending assistant entries that already exist on another live branch with the same stable provider response identity and identical text signature.

This is less ideal because it treats the symptom rather than avoiding post-turn replay.

Expected behavior

After a WebChat message, the transcript should contain one visible user message and one assistant response for that model call. If the user prompt is cleaned for transcript visibility, the cleanup should not duplicate already-completed assistant/tool entries.

Actual behavior

The transcript contains the original wrapped user message and assistant response, then a cleaned user message and a replayed duplicate assistant/tool suffix.

Notes

This does not appear related to Codex fast mode. Fast mode may affect model behavior/performance, but the duplicate entries preserve the same provider responseId, which points to transcript replay rather than a second provider request.

extent analysis

TL;DR

The most likely fix is to rewrite the prompt before model completion or before assistant append to avoid post-turn branch replay after the assistant/tool suffix exists.

Guidance

  • Identify the point where the effectivePrompt is sent to the provider/runtime and consider storing the transcript-safe user message at initial append time.
  • Perform the prompt rewrite immediately after user append and before activeSession.prompt(...) can append assistant/tool entries.
  • As an alternative, consider adding a single-entry in-place patch for transcript hygiene to replace only the target user message entry without branch replaying the suffix.
  • When replaying suffix entries, dedupe replayed assistant/tool entries by provider response identity to avoid re-appending duplicate entries.

Example

// Store transcript-safe user message at initial append time
const transcriptSafeUserMessage = getTranscriptSafeUserMessage(effectivePrompt);
// Send effectivePrompt to provider/runtime
await abortable(activeSession.prompt(effectivePrompt));
// Rewrite prompt before assistant append
rewriteSubmittedPromptTranscript({
  sessionManager,
  sessionFile: params.sessionFile,
  previousLeafId: transcriptLeafId,
  submittedPrompt: transcriptSafeUserMessage,
  transcriptPrompt: params.transcriptPrompt
});

Notes

The provided fix options aim to address the root cause of the issue, which is the post-turn branch replay after the assistant/tool suffix exists. The defensive fix, deduping replayed assistant/tool entries by provider response identity, may be less ideal but can help mitigate the symptom.

Recommendation

Apply the preferred fix: rewrite prompt before model completion or before assistant append. This approach preserves the 2026.4.24 goal of keeping runtime-only prompt context out of visible history without replaying completed assistant entries.

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…

FAQ

Expected behavior

After a WebChat message, the transcript should contain one visible user message and one assistant response for that model call. If the user prompt is cleaned for transcript visibility, the cleanup should not duplicate already-completed assistant/tool entries.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Bug: WebChat transcript prompt rewrite duplicates assistant/tool entries in 2026.4.24 [1 comments, 2 participants]