Skip to content

fix(agents): suppress private finals after message tool source replies#91333

Closed
ooiuuii wants to merge 1 commit into
openclaw:mainfrom
ooiuuii:agent/xiaozhua/restart-message-final-incident
Closed

fix(agents): suppress private finals after message tool source replies#91333
ooiuuii wants to merge 1 commit into
openclaw:mainfrom
ooiuuii:agent/xiaozhua/restart-message-final-incident

Conversation

@ooiuuii

@ooiuuii ooiuuii commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

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.2 reproduced this during a Telegram direct-chat QQBot setup diagnosis:

  • The useful diagnosis was sent with the message tool back to the same Telegram source conversation.
  • The tool result only carried a normal successful send result (ok: true, messageId: ...), so the embedded runner did not record it as a source reply.
  • The model then ended with private bookkeeping text equivalent to: I replied via Telegram and recorded the setup state in memory.
  • That private bookkeeping text became the apparent final response, making the turn look like it had no useful conclusion even though the useful message-tool reply had already been delivered.

The QQBot-specific diagnosis was incidental; this PR only fixes the current-session message-tool/final-selection boundary.

What changed

  • Annotate successful current-source send results only when the send result has positive delivery evidence (messageId/message_id, explicit sent/delivered status, and no failed/error status), with:
    • deliveryStatus: "sent"
    • sourceReplySink: "internal-ui"
    • sourceReply
  • Keep explicit sends to another target/session unannotated.
  • Keep failed or ambiguous current-source sends unannotated so the later assistant final remains eligible instead of being suppressed.
  • In payload building:
    • message_tool_only keeps the existing mirror payload behavior.
    • automatic uses delivered source-reply evidence to suppress later private finals without resending the source reply.

