Skip to content

feat(whatsapp,telegram): add groupPolicy config option#216

Merged
thewilloftheshadow merged 10 commits intoopenclaw:mainfrom
mneves75:feat/whatsapp-group-policy
Jan 6, 2026
Merged

feat(whatsapp,telegram): add groupPolicy config option#216
thewilloftheshadow merged 10 commits intoopenclaw:mainfrom
mneves75:feat/whatsapp-group-policy

Conversation

@mneves75
Copy link
Contributor

@mneves75 mneves75 commented Jan 5, 2026

Summary

Adds groupPolicy config option to WhatsApp and Telegram for controlling group message handling.

The Problem

Users expect allowFrom to restrict all communication, but groups bypass this check entirely (by design - they use mention-gating instead). This leaves no way to block group messages completely.

Solution

New groupPolicy option with 3 modes:

Policy Behavior
open Default. Groups bypass allowFrom, only mention-gating applies.
disabled Block all group messages entirely.
allowlist Only respond if sender is in allowFrom.
{
  whatsapp: {
    allowFrom: ["+15551234567"],
    groupPolicy: "disabled"
  },
  telegram: {
    allowFrom: ["123456789", "@username", "telegram:123456789"],
    groupPolicy: "disabled"
  }
}

Implementation Details

  • Shared schema: Extracted GroupPolicySchema constant for DRY validation
  • Consistent field ordering: groupPolicy follows allowFrom in both schemas
  • WhatsApp: Matches sender's E.164 against normalized allowFrom
  • Telegram: Matches sender by user ID or username (case-insensitive, with/without @ prefix)
  • Telegram prefix support: telegram:123456789 format works in group allowlist
  • Pre-computed allowlist values for efficiency (no redundant .map() calls per message)

Changes

File Change
src/config/zod-schema.ts Shared GroupPolicySchema constant with explanatory comment
src/config/types.ts Add groupPolicy to WhatsAppConfig and TelegramConfig
src/web/inbound.ts WhatsApp group policy filtering
src/telegram/bot.ts Telegram group policy filtering with prefix stripping
src/web/monitor-inbox.test.ts 4 tests for WhatsApp (incl. wildcard)
src/telegram/bot.test.ts 10 tests for Telegram (incl. prefixed ID)
docs/groups.md Accurate documentation for both surfaces
docs/plans/group-policy-hardening.md Engineering execution spec

Self-Critique Fixes (Hardening)

Finding Severity Fix
Telegram group allowlist ignores telegram: prefix MED Strip prefix during normalization
Docs say allowFrom only filters DMs LOW Clarified that allowlist mode uses it for groups
Zod .default().optional() pattern undocumented LOW Added explanatory comment
Missing WhatsApp wildcard test TEST Added test for allowFrom: ["*"]
Missing Telegram prefixed ID test TEST Added test for telegram:123456789 format

Backwards Compatibility

Default is open - existing users see no behavior change.

Test Plan

  • All 888 tests pass (2 new tests added)
  • groupPolicy: "disabled" blocks all group messages
  • groupPolicy: "allowlist" filters by sender (ID or username)
  • groupPolicy: "open" (default) preserves existing behavior
  • Case-insensitive username matching for Telegram
  • Wildcard ["*"] allows all senders in allowlist mode
  • telegram:123456789 prefix works in group allowlist

@mneves75 mneves75 changed the title feat(whatsapp): add groupPolicy config option feat(whatsapp,telegram): add groupPolicy config option Jan 5, 2026
@steipete
Copy link
Contributor

steipete commented Jan 5, 2026

🦞 Automated Code Review (Codex)

Findings:

  • [MED] Telegram group allowlist ignores telegram:-prefixed allowFrom entries; only raw id/username match. src/telegram/bot.ts:105-122. If users reuse the same list with groupPolicy: "allowlist", groups get blocked. Suggest: accept prefixed ids/usernames in group allowlist or document it as unsupported.
  • [LOW] Docs contradiction: docs/groups.md:41-43 says allowFrom only filters DMs, but allowlist mode uses allowFrom for groups. Clarify note.
  • [LOW] Zod default + optional likely drops default. src/config/zod-schema.ts:546-581 uses GroupPolicySchema.default("open").optional(). Consider dropping .optional() or rely on runtime default consistently.

Test gaps / suggestions:

  • Add WhatsApp wildcard allowlist test (groupPolicy: "allowlist", allowFrom: ["*"]) to mirror Telegram coverage.
  • Add Telegram test for telegram:<id> allowFrom if you decide to support it.

Question: Should Telegram group allowlist accept telegram:<id> for consistency with DM allowlist docs, or is that intentionally DM-only?


Reviewed by Clawd 🦞 via Codex (53k tokens)

@mneves75
Copy link
Contributor Author

mneves75 commented Jan 5, 2026

Thanks! Addressed the findings:

  • Telegram allowlist now trims entries and strips telegram:/tg: prefixes case-insensitively; the same normalized list is used for DM + group checks.
  • Added tests for DM allowlist with TG: + whitespace and group allowlist with TG: prefix.
  • Docs updated in docs/groups.md + docs/telegram.md to reflect allowlist usage and prefix support.

On the Zod .default().optional() note: left as-is; it’s intentional so input can omit the field while runtime resolves to "open". Happy to add a comment if you want it explicit.

I didn’t add the WhatsApp wildcard allowlist test yet; can add if you’d like.

@mneves75
Copy link
Contributor Author

mneves75 commented Jan 5, 2026

Follow-up for the review asks:

  • Added DM allowlist test for telegram:<id> in src/telegram/bot.test.ts (commit 50f6556).
  • WhatsApp wildcard allowlist test already exists in src/web/monitor-inbox.test.ts (allows all group senders with wildcard in groupPolicy allowlist), so no extra change needed there.

@mneves75
Copy link
Contributor Author

mneves75 commented Jan 5, 2026

Re-ran tests after adding the DM telegram: allowlist case. Note: pnpm test -- src/telegram/bot.test.ts still runs the full suite here.

Result: PASS — 160 files passed, 2 skipped (live tests).

@thewilloftheshadow thewilloftheshadow force-pushed the feat/whatsapp-group-policy branch from 50f6556 to 93f3390 Compare January 6, 2026 04:38
@thewilloftheshadow thewilloftheshadow merged commit 9ab0b88 into openclaw:main Jan 6, 2026
11 of 13 checks passed
dgarson added a commit to dgarson/clawdbot that referenced this pull request Feb 7, 2026
* feat: phase 0 to 3 for meridia enhancements/refactoring

* feat(meridia): phase 2 refactoring — sanitize, migrations, fanout, adapter tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: clean up stray brace and unused imports from merge resolution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(meridia): use readPositiveNumber for compaction/capture thresholds

readNumber accepts 0/negative values, but scheduleIntervalHours,
minExperiencesForCompaction, maxPerHour, minIntervalMs etc. must be
positive. Previously, the old local helpers enforced > 0; this was
lost when readNumber was extracted to event.ts. Switch to
readPositiveNumber which falls back to defaults for non-positive values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
Co-authored-by: Marcus Neves <conhecendo.contato@gmail.com>
Co-authored-by: Shadow <hi@shadowing.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants