You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Default automatic-delivery Matrix multi-person rooms can receive internal tool/progress events as visible chat messages on non-room_event turns; reproduced 2026-05-21.
Steps to reproduce
Run OpenClaw 2026.5.19 (commit 85852b5cc3 on upstream/main-tracking branch) with the Matrix channel extension bound to a multi-person Matrix room (not a DM with the bot user).
Bind an agent session to that room (non-room_event inbound — i.e. an ordinary user message reply turn). Use default automatic delivery mode: no sourceReplyDeliveryMode: "message_tool_only" opt-in, no verboseLevel: "on".
Trigger any tool-heavy operation: file read, search, patch apply, exec.
Observe the Matrix room: internal tool-progress summaries appear as visible chat messages, e.g. 🛠️ print lines..., 🛠️ search..., 🩹 Apply Patch, 🔌 Gateway: messages.
Expected behavior
Default-mode multi-person rooms (ChatType: "channel" or "group") should not receive internal tool summaries or verbose progress events. This matches the existing behavior for ChatType: "group" (carve-out at dispatch-from-config.ts:1231: ctx.ChatType !== "group" || ctx.IsForum === true) and for Slack non-direct (carve-out via isSlackNonDirectSurface).
The explicit message_tool_only and verboseLevel: "on" paths, restored by PR #80042, should continue to deliver verbose tool progress on channel turns. The existing test at src/auto-reply/reply/dispatch-from-config.test.ts:5211 ("delivers verbose tool progress in message-tool-only mode") encodes that contract and must stay green.
Actual behavior
Default-mode Matrix channel turns (ChatType: "channel", no message_tool_only, no verboseLevel: "on", non-room_event) emit internal tool/progress events into the visible Matrix chat surface. Observed 2026-05-21 in a private Matrix room (name redacted) during ordinary investigation work (file reads, search, patch apply).
OpenClaw version
2026.5.19 (build 85852b5cc3c0c39086a27c7df6c14576a48ddd0f, built 2026-05-20T17:11Z).
The reproduced deployment tracks upstream/main with a small set of unrelated local patches (audience field for hidden runtime context, trajectory null-safety which is now also in main via #84797). None of the local patches touch dispatch-from-config.ts, extensions/matrix/, or the verbose-progress / tool-summary code paths — verified by git log --name-only upstream/main..mercury/local-patches.
Operating system
macOS 14.7.6 (Darwin 23.6.0, x86_64).
Install method
pnpm dev build (pnpm build against the tracking branch; daemon launched via /Library/LaunchDaemons/ai.openclaw.gateway.plist).
Model
NOT_ENOUGH_INFO
(The bug is in dispatch-context routing logic, not model-dependent; the specific model for the leaked turn was not captured.)
No relevant agent/model overrides for this case — the bug surfaces at dispatch context routing before any model call. Default effectiveVisibleReplies (none of automatic / message_tool was explicitly set on the affected session). No safe-debug-room configuration enabled.
Logs, screenshots, and evidence
# Symptoms observed in a private Matrix room transcript (room name and id redacted):
🛠️ print lines...
🛠️ search...
🩹 Apply Patch
🔌 Gateway: messages
Source-level evidence (verifiable on upstream/main at the time of writing):
The predicate gap: src/auto-reply/reply/dispatch-from-config.ts:1228-1232
For Matrix ChatType: "channel": isSlackNonDirectSurface is false (not Slack) and ctx.ChatType !== "group" is true ("channel" ≠ "group"), so verbose progress and tool summaries are allowed.
Matrix emits "channel" for non-DMs: extensions/matrix/src/matrix/monitor/handler.ts:1351, extensions/matrix/src/session-route.ts:103.
ChatType is typed as "direct" | "group" | "channel" in src/channels/chat-type.ts; normalizeChatType() is already exported.
Sibling files already pair "group" and "channel" correctly: src/auto-reply/reply/source-reply-delivery-mode.ts:59, 65; completion-delivery-policy.ts:64; agent-runner-execution.ts:486; reply-threading.ts:23; get-reply-run.ts:109, 691; src/auto-reply/dispatch.ts:132. The predicate at dispatch-from-config.ts:1230 is the outlier.
Existing contract that the fix must preserve: src/auto-reply/reply/dispatch-from-config.test.ts:5211 requires ChatType: "channel" + sourceReplyDeliveryMode: "message_tool_only" + verboseLevel: "on" to deliver verbose tool progress. Restored by PR Fix Discord verbose tool progress delivery #80042 (commit 57da466ec).
Existing room_event suppression at dispatch-from-config.test.ts:2243 covers ambient room-event turns and should keep passing.
Impact and severity
Affected: Sessions bound to multi-person Matrix rooms in default automatic-delivery mode. Source-level admission also extends to non-Slack channel-class surfaces (Discord, Mattermost, MS Teams, Google Chat, WhatsApp newsletter, Synology Chat, ClickClack, Feishu, QA channel — none separately reproduced).
Severity: Privacy-sensitive. Internal tool/progress summaries can carry local file paths, command names, search terms, and operationally sensitive context. Maintainers to decide on impact:security label.
Frequency: Observed deterministically on the affected setup whenever a tool-heavy operation runs on a default-mode Matrix channel turn (single repro environment; not separately measured across deployments).
Consequence: Privacy exposure in the visible chat surface; operational noise; risk of leaking implementation details to non-operator participants.
Additional information
Cross-references (state and labels should be re-confirmed by triage)
Fix Discord verbose tool progress delivery #80042 — "Fix Discord verbose tool progress delivery" (merged 2026-05-17, commit 57da466ec). Intentionally restored verbose tool progress for explicit message_tool_only channel turns. The fix here must not regress that behavior; existing test at :5211 is the regression guard.
The prefersMessageToolDelivery masking story is analysis based on diff inspection; the precise "what changed in default visibility" should be confirmed by a pre/post dispatch-from-config.test.ts run, which has not been performed for this report.
Date
Commit / PR
Effect
2026-04-24
76a4c167f7e (closes #69067, "fix(slack): suppress verbose progress in rooms")
Introduces predicate ctx.ChatType !== "group" || ctx.IsForum === true. Slack carve-out only. Latent gap for non-Slack channel surfaces.
2026-04-24 → 2026-05-18
—
Gap may have been masked in default operation by prefersMessageToolDelivery auto-allowing the message tool for group/channel turns; precise interaction unverified.
Removed the channel-aware prefersMessageToolDelivery clause. Predicate gap visible in default-mode non-room_event turns on channel-class surfaces.
2026-05-21
—
Reproduced on Matrix during tool-heavy agent work in default automatic delivery mode.
Surfaces that source-admit ChatType: "channel"
Known examples on upstream/main (not exhaustive; source-suspect, not separately reproduced; Slack non-DM is already covered by the isSlackNonDirectSurface guard):
Discord: extensions/discord/src/monitor/message-handler.process.ts:212-219; inbound envelope at message-handler.context.ts:333-358. Existing room_event test at :2243 and message_tool_only test at :5211 constrain the fix.
QQ bot: wider c2c|group|guild|dm|channel alternation at extensions/qqbot/src/engine/utils/request-context.ts:33; benefits from normalization at the dispatch boundary.
Shared inbound builder at src/channels/inbound-event/context.ts:194 passes params.conversation.kind through as ChatType.
Suggested fix shape (proposal, not part of the bug report)
The desired policy:
Slack non-direct: suppress (existing behavior; preserved by isSlackNonDirectSurface).
ChatType: "channel": suppress by default (NEW — this is the bug fix) unlessIsForum === true or sourceReplyDeliveryMode === "message_tool_only" (preserves PR Fix Discord verbose tool progress delivery #80042's explicit-mode contract verified by dispatch-from-config.test.ts:5211).
ChatType: "direct": allow (existing behavior).
Note on the cascade: dispatch-from-config.ts:1234-1240 defines shouldDeliverVerboseProgressDespiteSourceSuppression which is itself gated on shouldSendVerboseProgressMessages. Any change that makes the predicate return false for channel unconditionally would also kill the explicit-mode opt-in path. The proposal below threads sourceReplyDeliveryMode into the predicate to keep that path intact.
Concrete shape (illustrative; maintainers may prefer a different factoring):
isSlackNonDirectSurface guard stays (catches missing/unknown ChatType on Slack non-direct that a strict normalizeChatType-based helper would not).
Forum carve-out preserved.
Must keep dispatch-from-config.test.ts:5211 green (PR Fix Discord verbose tool progress delivery #80042's ChatType: "channel" + sourceReplyDeliveryMode: "message_tool_only" + verboseLevel: "on" contract). The proposal above includes isChannelExplicitMessageToolOptIn specifically to preserve that path so the cascade at :1234-1240 still fires.
Until merged: avoid running tool-heavy investigations from a session bound to a multi-person Matrix room in default-mode delivery. Use a DM, the web dashboard, or a dedicated safe room; return only a final summary to the public room.
Suggested labels
bug, bug:behavior, regression, matrix, gateway. Maintainers to decide on P1 and impact:security given the evidence is source-level plus one Matrix repro.
Bug type
Regression (worked before, now fails)
Beta release blocker
No
Summary
Default automatic-delivery Matrix multi-person rooms can receive internal tool/progress events as visible chat messages on non-
room_eventturns; reproduced 2026-05-21.Steps to reproduce
2026.5.19(commit85852b5cc3onupstream/main-tracking branch) with the Matrix channel extension bound to a multi-person Matrix room (not a DM with the bot user).room_eventinbound — i.e. an ordinary user message reply turn). Use default automatic delivery mode: nosourceReplyDeliveryMode: "message_tool_only"opt-in, noverboseLevel: "on".🛠️ print lines...,🛠️ search...,🩹 Apply Patch,🔌 Gateway: messages.Expected behavior
Default-mode multi-person rooms (
ChatType: "channel"or"group") should not receive internal tool summaries or verbose progress events. This matches the existing behavior forChatType: "group"(carve-out atdispatch-from-config.ts:1231:ctx.ChatType !== "group" || ctx.IsForum === true) and for Slack non-direct (carve-out viaisSlackNonDirectSurface).The explicit
message_tool_onlyandverboseLevel: "on"paths, restored by PR #80042, should continue to deliver verbose tool progress on channel turns. The existing test atsrc/auto-reply/reply/dispatch-from-config.test.ts:5211("delivers verbose tool progress in message-tool-only mode") encodes that contract and must stay green.Actual behavior
Default-mode Matrix channel turns (
ChatType: "channel", nomessage_tool_only, noverboseLevel: "on", non-room_event) emit internal tool/progress events into the visible Matrix chat surface. Observed 2026-05-21 in a private Matrix room (name redacted) during ordinary investigation work (file reads, search, patch apply).OpenClaw version
2026.5.19(build85852b5cc3c0c39086a27c7df6c14576a48ddd0f, built 2026-05-20T17:11Z).The reproduced deployment tracks
upstream/mainwith a small set of unrelated local patches (audience field for hidden runtime context, trajectory null-safety which is now also in main via #84797). None of the local patches touchdispatch-from-config.ts,extensions/matrix/, or the verbose-progress / tool-summary code paths — verified bygit log --name-only upstream/main..mercury/local-patches.Operating system
macOS 14.7.6 (Darwin 23.6.0, x86_64).
Install method
pnpm dev build (
pnpm buildagainst the tracking branch; daemon launched via/Library/LaunchDaemons/ai.openclaw.gateway.plist).Model
NOT_ENOUGH_INFO(The bug is in dispatch-context routing logic, not model-dependent; the specific model for the leaked turn was not captured.)
Provider / routing chain
openclaw → matrix extension (extensions/matrix) → Matrix homeserver (multi-person room).Inbound classification:
extensions/matrix/src/matrix/monitor/handler.ts:1351emitsChatType: isDirectMessage ? "direct" : "channel". Outbound session routing:extensions/matrix/src/session-route.ts:103emitschatType = target.kind === "user" ? "direct" : "channel". Both verified onupstream/main.Additional provider/model setup details
No relevant agent/model overrides for this case — the bug surfaces at dispatch context routing before any model call. Default
effectiveVisibleReplies(none ofautomatic/message_toolwas explicitly set on the affected session). No safe-debug-room configuration enabled.Logs, screenshots, and evidence
Source-level evidence (verifiable on
upstream/mainat the time of writing):The predicate gap:
src/auto-reply/reply/dispatch-from-config.ts:1228-1232For Matrix
ChatType: "channel":isSlackNonDirectSurfaceis false (not Slack) andctx.ChatType !== "group"is true ("channel"≠"group"), so verbose progress and tool summaries are allowed.Matrix emits
"channel"for non-DMs:extensions/matrix/src/matrix/monitor/handler.ts:1351,extensions/matrix/src/session-route.ts:103.ChatTypeis typed as"direct" | "group" | "channel"insrc/channels/chat-type.ts;normalizeChatType()is already exported.Sibling files already pair
"group"and"channel"correctly:src/auto-reply/reply/source-reply-delivery-mode.ts:59, 65;completion-delivery-policy.ts:64;agent-runner-execution.ts:486;reply-threading.ts:23;get-reply-run.ts:109, 691;src/auto-reply/dispatch.ts:132. The predicate atdispatch-from-config.ts:1230is the outlier.Existing contract that the fix must preserve:
src/auto-reply/reply/dispatch-from-config.test.ts:5211requiresChatType: "channel"+sourceReplyDeliveryMode: "message_tool_only"+verboseLevel: "on"to deliver verbose tool progress. Restored by PR Fix Discord verbose tool progress delivery #80042 (commit57da466ec).Existing
room_eventsuppression atdispatch-from-config.test.ts:2243covers ambient room-event turns and should keep passing.Impact and severity
channel-class surfaces (Discord, Mattermost, MS Teams, Google Chat, WhatsApp newsletter, Synology Chat, ClickClack, Feishu, QA channel — none separately reproduced).impact:securitylabel.Additional information
Cross-references (state and labels should be re-confirmed by triage)
76a4c167f7e, 2026-04-24) closing this issue is the predicate this report extends.57da466ec). Intentionally restored verbose tool progress for explicitmessage_tool_onlychannel turns. The fix here must not regress that behavior; existing test at:5211is the regression guard.1e5450f23e). The trigger that made this gap visible in default operation — see Timeline below./reasoning onhas no effect on Matrix channel. Same surface family.messages.toolMessageLoggingoverride. Adjacent design space; not a clean root-fix for this predicate gap.Timeline (analysis, not direct observation)
The
prefersMessageToolDeliverymasking story is analysis based on diff inspection; the precise "what changed in default visibility" should be confirmed by a pre/postdispatch-from-config.test.tsrun, which has not been performed for this report.76a4c167f7e(closes #69067, "fix(slack): suppress verbose progress in rooms")ctx.ChatType !== "group" || ctx.IsForum === true. Slack carve-out only. Latent gap for non-Slackchannelsurfaces.prefersMessageToolDeliveryauto-allowing the message tool for group/channel turns; precise interaction unverified.57da466ec/ PR #80042message_tool_onlychannel turns. Any fix here must preserve this.1e5450f23e/ PR #83498channel-awareprefersMessageToolDeliveryclause. Predicate gap visible in default-mode non-room_eventturns onchannel-class surfaces.Surfaces that source-admit
ChatType: "channel"Known examples on
upstream/main(not exhaustive; source-suspect, not separately reproduced; Slack non-DM is already covered by theisSlackNonDirectSurfaceguard):extensions/discord/src/monitor/message-handler.process.ts:212-219; inbound envelope atmessage-handler.context.ts:333-358. Existingroom_eventtest at:2243andmessage_tool_onlytest at:5211constrain the fix.extensions/mattermost/src/session-route.ts:38,extensions/mattermost/src/mattermost/monitor-auth.ts:257,extensions/mattermost/src/mattermost/slash-http.ts:463.extensions/msteams/src/session-route.ts:32,monitor-handler/message-handler.ts:790.extensions/googlechat/src/monitor.ts:335.extensions/whatsapp/src/session-route.ts:18(newsletter targets emit"channel").extensions/synology-chat/src/inbound-event.ts:91.extensions/clickclack/src/inbound.ts:22, 38,channel.ts:125.chatTypes: ["direct", "channel"]atextensions/feishu/src/channel.ts:682.extensions/qa-channel/src/bus-client.ts:138, 145,channel-actions.ts:62, 71.c2c|group|guild|dm|channelalternation atextensions/qqbot/src/engine/utils/request-context.ts:33; benefits from normalization at the dispatch boundary.Shared inbound builder at
src/channels/inbound-event/context.ts:194passesparams.conversation.kindthrough asChatType.Suggested fix shape (proposal, not part of the bug report)
The desired policy:
isSlackNonDirectSurface).ChatType: "group": suppress unlessIsForum === true(existing behavior).ChatType: "channel": suppress by default (NEW — this is the bug fix) unlessIsForum === trueorsourceReplyDeliveryMode === "message_tool_only"(preserves PR Fix Discord verbose tool progress delivery #80042's explicit-mode contract verified bydispatch-from-config.test.ts:5211).ChatType: "direct": allow (existing behavior).Note on the cascade:
dispatch-from-config.ts:1234-1240definesshouldDeliverVerboseProgressDespiteSourceSuppressionwhich is itself gated onshouldSendVerboseProgressMessages. Any change that makes the predicate returnfalseforchannelunconditionally would also kill the explicit-mode opt-in path. The proposal below threadssourceReplyDeliveryModeinto the predicate to keep that path intact.Concrete shape (illustrative; maintainers may prefer a different factoring):
Optional shared helper alongside
normalizeChatType()insrc/channels/chat-type.ts:Critical constraints for the fix:
isSlackNonDirectSurfaceguard stays (catches missing/unknownChatTypeon Slack non-direct that a strictnormalizeChatType-based helper would not).dispatch-from-config.test.ts:5211green (PR Fix Discord verbose tool progress delivery #80042'sChatType: "channel"+sourceReplyDeliveryMode: "message_tool_only"+verboseLevel: "on"contract). The proposal above includesisChannelExplicitMessageToolOptInspecifically to preserve that path so the cascade at:1234-1240still fires.group: explicitmessage_tool_onlyopt-in keeps verbose progress onchannel(matches PR Fix Discord verbose tool progress delivery #80042) but does NOT ongroup(matches current behavior — not changed by PR Fix Discord verbose tool progress delivery #80042). If maintainers want symmetric behavior, that's a separate decision and should be called out in the fix PR."direct" | "group" | "channel"ChatTypecontract.Suggested new tests (for the fix PR, not part of this issue)
Cross-surface coverage can be parameterized on
Providerrather than duplicated per surface.Operational workaround (current Mercury deployment)
Until merged: avoid running tool-heavy investigations from a session bound to a multi-person Matrix room in default-mode delivery. Use a DM, the web dashboard, or a dedicated safe room; return only a final summary to the public room.
Suggested labels
bug,bug:behavior,regression,matrix,gateway. Maintainers to decide onP1andimpact:securitygiven the evidence is source-level plus one Matrix repro.