feat: unified group modes (open/listen/mention-only) (#267)

Consolidates listeningGroups and groups.requireMention into a single
groups config with explicit mode per group. Backward compatible --
legacy formats auto-normalize with deprecation warnings.

- Add shared group-mode.ts with isGroupAllowed/resolveGroupMode helpers
- Update all 5 channel adapters to use mode-based gating
- Default to mention-only for configured entries (safe), open when no config
- Listening mode now set at adapter level, bot.ts has legacy fallback
- Fix YAML large-ID parsing for groups map keys (Discord snowflakes)
- Add migration in normalizeAgents for listeningGroups + requireMention
- Add unit tests for group-mode helpers + update all gating tests
- Update docs, README, and example config

Closes #266

Written by Cameron and Letta Code

"Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away." -- Antoine de Saint-Exupery
This commit is contained in:
Cameron
2026-02-10 16:01:21 -08:00
committed by GitHub
parent 745291841d
commit c410decd18
23 changed files with 677 additions and 274 deletions

View File

@@ -265,6 +265,30 @@ channels:
The deprecated `groupPollIntervalMin` (minutes) still works for backward compatibility but `groupDebounceSec` takes priority.
### Group Modes
Use `groups.<id>.mode` to control how each group/channel behaves:
- `open`: process and respond to all messages (default behavior)
- `listen`: process all messages for context/memory, only respond when mentioned
- `mention-only`: drop group messages unless the bot is mentioned
You can also use `*` as a wildcard default:
```yaml
channels:
telegram:
groups:
"*": { mode: listen }
"-1001234567890": { mode: open }
"-1009876543210": { mode: mention-only }
```
Deprecated formats are still supported and auto-normalized with warnings:
- `listeningGroups: ["id"]` -> `groups: { "id": { mode: listen } }`
- `groups: { "id": { requireMention: true/false } }` -> `mode: mention-only/open`
### DM Policies
**Note:** For WhatsApp/Signal with `selfChat: true` (personal number), dmPolicy is ignored - only you can message via "Message Yourself" / "Note to Self".