feat: move group mention gating to provider groups

This commit is contained in:
Peter Steinberger
2026-01-02 22:23:00 +01:00
parent e93102b276
commit 5cf1a9535e
27 changed files with 613 additions and 50 deletions

View File

@@ -285,9 +285,10 @@ describe("trigger handling", () => {
},
whatsapp: {
allowFrom: ["*"],
groups: { "*": { requireMention: false } },
},
routing: {
groupChat: { requireMention: false },
groupChat: {},
},
session: { store: join(home, "sessions.json") },
},

View File

@@ -512,8 +512,48 @@ export async function getReplyFromConfig(
sessionCtx.Body = queueCleaned;
sessionCtx.BodyStripped = queueCleaned;
const resolveGroupRequireMention = () => {
const surface =
groupResolution?.surface ?? ctx.Surface?.trim().toLowerCase();
const groupId = groupResolution?.id ?? ctx.From?.replace(/^group:/, "");
if (surface === "telegram") {
if (groupId) {
const groupConfig = cfg.telegram?.groups?.[groupId];
if (typeof groupConfig?.requireMention === "boolean") {
return groupConfig.requireMention;
}
}
const groupDefault = cfg.telegram?.groups?.["*"]?.requireMention;
if (typeof groupDefault === "boolean") return groupDefault;
return true;
}
if (surface === "whatsapp") {
if (groupId) {
const groupConfig = cfg.whatsapp?.groups?.[groupId];
if (typeof groupConfig?.requireMention === "boolean") {
return groupConfig.requireMention;
}
}
const groupDefault = cfg.whatsapp?.groups?.["*"]?.requireMention;
if (typeof groupDefault === "boolean") return groupDefault;
return true;
}
if (surface === "imessage") {
if (groupId) {
const groupConfig = cfg.imessage?.groups?.[groupId];
if (typeof groupConfig?.requireMention === "boolean") {
return groupConfig.requireMention;
}
}
const groupDefault = cfg.imessage?.groups?.["*"]?.requireMention;
if (typeof groupDefault === "boolean") return groupDefault;
return true;
}
return true;
};
const defaultGroupActivation = () => {
const requireMention = cfg.routing?.groupChat?.requireMention;
const requireMention = resolveGroupRequireMention();
return requireMention === false ? "always" : "mention";
};
@@ -954,6 +994,10 @@ export async function getReplyFromConfig(
const webLinked = await webAuthExists();
const webAuthAgeMs = getWebAuthAgeMs();
const heartbeatSeconds = resolveHeartbeatSeconds(cfg, undefined);
const groupActivation = isGroup
? normalizeGroupActivation(sessionEntry?.groupActivation) ??
defaultGroupActivation()
: undefined;
const statusText = buildStatusMessage({
agent: {
model,
@@ -966,6 +1010,7 @@ export async function getReplyFromConfig(
sessionKey,
sessionScope,
storePath,
groupActivation,
resolvedThink: resolvedThinkLevel,
resolvedVerbose: resolvedVerboseLevel,
webLinked,

View File

@@ -30,6 +30,7 @@ type StatusArgs = {
sessionKey?: string;
sessionScope?: SessionScope;
storePath?: string;
groupActivation?: "mention" | "always";
resolvedThink?: ThinkLevel;
resolvedVerbose?: VerboseLevel;
now?: number;
@@ -198,7 +199,7 @@ export function buildStatusMessage(args: StatusArgs): string {
Boolean(args.sessionKey?.includes(":channel:")) ||
Boolean(args.sessionKey?.startsWith("group:"));
const groupActivationLine = isGroupSession
? `Group activation: ${entry?.groupActivation ?? "mention"}`
? `Group activation: ${args.groupActivation ?? entry?.groupActivation ?? "mention"}`
: undefined;
const contextLine = `Context: ${formatTokens(