Skip to content

feat(channels): add neverReply config for group message suppression#42400

Open
cayde-6 wants to merge 15 commits intoopenclaw:mainfrom
cayde-6:feat/never-reply-group-policy
Open

feat(channels): add neverReply config for group message suppression#42400
cayde-6 wants to merge 15 commits intoopenclaw:mainfrom
cayde-6:feat/never-reply-group-policy

Conversation

@cayde-6
Copy link
Copy Markdown

@cayde-6 cayde-6 commented Mar 10, 2026

Note

AI-assisted PR (Claude Opus 4.6). Fully tested via automated suite (873 files, 7113 tests, 0 failures). Author understands all changes and has resolved all bot review conversations.

Summary

  • Problem: No way to make the bot passively observe group messages without replying. Existing workarounds (requireMention: true, NO_REPLY system prompt, log scraping) are either too restrictive, waste tokens, or are fragile.
  • Why it matters: Users monitoring many group chats (school, work, client) need passive observation with context accumulation but zero outbound risk.
  • What changed: Added neverReply boolean config option across all 14 channels (7 built-in + 7 extensions). When enabled, group messages pass access control, get recorded into pending history, but no LLM call or reply is dispatched. DMs are unaffected.
  • What did NOT change (scope boundary): No transport-level outbound blocking (that's Feature request: Listen-only / suppress-outbound channel mode for WhatsApp #22791). No hook/plugin integration for silent ingest (that's PR Add Silent Ingest for Group Chat Messages #15841). No changes to requireMention, groupPolicy, or existing message flow.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • New config option channels.<channel>.neverReply: true (and channels.defaults.neverReply)
  • When enabled on a channel, group messages are silently stored as context history without triggering LLM or sending replies
  • Config resolution follows account > channel > defaults cascade
  • DMs are not affected by this setting

Quick start

channels:
  telegram:
    groupPolicy: open
    neverReply: true    # observe all groups, never reply

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

No new attack surface. neverReply only suppresses outbound replies; it does not expand which groups or senders are accepted (that's controlled by groupPolicy and allowlists as before).

Repro + Verification

Environment

  • OS: macOS 26.3 (arm64)
  • Runtime: Node 22+ / Bun
  • Integration/channel: All 14 group-capable channels

Steps

  1. Set channels.telegram.neverReply: true in config
  2. Send a message in a Telegram group where the bot is present
  3. Observe that no reply is sent
  4. Send a DM — verify the bot still replies normally

Expected

  • Bot does not reply to the group message
  • Message is recorded in pending group history
  • DMs continue working normally

Actual

  • Confirmed: no reply dispatched, history entry recorded with correct sender/body/timestamp
  • DMs unaffected

Evidence

  • Failing test/log before + passing after
  • 873 test files, 7113 tests passed, 0 failed
  • 20 new neverReply-specific tests covering:
    • Config resolution (9 tests): account/channel/defaults cascade, boolean semantics
    • Discord (1 test): drop + history recording
    • Telegram (3 tests): body-level drop + history recording + DM passthrough + bot-level integration
    • Signal (1 test): drop + history recording
    • WhatsApp (1 test): drop + history content verification
    • Slack (1 test): drop + history recording
    • iMessage (3 tests): drop + history recording + DM passthrough
    • Schema quality (1 test): label parity

Human Verification (required)

  • Verified scenarios: All 14 channels compile and pass type checks; message drop and history recording verified via unit tests for each channel; history keys scoped by accountId to prevent multi-account context leakage
  • Edge cases checked: DMs not affected; account-level override; defaults fallback; empty history (historyLimit=0); multi-account isolation
  • What I did NOT verify: Live end-to-end testing on actual messaging platforms

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

All 23 bot review threads (Greptile + Codex) addressed and resolved across 4 review rounds.

Compatibility / Migration

  • Backward compatible? YesneverReply defaults to undefined/false, preserving existing behavior
  • Config/env changes? Yes — new optional neverReply field in channel config schemas
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: remove neverReply from config; bot reverts to normal reply behavior immediately
  • Files/config to restore: user config only (no data migration)
  • Known bad symptoms reviewers should watch for: bot unexpectedly not replying to groups → check if neverReply is set

Risks and Mitigations

  • Risk: User sets neverReply at defaults level and forgets, causing all channels to go silent in groups
    • Mitigation: neverReply defaults to false; help text in schema.help.ts explains the option; config shows neverReply: true explicitly when set

cayde-6 added 5 commits March 10, 2026 18:27
…ssion

Add resolveNeverReply() helper with account > channel > defaults cascade.
Add neverReply to config schema, types, Zod validation, help text, and labels.
Export resolveNeverReply from all per-channel plugin SDK subpaths.

Discussion: https://github.com/openclaw/openclaw/discussions/42396
Wire resolveNeverReply into group message handlers for Telegram, Discord,
Slack, Signal, WhatsApp, and iMessage. Dropped messages are recorded as
pending history entries so context is preserved for future replies.
Wire resolveNeverReply into group message handlers for Matrix, MS Teams,
Mattermost, Google Chat, BlueBubbles, Zalo, and ZaloUser extensions.
Add 20 new tests covering config resolution (account/channel/defaults cascade),
message drop, history recording with content verification, and DM passthrough
for Telegram, Discord, Slack, Signal, WhatsApp, and iMessage.
Add neverReply to the group policy flow diagram, quick-start table,
and a dedicated section explaining behavior, config examples, and
relationship to requireMention.
@openclaw-barnacle openclaw-barnacle bot added docs Improvements or additions to documentation channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser size: L labels Mar 10, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR adds a neverReply boolean config option across all 14 group-capable channels. When enabled, the bot passively records group messages into pending history but never triggers an LLM run or sends a reply; DMs are unaffected. The implementation follows the established groupPolicy / requireMention ordering (disabled → allowlist gating → neverReply → mention gating → reply), and the config cascade (account > channel > defaults) is correctly implemented via the new resolveNeverReply helper.

All issues flagged in previous review rounds (history not recorded in 6 channels, Line and IRC missing implementations, MSTeams/WhatsApp accountId not threaded, Mattermost/ZaloUser write-key ≠ read-key, GoogleChat wall-clock timestamp) have been successfully addressed in this revision. The core feature is complete, well-tested, and backward-compatible.

Confidence Score: 5/5

  • Safe to merge—all critical issues from prior reviews have been resolved. The feature is backward-compatible and well-tested.
  • All previously flagged issues have been verified as fixed: history is properly recorded in all 14 channels (including the 6 that had missing calls), Line and IRC have complete implementations with account-scoped history keys, Mattermost and ZaloUser use consistent write/read keys, MSTeams/WhatsApp properly thread accountId, and GoogleChat uses correct event timestamps. The config cascade is properly implemented, DMs are unaffected, and the feature defaults to false for backward compatibility. The codebase passes 873 tests with 0 failures.
  • No files require special attention. All channel implementations are consistent and correct.

Last reviewed commit: fe0af6d

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1f77feb06a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Pass accountId to resolveNeverReply in Discord, MSTeams, and WhatsApp
  so account-level overrides work correctly
- Add recordPendingHistoryEntryIfEnabled calls in BlueBubbles, Mattermost,
  GoogleChat, Matrix, Zalo, and ZaloUser before early return
- Add neverReply implementation to Line monitor (was config-only stub)
- Export history helpers from googlechat, matrix, and zalo plugin SDK
@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

All review findings from Greptile and Codex have been addressed in commit 54a04e1:

1. History recording added to 6 extension channels (BlueBubbles, Mattermost, GoogleChat, Matrix, Zalo, ZaloUser)

  • Each now calls recordPendingHistoryEntryIfEnabled before the early return, matching the pattern used in built-in channels

2. Line monitor implementation added

  • Was config-only stub; now has a proper resolveNeverReply check with early return in src/line/monitor.ts

3. accountId passed everywhere

  • Discord: uses resolvedAccountId (from params.accountId ?? DEFAULT_ACCOUNT_ID)
  • MSTeams: uses DEFAULT_ACCOUNT_ID (neverReply check happens before route resolution)
  • WhatsApp: added accountId to ApplyGroupGatingParams, passed from route.accountId in caller

All 14 channels now consistently: pass accountId, record pending history, and log the drop.

Full test suite passes: 873 files, 7113 tests, 0 failures.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54a04e1365

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@greptile review
@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54a04e1365

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ed8b90a551

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f150a378c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@greptile-apps review

All review comments have been addressed:

  • Google Chat, Matrix, Zalo: wired up buildPendingHistoryContextFromMap so recorded history is consumed
  • Line: moved neverReply check to bot-handlers.ts for proper history recording
  • IRC: added neverReply implementation
  • Discord, MSTeams, WhatsApp: added accountId to resolveNeverReply calls
  • BlueBubbles, Mattermost, ZaloUser: added recordPendingHistoryEntryIfEnabled before early returns

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@chatgpt-codex-connector review

All review comments have been addressed — see replies on each thread.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f150a378c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a5404302f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@steipete @joshp123 This PR is ready for review.

What it does: Adds neverReply config option across all 14 channels — when enabled, the bot passively observes group messages (recording them as pending history context) without triggering LLM calls or sending replies. DMs are unaffected.

Status:

  • All CI checks passing (except install-smoke — Docker buildx infra crash, unrelated)
  • 873 test files, 7113 tests, 0 failures
  • All 23 bot review conversations addressed and resolved across 4 review rounds
  • Discussion: #42396

Happy to address any feedback!

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@greptile-apps review

IRC neverReply history recording was added in a540430channelHistories map, recordPendingHistoryEntryIfEnabled, and buildPendingHistoryContextFromMap are all wired up. GoogleChat timestamp issue also fixed (uses event.eventTime instead of Date.now()). Please re-evaluate.

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@greptileai review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 87be133f2d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@greptileai review

All issues from previous review addressed in 88800bd:

  • Mattermost key mismatch: moved route computation before neverReply, now uses route.sessionKey on both write and read paths
  • ZaloUser key mismatch: same fix — moved route computation before neverReply, uses route.sessionKey
  • MSTeams empty-body guard: added rawBody ? {...} : null guard matching all other channels
  • History clearing: added clearHistoryEntriesIfEnabled after dispatch in Matrix, Zalo, GoogleChat, and IRC (matching existing Discord/Mattermost/MSTeams/ZaloUser pattern)
  • Telegram audio preflight: moved neverReply check before audio transcription to avoid wasting compute

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88800bd205

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cayde-6
Copy link
Copy Markdown
Author

cayde-6 commented Mar 10, 2026

@greptileai review

Line historyKey now uses ${account.accountId}:${groupId ?? roomId} consistently across all write paths (neverReply, requireMention skip) and the read path (bot-message-context.ts), matching the accountId-scoped pattern used by all other channels. This was the last remaining caveat from the 4/5 review.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe0af6d129

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@flowolforg
Copy link
Copy Markdown

Great work on this – the 14-channel coverage is impressive, and the platform-specific edge cases you found (IRC historyLimit asymmetry, Matrix pending-history-clearing, Mattermost session key mismatches) are the kind of thing that only surfaces through thorough cross-platform testing.

We explored the same problem from a different angle. We noticed that the inbound_claim hook infrastructure from PR #45318 already exists but only fires for plugin-bound conversations. Issue #48434 describes the gap: if the hook is broadcast to all registered plugins (~6 lines in dispatch-from-config.ts), the entire listen-only logic can live in a plugin – no channel-handler modifications needed.

On top of the silence, we added an L0/L1 memory pipeline: raw message logging (no LLM cost) + periodic Haiku summaries. This covers the "context over time" problem that pendingHistory can't solve – when the batch or history has been flushed, L0/L1 still has the full record.

One architectural difference worth noting: pendingHistory flushes into the normal message context, so the LLM sees accumulated messages as regular conversation turns with the full soul.md/identity.md enrichment. Our approach injects the batch as a separate prependContext block via before_prompt_build – the LLM can distinguish background context from direct interaction. This helps with the rule-conflict issue described in #41366.

Your platform-specific fixes are genuinely valuable though – the hook-broadcast approach solves the architecture, but it doesn't automatically surface IRC or Mattermost edge cases. Would be great to discuss whether a combined path makes sense: hook-broadcast for the infrastructure, your channel-level fixes where needed, and L0/L1 for long-term context.

Repo: https://github.com/flowolforg/openclaw-listen-only

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

Labels

channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: irc channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser docs Improvements or additions to documentation size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants