openclaw - 💡(How to fix) Fix Every user message is processed twice: rewriteSubmittedPromptTranscript branches after agent reply, triggering duplicate run [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#72288Fetched 2026-04-27 05:32:00
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
0
Timeline (top)
closed ×1commented ×1

Root Cause

The root cause is rewriteSubmittedPromptTranscript in selection-C3otDzGD.js — it creates a new transcript branch after the agent has already replied, and the new branch triggers a second agent run.

Code Example

7786ae32 (assistant: greeting)
  ├── 06981791 (user: WITH Sender metadata)     [16:48:05.620]
  │   └── 68cd74aa (assistant: "1")              [16:48:09.435]  ← 1st run reply
  └── db88661b (user: WITHOUT Sender metadata)   [16:48:09.475]  ← rewrite branch
      └── 14704559 (assistant: "1")              [16:48:09.475]  ← 2nd run reply (DUPLICATE)

---

Sender (untrusted metadata):
{"label": "openclaw-control-ui", "id": "openclaw-control-ui"}

[Mon 2026-04-27 00:48 GMT+8] 如果你可以看到...

---

[Mon 2026-04-27 00:48 GMT+8] 如果你可以看到...

---

// selection-C3otDzGD.js ~line 7118
   rewriteSubmittedPromptTranscript({
       sessionManager,
       sessionFile: params.sessionFile,
       previousLeafId: transcriptLeafId,
       submittedPrompt: effectivePrompt,        // WITH Sender metadata
       transcriptPrompt: params.transcriptPrompt // WITHOUT Sender metadata
   });
RAW_BUFFERClick to expand / collapse

Bug Summary

Every inbound user message is processed twice by the agent, producing two separate transcript entries and two responses. This affects all channels (webchat, Feishu/Lark, etc.).

The root cause is rewriteSubmittedPromptTranscript in selection-C3otDzGD.js — it creates a new transcript branch after the agent has already replied, and the new branch triggers a second agent run.

Environment

  • OpenClaw: 2026.4.24 (cbcfdf6)
  • OS: Linux 6.17.0-20-generic (x64)
  • Node: v25.8.2
  • Channel: all (confirmed webchat + Feishu/Lark)

Reproduction

  1. Start any conversation via webchat or Feishu
  2. Send a message
  3. Observe the agent responds twice

Evidence: Transcript Analysis

Sent one webchat message: 如果你看到我说了两句一样的话你就回复 1

The session transcript (JSONL) shows two user entries with the same parentId, plus two assistant responses:

7786ae32 (assistant: greeting)
  ├── 06981791 (user: WITH Sender metadata)     [16:48:05.620]
  │   └── 68cd74aa (assistant: "1")              [16:48:09.435]  ← 1st run reply
  └── db88661b (user: WITHOUT Sender metadata)   [16:48:09.475]  ← rewrite branch
      └── 14704559 (assistant: "1")              [16:48:09.475]  ← 2nd run reply (DUPLICATE)

Both user entries share parentId: 7786ae32 but have different IDs. The first contains the full envelope with Sender metadata:

Sender (untrusted metadata):
{"label": "openclaw-control-ui", "id": "openclaw-control-ui"}

[Mon 2026-04-27 00:48 GMT+8] 如果你可以看到...

The second contains only the bare message:

[Mon 2026-04-27 00:48 GMT+8] 如果你可以看到...

The agent replied "1" to both, confirming it processed the message twice.

This happens for every message. The same pattern repeats for Feishu messages (Sender = ou_xxx vs bare message).

Root Cause

The Flow

  1. getReplyFromConfig in get-reply-CSQ5BMwG.js builds two versions of the user message:

    • effectiveBaseBody = inboundUserContext (with Sender envelope) + baseBodyFinal → used as prompt for the agent
    • transcriptBodyBase = baseBodyFinal only (without Sender envelope) → passed as transcriptPrompt
  2. In buildReplyPromptBodies, these become:

    • queuedBodyfollowupRun.prompt (with Sender)
    • transcriptCommandBodyfollowupRun.transcriptPrompt (without Sender)
  3. The agent runner appends the prompt (with Sender) to the transcript as a user message via sessionManager.appendMessage().

  4. The agent runs and produces a response. The response is appended to the transcript.

  5. After the agent reply, rewriteSubmittedPromptTranscript is called:

    // selection-C3otDzGD.js ~line 7118
    rewriteSubmittedPromptTranscript({
        sessionManager,
        sessionFile: params.sessionFile,
        previousLeafId: transcriptLeafId,
        submittedPrompt: effectivePrompt,        // WITH Sender metadata
        transcriptPrompt: params.transcriptPrompt // WITHOUT Sender metadata
    });
  6. Since submittedPrompt !== transcriptPrompt, it proceeds to rewrite. It calls rewriteTranscriptEntriesInSessionManager which:

    • Calls sessionManager.branch(firstMatchedEntry.parentId) — creates a new branch from the user message's parent
    • Re-appends the user message with the replacement text (without Sender)
    • This creates a new entry in the transcript
  7. The new branch has a new user message entry, which is detected as a pending user turn, triggering a second agent run.

Why It's a Branch, Not a Replacement

rewriteTranscriptEntriesInSessionManager (in transcript-rewrite-DEfbMkgI.js) works by:

  1. Finding the matching entry in the current branch
  2. Calling sessionManager.branch(entry.parentId) to fork from the parent
  3. Re-appending all entries from that point, substituting the replacement

This leaves the old branch intact (the one with the Sender metadata + agent reply). The new branch starts from the same parent with the rewritten content.

Why It Triggers a Second Run

After the rewrite, the transcript's leaf points to the new branch. The new branch has a fresh user message (no response yet), so the agent runner picks it up as a new pending turn and runs the agent again.

Impact

  • Double token consumption — every message costs 2x tokens
  • Duplicate responses — the user sees two replies
  • Conversation confusion — the agent's context contains duplicate user messages, degrading response quality
  • Compaction bloat — transcripts grow 2x faster, triggering more frequent compactions

Suggested Fix

Option A: Skip the rewrite entirely. Since the Sender metadata is already injected as untrusted context and the agent handles it correctly, the transcript rewrite provides no value while causing duplicates.

Option B: Perform the rewrite before the agent runs, not after. This way the transcript only ever contains one version of the user message.

Option C: Check if the old branch already has an assistant response. If it does, don't branch — the rewrite is too late.

Files Involved

FileFunctionRole
selection-C3otDzGD.jsrewriteSubmittedPromptTranscriptTriggers the problematic rewrite
transcript-rewrite-DEfbMkgI.jsrewriteTranscriptEntriesInSessionManagerCreates new branch instead of in-place edit
get-reply-CSQ5BMwG.jsbuildReplyPromptBodies / getReplyFromConfigProduces two different versions of the prompt
pi-embedded-Cic3zlxn.jsRun attempt flowCalls rewrite after agent reply

extent analysis

TL;DR

The most likely fix is to skip the rewrite entirely or perform it before the agent runs to prevent duplicate processing of user messages.

Guidance

  • Review the rewriteSubmittedPromptTranscript function in selection-C3otDzGD.js to understand the conditions under which it triggers a rewrite.
  • Consider implementing Option A: Skip the rewrite entirely, as the Sender metadata is already handled correctly by the agent.
  • Alternatively, explore Option B: Perform the rewrite before the agent runs, to ensure the transcript only contains one version of the user message.
  • Verify the fix by checking the transcript for duplicate user messages and agent responses.

Example

No code snippet is provided, as the issue is more related to the logic and timing of the rewrite process rather than a specific code error.

Notes

The provided information suggests that the issue is specific to the handling of user messages and the rewrite process. The suggested fixes aim to address the root cause of the problem, but further testing and verification are necessary to ensure the solution works as expected.

Recommendation

Apply Option A: Skip the rewrite entirely, as it seems to provide no value while causing duplicates, and the agent already handles the Sender metadata correctly. This approach is simpler and less likely to introduce new issues compared to modifying the timing of the rewrite process.

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…

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 Every user message is processed twice: rewriteSubmittedPromptTranscript branches after agent reply, triggering duplicate run [1 comments, 2 participants]