Skip to content

fix(reply): suppress tool-error progress delivery when messages.suppressToolErrors is set#98063

Merged
vincentkoc merged 1 commit into
openclaw:mainfrom
moeedahmed:fix/suppress-tool-error-progress-native
Jul 1, 2026
Merged

fix(reply): suppress tool-error progress delivery when messages.suppressToolErrors is set#98063
vincentkoc merged 1 commit into
openclaw:mainfrom
moeedahmed:fix/suppress-tool-error-progress-native

Conversation

@moeedahmed

Copy link
Copy Markdown
Contributor

Replacement for #88898

This carries the same narrow fix as #88898, rebased onto current main, from a Moeed-owned fork branch that agents can update if follow-up is needed. The original PR remains blocked because its contributor-fork branch is conflicting and this account has no write access to that fork or upstream.

Local verification on this replacement branch:

  • git diff --check passed
  • conflict-marker scan passed
  • outgoing diff/touched-file secret-pattern scan passed
  • focused Vitest command could not run in the fresh clone because node_modules is not installed; upstream CI is expected to provide full test proof

Summary

messages.suppressToolErrors is an existing user-facing config knob that hides tool-error noise from chat (landed in #16620 / #81561). Today it only drops the warning TEXT inside src/auto-reply/reply/payloads.ts. The error tool-result payload is still delivered as channel progress through the onToolResult path in src/auto-reply/reply/dispatch-from-config.ts unless sourceReplyDeliveryMode === "message_tool_only". Operators who set messages.suppressToolErrors: true therefore still see tool-error noise as progress payloads, contradicting the documented behavior of the knob.

Change

Add a config-gated early-return inside onToolResult in src/auto-reply/reply/dispatch-from-config.ts that drops the visible progress delivery when payload.isError === true and replyConfig.messages?.suppressToolErrors === true, regardless of sourceReplyDeliveryMode. Per review feedback, the gate is positioned before the optional source-delivery callback, so a suppressed error payload never reaches progress delivery or the source callback. A focused regression test in src/auto-reply/reply/dispatch-from-config.test.ts exercises the suppressed-error path through dispatchReplyFromConfig and asserts neither onToolResult nor sendToolResult is called while the final reply still ships.

Real behavior proof

Behavior addressed: when messages.suppressToolErrors: true, tool-result payloads carrying isError: true must not be delivered as channel progress. Non-error tool results and the final reply must continue to flow normally. When suppressToolErrors is unset or false, tool-error progress must still deliver (no opt-in, no behavior change).

Real environment tested: live deployed openclaw gateway on rh-bot.lan, pid 71842, build SHA 23804e6 (upgrade-v2026.5.28 includes this commit; deployed bundle dist/dispatch-D9SNCck_.js contains the new gate at line 1458).

Exact steps or command run after this patch: copied /tmp/proof-toolerr-amittell.mjs to rh-bot.lan and ran node /tmp/proof-toolerr-amittell.mjs against the deployed bundle. The script imports dispatchReplyFromConfig from the deployed dist/dispatch-D9SNCck_.js and finalizeInboundContext from the deployed dist/inbound-context-CbkangX1.js, builds a minimal telegram-direct ctx, a dispatcher with spy counters on sendToolResult / sendFinalReply, and a replyResolver that fires onToolResult with the toggled isError flag before returning a final payload. Three scenarios were exercised:

A. messages.suppressToolErrors: true + isError: true
B. messages.suppressToolErrors: true + isError: false
C. messages.suppressToolErrors: false + isError: true

agents.defaults.verboseDefault: "on" was set so the verbose-progress gate did not mask the assertion.

Evidence after fix: deployed bundle gate verified at /Users/alexm/.openclaw/openclaw/dist/dispatch-D9SNCck_.js:1458 as if (payload.isError === true && replyConfig.messages?.suppressToolErrors === true) return;. Script output:

--- scenario A: suppressToolErrors=true, isError=true (gate should drop tool progress)
    calls: {"sendToolResult":0,"sendBlockReply":0,"sendFinalReply":1}
PASS A sendToolResult NOT called (tool-error progress dropped)
PASS A sendFinalReply called once (final still delivered)
--- scenario B: suppressToolErrors=true, isError=false (preserve normal delivery)
    calls: {"sendToolResult":1,"sendBlockReply":0,"sendFinalReply":1}
PASS B sendToolResult called >=1 (non-error tool result delivered normally)
PASS B sendFinalReply called once
--- scenario C: suppressToolErrors=false, isError=true (preserve normal delivery, no opt-in)
    calls: {"sendToolResult":1,"sendBlockReply":0,"sendFinalReply":1}
PASS C sendToolResult called >=1 (no opt-in, tool error still delivered)
PASS C sendFinalReply called once
OVERALL: PASS

Observed result after fix: with messages.suppressToolErrors: true and isError: true, the deployed bundle dropped the tool-result progress delivery (sendToolResult count was 0) while the final reply still shipped (sendFinalReply count was 1). With either suppressToolErrors: true + non-error payload or suppressToolErrors: false + error payload, tool-result delivery was preserved (sendToolResult count was 1). Existing behavior is preserved outside the explicit opt-in.

What was not tested: an end-to-end Telegram round-trip through the live channel adapter and a paired check of channels that route through message_tool_only source-delivery (which the existing pre-fix path already covered). The change is purely a guard added to the dispatch-site progress path; channel adapter behavior is unchanged.

…essToolErrors is set

5.22 already drops the tool-error WARNING text via payloads.ts, but the
error tool-result payload was still delivered as channel progress unless
sourceReplyDeliveryMode was message_tool_only. Operators who opt into
messages.suppressToolErrors expect no tool-error noise in chat at all.
Add a config-gated early-return in the onToolResult dispatch path so the
visible progress delivery is dropped too, matching the warning-text policy.
No-op unless messages.suppressToolErrors is true. Folds the mac-mini deploy
hotfix into the tracked branch.

(cherry picked from commit a973410)
@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 3:19 AM ET / 07:19 UTC.

Summary
The PR adds a config-gated early return for error tool-result progress in dispatchReplyFromConfig and a focused regression test for the suppressed-error path.

PR surface: Source +7, Tests +33. Total +40 across 2 files.

Reproducibility: yes. from source inspection: current main forwards payload.isError tool results through onToolResult/sendToolResult without checking messages.suppressToolErrors, while the warning-builder path already honors the knob. I did not run a local test because this review is read-only.

Review metrics: 1 noteworthy metric.

  • Existing config behavior: 1 existing knob behavior broadened, 0 new config keys. The PR changes what messages.suppressToolErrors suppresses without adding a new config/default surface, so maintainers should notice the upgrade behavior.

Root-cause cluster
Relationship: canonical
Canonical: #98063
Summary: This PR is the clean replacement and viable landing candidate for the same narrow fix in the older conflicting PR.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

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:

  • none.

Risk before merge

  • [P1] Merging intentionally suppresses visible tool-error progress for existing users who already set messages.suppressToolErrors: true; that matches the PR's stated contract but is still a message-delivery behavior change.
  • [P1] The supplied real behavior proof exercises the deployed dispatch bundle with a Telegram-direct context, not a full end-to-end channel adapter round trip.

Maintainer options:

  1. Accept config-gated suppression (recommended)
    Land the PR if maintainers agree messages.suppressToolErrors should suppress error tool-result progress as well as warning payloads.
  2. Ask for channel round-trip proof
    Request a short live channel proof only if maintainers want transport-level evidence beyond the dispatch-bundle proof already supplied.
  3. Keep progress outside the knob
    Pause or close if maintainers decide tool-result progress is intentionally outside the suppressToolErrors contract.

Next step before merge

  • [P2] No repair job is needed; the remaining action is maintainer acceptance of the intentional config-gated message-delivery change and normal merge review.

Security
Cleared: The diff touches only reply dispatch logic and a colocated test; it does not change dependencies, workflows, secrets, permissions, or code-execution surfaces.

Review details

Best possible solution:

Land this focused dispatch-boundary fix after maintainers accept the intentional config-gated message-delivery change, then treat #88898 as superseded by this clean replacement.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: current main forwards payload.isError tool results through onToolResult/sendToolResult without checking messages.suppressToolErrors, while the warning-builder path already honors the knob. I did not run a local test because this review is read-only.

Is this the best way to solve the issue?

Yes, this is the best narrow fix: the leak is in dispatch progress delivery, and changing the payload builder or channel adapters would either miss the callback path or duplicate core policy. The default behavior remains unchanged unless the existing config knob is explicitly enabled.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 56c2d637d940.

Label changes

Label changes:

  • add P2: This is a normal-priority user-visible bug fix for a narrow reply-progress noise issue with limited blast radius.
  • add merge-risk: 🚨 message-delivery: The patch intentionally stops delivering error tool-result progress for users who have messages.suppressToolErrors enabled.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal/live-output proof from a deployed bundle showing suppressed error progress, preserved non-error progress, and preserved default error progress.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal/live-output proof from a deployed bundle showing suppressed error progress, preserved non-error progress, and preserved default error progress.

Label justifications:

  • P2: This is a normal-priority user-visible bug fix for a narrow reply-progress noise issue with limited blast radius.
  • merge-risk: 🚨 message-delivery: The patch intentionally stops delivering error tool-result progress for users who have messages.suppressToolErrors enabled.
  • 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-fix terminal/live-output proof from a deployed bundle showing suppressed error progress, preserved non-error progress, and preserved default error progress.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal/live-output proof from a deployed bundle showing suppressed error progress, preserved non-error progress, and preserved default error progress.
Evidence reviewed

PR surface:

Source +7, Tests +33. Total +40 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 7 0 +7
Tests 1 33 0 +33
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 40 0 +40

What I checked:

  • Repository policy applied: Full root policy was read and applied; message delivery and config behavior need source-path review, sibling-path checks, best-fix judgment, and merge-risk visibility. (AGENTS.md:1, 56c2d637d940)
  • Scoped maintainer note checked: Telegram maintainer notes were inspected because the proof uses a Telegram-direct context; the patch does not alter Telegram adapter ownership, topics, callbacks, authorization, or reply context. (.agents/maintainer-notes/telegram.md:1, 56c2d637d940)
  • Live PR state: Live GitHub data shows this PR is open, not draft, cleanly mergeable, and targets current main at 56c2d63; CI and security checks visible in the rollup were successful or skipped as expected. (fc00ccd27263)
  • Patch surface: The patch only adds a suppressToolErrors guard in dispatch-from-config.ts and one regression test in dispatch-from-config.test.ts. (src/auto-reply/reply/dispatch-from-config.ts:3128, fc00ccd27263)
  • Current-main bug path: Current main forwards payload.isError tool results through onToolResult and then sendToolResult or route-reply without checking messages.suppressToolErrors. (src/auto-reply/reply/dispatch-from-config.ts:3118, 56c2d637d940)
  • Existing config contract: The config type documents suppressToolErrors as suppressing tool-error warnings from being shown to the user, and schema/help entries expose the same knob. (src/config/types.messages.ts:173, 56c2d637d940)

Likely related people:

  • vai-oro: Authored merged PR feat: add messages.suppressToolErrors config option #16620 adding the messages.suppressToolErrors config surface and original warning suppression behavior. (role: introduced behavior; confidence: high; commits: 2c8b9210548d; files: src/config/types.messages.ts, src/config/schema.help.ts, src/config/zod-schema.session.ts)
  • moeedahmed: Authored merged PR fix: honour tool error suppression for mutating tools #81561, which extended suppressToolErrors to mutating tool warning payloads and added adjacent regression coverage. (role: recent adjacent contributor; confidence: high; commits: 9c00268914b9; files: src/agents/embedded-agent-runner/run/payloads.ts, src/agents/embedded-agent-runner/run/payloads.errors.test.ts)
  • Masato Hoshino: Current blame for the dispatch tool-result block points to recent broad refactor commit 888f399 in the same reply-dispatch and payload files. (role: recent area contributor; confidence: medium; commits: 888f399499c4; files: src/auto-reply/reply/dispatch-from-config.ts, 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 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. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 30, 2026
@vincentkoc vincentkoc self-assigned this Jul 1, 2026
@vincentkoc
vincentkoc merged commit c99add6 into openclaw:main Jul 1, 2026
141 of 146 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS 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.

3 participants