Related context

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/OpenClaw 2026.6.5-beta.2 Telegram 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:

    pnpm exec tsx /tmp/message-tool-source-reply-probe.ts
    node scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/payloads.test.ts
    node scripts/run-vitest.mjs src/infra/outbound/message-action-runner.core-send.test.ts
    pnpm 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.ts
    git diff --check
  • Evidence after fix: Console output from the after-patch source-level probe for the real incident shape (automatic delivery, 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:

    ✓ src/agents/embedded-agent-runner/run/payloads.test.ts (35 tests)
    ✓ src/infra/outbound/message-action-runner.core-send.test.ts (13 tests)
    Found 0 warnings and 0 errors.
    
  • 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. Existing message_tool_only mirror 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.ts
  • node scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/payloads.test.ts
  • node scripts/run-vitest.mjs src/infra/outbound/message-action-runner.core-send.test.ts
  • pnpm 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.ts
  • git diff --check
  • pnpm build:plugin-sdk:dts

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: M triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 8, 2026
@clawsweeper

clawsweeper Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 8, 2026, 2:35 AM ET / 06:35 UTC.

Summary
The PR marks positively delivered current-source message(action="send") results as internal source replies and updates embedded payload selection/tests so later private finals are suppressed without resending the tool-delivered reply.

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 sourceReplySink, so ordinary successful current-source sends can leave later assistant finals eligible. I did not run a live Telegram replay.

Review metrics: none identified.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Use the recommended Mantis Telegram proof if maintainers want transport-visible confirmation before merge.

Mantis proof suggestion
A native Telegram Desktop proof would materially reduce the remaining message-delivery risk for the original incident shape. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

telegram desktop proof: verify a Telegram direct turn where the agent sends the useful reply with message(action=send) and then emits private bookkeeping text; the chat shows the useful reply without a duplicate/private final.

Risk before merge

  • [P1] This changes the message-delivery/final-selection boundary: a delivered current-source message-tool send can now suppress a later assistant final, so maintainers should agree that positive delivery evidence makes the tool send authoritative for that turn.
  • [P1] The supplied proof is strong source-level terminal proof plus focused tests, but it does not replay the exact patched Telegram transport-visible incident end to end.

Maintainer options:

  1. Review and land with source-level proof (recommended)
    Maintainers can accept the source-level probe and regression tests as sufficient because the patch changes core final-selection evidence rather than Telegram transport code.
  2. Ask Mantis for Telegram replay
    Before merge, a maintainer can request Telegram Desktop proof showing the useful message-tool reply remains visible and the private bookkeeping final is not delivered.

Next step before merge

  • No automated repair is needed; the remaining action is maintainer review of the message-delivery invariant and optional live Telegram proof.

Security
Cleared: The diff changes TypeScript runtime logic and tests only; it does not touch dependencies, workflows, secrets, package metadata, or code-download surfaces.

Review details

Best 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 sourceReplySink, so ordinary successful current-source sends can leave later assistant finals eligible. I did not run a live Telegram replay.

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 changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-patch terminal output from a source-level behavior probe showing automatic-mode delivered source reply plus private final yields no final payload, along with focused regression tests; full Telegram replay was not run.

Label justifications:

  • P2: This is a normal-priority message-delivery bug with a bounded agent/outbound surface and no emergency data-loss or availability signal.
  • merge-risk: 🚨 message-delivery: The diff changes when OpenClaw suppresses final channel payloads after message-tool sends, so a wrong invariant could drop or duplicate visible replies.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-patch terminal output from a source-level behavior probe showing automatic-mode delivered source reply plus private final yields no final payload, along with focused regression tests; full Telegram replay was not run.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-patch terminal output from a source-level behavior probe showing automatic-mode delivered source reply plus private final yields no final payload, along with focused regression tests; full Telegram replay was not run.
  • mantis: telegram-visible-proof: Mantis should capture Telegram visible proof. The bug is visible in Telegram chat behavior, and a short Telegram Desktop proof can show the useful message-tool reply without a duplicate/private final.
Evidence reviewed

PR surface:

Source +164, Tests +139. Total +303 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 172 8 +164
Tests 2 142 3 +139
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 314 11 +303

What I checked:

Likely related people:

  • Vincent Koc: Blame and history show the current source-reply extraction, payload suppression, and outbound routing helpers in the central files trace to recent commits by this author. (role: introduced behavior and recent area contributor; confidence: high; commits: 8dff52958701, 6a0fdea90ad0; files: src/agents/embedded-agent-subscribe.handlers.tools.ts, src/agents/embedded-agent-runner/run/payloads.ts, src/infra/outbound/message-action-runner.ts)
  • mushuiyu_xydt: Recent merged work touched the same embedded payload builder around assistant final/error selection, so this person is a useful adjacent reviewer if the payload suppression invariant needs a second look. (role: recent adjacent contributor; confidence: medium; commits: b2c1de77acc7; files: src/agents/embedded-agent-runner/run/payloads.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 8, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 8, 2026
@ooiuuii
ooiuuii force-pushed the agent/xiaozhua/restart-message-final-incident branch from 281dc09 to 38471f8 Compare June 8, 2026 05:41
@ooiuuii

ooiuuii commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 8, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 8, 2026
@ooiuuii
ooiuuii force-pushed the agent/xiaozhua/restart-message-final-incident branch from 38471f8 to ee07510 Compare June 8, 2026 06:01
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 8, 2026
@ooiuuii
ooiuuii force-pushed the agent/xiaozhua/restart-message-final-incident branch from ee07510 to 2becd6b Compare June 8, 2026 06:17
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 8, 2026
@ooiuuii
ooiuuii force-pushed the agent/xiaozhua/restart-message-final-incident branch from 2becd6b to f838b0e Compare June 8, 2026 06:23
@vincentkoc

Copy link
Copy Markdown
Member

Closing this implementation; the issue remains valid, but this fix is too broad to land safely.

Fresh maintainer review after rebasing onto current main found two blocking regressions:

  1. In automatic delivery mode, any successful current-conversation message(action=send) suppresses the final assistant text. Interim status/media sends can therefore discard the substantive final answer.
  2. Current-source classification matches only the channel target and ignores thread identity, so a send to another thread or channel root can suppress the final reply in the actual source thread.

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.

@ooiuuii

ooiuuii commented Jun 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, Vincent. Your boundary here was right: an ordinary send receipt, including a returned messageId, should not be treated as proof that the terminal/source conversation received a final reply.

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 inputProvenance through active subagent wake inputs, so provenance is carried when it is already known rather than inferred from delivery metadata or target heuristics.

New PR: #92251

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants