fix(agents): suppress private finals after message tool source replies#91333
fix(agents): suppress private finals after message tool source replies#91333ooiuuii wants to merge 1 commit into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 8, 2026, 2:35 AM ET / 06:35 UTC. Summary PR surface: Source +164, Tests +139. Total +303 across 4 files. Reproducibility: yes. source-level reproduction is high confidence: current main extracts source replies only when tool results already include Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the scoped core runner/payload fix after maintainer review, using Mantis Telegram proof first if maintainers want transport-visible confirmation. Do we have a high-confidence way to reproduce the issue? Yes, source-level reproduction is high confidence: current main extracts source replies only when tool results already include Is this the best way to solve the issue? Yes, this is the best apparent fix shape: the outbound runner is the layer that knows current-source routing and delivery evidence, and the payload builder is the existing final-selection boundary. A live Telegram proof would increase confidence but does not change the code direction. AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 538d36eaaaa6. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +164, Tests +139. Total +303 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
281dc09 to
38471f8
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
38471f8 to
ee07510
Compare
ee07510 to
2becd6b
Compare
2becd6b to
f838b0e
Compare
|
Closing this implementation; the issue remains valid, but this fix is too broad to land safely. Fresh maintainer review after rebasing onto current
Focused tests pass, but they do not cover these user-visible loss cases. The replacement should only suppress a final when delivery evidence identifies a terminal source reply, and it must include thread identity. |
|
Thanks, Vincent. Your boundary here was right: an ordinary send receipt, including a returned I'm preparing a clean replacement PR that does not revive the automatic final suppression approach from this issue. The narrower change is only to preserve explicit typed New PR: #92251 |
Summary
Fixes #91330.
Current-session
message(action="send")replies can already deliver the useful answer to the source chat, but the runner did not mark those sends as delivered source replies. If the model then ended with private bookkeeping text, that bookkeeping final could become the channel-visible final answer.This PR marks successful current-source message sends as delivered source replies and suppresses later private assistant artifacts. It does not resend the message-tool reply in automatic delivery mode.
Source-proven bug this PR fixes
A Windows/OpenClaw node running
2026.6.5-beta.2reproduced this during a Telegram direct-chat QQBot setup diagnosis:messagetool back to the same Telegram source conversation.ok: true,messageId: ...), so the embedded runner did not record it as a source reply.I replied via Telegram and recorded the setup state in memory.The QQBot-specific diagnosis was incidental; this PR only fixes the current-session message-tool/final-selection boundary.
What changed
sendresults only when the send result has positive delivery evidence (messageId/message_id, explicitsent/deliveredstatus, and no failed/error status), with:deliveryStatus: "sent"sourceReplySink: "internal-ui"sourceReplymessage_tool_onlykeeps the existing mirror payload behavior.automaticuses delivered source-reply evidence to suppress later private finals without resending the source reply.Related context
message_tool_onlydelivery fixes. This PR covers the normal automatic direct-session path instead.This PR intentionally does not fix gateway restart/session continuation. The earlier interrupted rollout in the incident is a separate problem and is not required for this patch.
Real behavior proof
Behavior or issue addressed: A current-session message-tool reply can deliver the useful response, but a later private bookkeeping final can replace/obscure it as the visible final answer because the successful send was not recorded as a delivered source reply.
Real environment tested: Local OpenClaw source checkout on macOS/Darwin, branch
agent/xiaozhua/restart-message-final-incident. The user-visible incident came from a Windows/OpenClaw2026.6.5-beta.2Telegram direct session and is documented in Current-session message-tool replies can be replaced by private bookkeeping finals #91330 with sensitive values redacted.Exact steps or command run after this patch: Ran an after-patch source-level behavior probe with
pnpm exec tsx /tmp/message-tool-source-reply-probe.ts, plus focused regression tests:Evidence after fix: Console output from the after-patch source-level probe for the real incident shape (
automaticdelivery, delivered current-session message-tool source reply, followed by private bookkeeping final):{ "scenario": "automatic current-session message-tool source reply followed by private bookkeeping final", "payloadCount": 0, "payloads": [] }Focused test output also covered the regression path:
Observed result after fix: Automatic-mode delivered source replies suppress later private bookkeeping finals (
payloadCount: 0) and do not emit a duplicate final payload for the already-delivered message-tool reply. Existingmessage_tool_onlymirror behavior remains covered. Explicit sends to another session remain unmarked as source replies, and failed/ambiguous current-source sends remain unmarked so a later final is not hidden when delivery was not proven.What was not tested: A full live Telegram replay against a patched production Gateway was not run. Gateway restart/session continuation is not fixed or tested by this PR.
Tests
pnpm exec tsx /tmp/message-tool-source-reply-probe.tsnode scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/payloads.test.tsnode scripts/run-vitest.mjs src/infra/outbound/message-action-runner.core-send.test.tspnpm exec oxlint src/infra/outbound/message-action-runner.ts src/infra/outbound/message-action-runner.core-send.test.ts src/agents/embedded-agent-runner/run/payloads.ts src/agents/embedded-agent-runner/run/payloads.test.tsgit diff --checkpnpm build:plugin-sdk:dts