From a3228977fb436f741a16655614a9d4bd3f3341a7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 30 Apr 2026 15:53:09 +0100 Subject: [PATCH] test(signal): cover group mention gating defaults --- docs/channels/groups.md | 1 + docs/channels/signal.md | 1 + .../event-handler.inbound-context.test.ts | 38 +++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/docs/channels/groups.md b/docs/channels/groups.md index 3fb4669eb6b..47cb60c0a31 100644 --- a/docs/channels/groups.md +++ b/docs/channels/groups.md @@ -332,6 +332,7 @@ Replying to a bot message counts as an implicit mention when the channel support - Surfaces that provide explicit mentions still pass; patterns are a fallback. - Per-agent override: `agents.list[].groupChat.mentionPatterns` (useful when multiple agents share a group). - Mention gating is only enforced when mention detection is possible (native mentions or `mentionPatterns` are configured). + - Allowlisting a group or sender does not disable mention gating; set that group's `requireMention` to `false` when all messages should trigger. - Group chat prompt context carries the resolved silent-reply instruction every turn; workspace files should not duplicate `NO_REPLY` mechanics. - Groups where silent replies are allowed treat clean empty or reasoning-only model turns as silent, equivalent to `NO_REPLY`. Direct chats do the same only when direct silent replies are explicitly allowed; otherwise empty replies remain failed agent turns. - Discord defaults live in `channels.discord.guilds."*"` (overridable per guild/channel). diff --git a/docs/channels/signal.md b/docs/channels/signal.md index c598695e02c..e384c6d32f9 100644 --- a/docs/channels/signal.md +++ b/docs/channels/signal.md @@ -197,6 +197,7 @@ Groups: - `channels.signal.groupAllowFrom` controls which groups or senders can trigger group replies when `allowlist` is set; entries can be Signal group IDs (raw, `group:`, or `signal:group:`), sender phone numbers, or `uuid:` values. - `channels.signal.groups["" | "*"]` can override group behavior with `requireMention`, `tools`, and `toolsBySender`. - Use `channels.signal.accounts..groups` for per-account overrides in multi-account setups. +- Allowlisting a Signal group does not disable mention gating. To process every message in an allowlisted group, set `channels.signal.groups[""].requireMention=false` or use the `"*"` group default. - Runtime note: if `channels.signal` is completely missing, runtime falls back to `groupPolicy="allowlist"` for group checks (even if `channels.defaults.groupPolicy` is set). ## How it works (behavior) diff --git a/extensions/signal/src/monitor/event-handler.inbound-context.test.ts b/extensions/signal/src/monitor/event-handler.inbound-context.test.ts index cf7c7e6388c..3ad3aa6f644 100644 --- a/extensions/signal/src/monitor/event-handler.inbound-context.test.ts +++ b/extensions/signal/src/monitor/event-handler.inbound-context.test.ts @@ -248,6 +248,44 @@ describe("signal createSignalEventHandler inbound context", () => { expect(capture.ctx?.From).toBe("group:g1"); }); + it("keeps mention gating enabled for group-id allowlists by default", async () => { + const groupHistories = new Map(); + const handler = createSignalEventHandler( + createBaseSignalEventHandlerDeps({ + cfg: { + messages: { + inbound: { debounceMs: 0 }, + groupChat: { mentionPatterns: ["@bot"] }, + }, + channels: { + signal: { + groupPolicy: "allowlist", + groupAllowFrom: ["g1"], + }, + }, + }, + groupPolicy: "allowlist", + groupAllowFrom: ["g1"], + groupHistories, + historyLimit: 5, + }), + ); + + await handler( + createSignalReceiveEvent({ + dataMessage: { + message: "hello without mention", + groupInfo: { groupId: "g1", groupName: "Test Group" }, + attachments: [], + }, + }), + ); + + expect(capture.ctx).toBeUndefined(); + expect(dispatchInboundMessageMock).not.toHaveBeenCalled(); + expect(groupHistories.get("g1")?.[0]?.body).toBe("hello without mention"); + }); + it("blocks Signal groups whose id is not listed in groupAllowFrom", async () => { const handler = createSignalEventHandler( createBaseSignalEventHandlerDeps({