Skip to content

Current-session message-tool replies can be replaced by private bookkeeping finals #91330

Description

@ooiuuii

Summary

In automatic channel delivery mode, a successful message(action="send") call back to the current source conversation can be delivered to the user without being recorded as a delivered source reply. If the model then emits a private bookkeeping final, OpenClaw can select that bookkeeping text as the visible final response instead of treating the message-tool send as the user-facing answer.

This is a message-delivery/final-selection bug, not a QQBot setup bug and not a gateway-restart recovery request.

Real environment observed

  • Version observed: OpenClaw 2026.6.5-beta.2
  • Surface: Telegram direct conversation
  • Runtime shape: Windows-side main agent using the Codex runtime
  • Delivery shape: the agent used message(action="send") to reply to the same source conversation during the turn
  • Privacy note: chat ids, account ids, tokens, local file paths, and private user content are intentionally redacted

User-visible symptom

The agent completed the useful diagnostic work and sent the substantive answer through the message tool to the current Telegram conversation. The same run then ended with private bookkeeping text equivalent to:

I replied via Telegram and recorded the setup state in memory.

That bookkeeping text became the apparent final surface for the turn, making the chat look like the useful conclusion was missing or replaced even though the message-tool reply had already been sent.

Source-level repro on current main

The current source-reply extraction path only records message-tool source replies when the tool result carries source-reply metadata such as sourceReplySink: "internal-ui":

extractMessagingToolSourceReplyPayload(...)
// requires details.sourceReplySink === "internal-ui"

However, a normal successful current-source message-tool send can return an ordinary send payload such as:

{ "ok": true, "messageId": "<redacted>" }

or a core send wrapper whose positive delivery evidence is nested under payload.result.messageId, without sourceReplySink. Downstream final-payload selection therefore lacks evidence that the current source reply was already delivered. A later assistant bookkeeping final remains eligible for channel-visible delivery.

The problematic shape is:

  1. current-source message(action="send") succeeds;
  2. result has positive delivery evidence, but no source-reply marker;
  3. model emits private bookkeeping final text;
  4. final selection surfaces the bookkeeping text instead of suppressing it as private post-delivery text.

Expected behavior

For a successful message(action="send") to the current source conversation:

  • Treat the send as a delivered source reply only when delivery is positively proven (messageId/message_id or explicit sent/delivered status, and no failed/error status).
  • Mirror/source-record that delivered reply so transcript/history and final selection know the user-facing response was already delivered.
  • Suppress later private bookkeeping final text from becoming the channel-visible final response.
  • Do not annotate failed or ambiguous sends; if delivery is not proven, the later assistant final should remain eligible so the user is not left with no visible reply.
  • Do not treat explicitly routed sends to other targets/sessions as replies to the current source conversation.

Actual behavior

Current-source message-tool sends can be treated like ordinary external sends. Without source-reply metadata, the embedded runner cannot reliably distinguish an already-delivered source reply from an unrelated message-tool send, so later private final text can still be selected as the visible reply.

Scope / non-goals

  • This is not a request to fix gateway restart/session continuation.
  • This is not a request to change QQBot setup behavior.
  • This is not about sends explicitly routed to another conversation.
  • The narrow scope is the current-source message-tool delivery boundary and final-selection suppression.

Proposed fix

#91333 proposes the narrow fix for this issue.

Metadata

Metadata

Assignees

Labels

P2Normal backlog priority with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions