refactor: reuse ack reaction helper for whatsapp

This commit is contained in:
Peter Steinberger
2026-01-23 22:20:28 +00:00
parent 02bd6e4a24
commit 892197c43e
4 changed files with 141 additions and 23 deletions

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { shouldAckReaction } from "./ack-reactions.js"; import { shouldAckReaction, shouldAckReactionForWhatsApp } from "./ack-reactions.js";
describe("shouldAckReaction", () => { describe("shouldAckReaction", () => {
it("honors direct and group-all scopes", () => { it("honors direct and group-all scopes", () => {
@@ -132,3 +132,93 @@ describe("shouldAckReaction", () => {
).toBe(true); ).toBe(true);
}); });
}); });
describe("shouldAckReactionForWhatsApp", () => {
it("respects direct and group modes", () => {
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: true,
isGroup: false,
directEnabled: true,
groupMode: "mentions",
wasMentioned: false,
groupActivated: false,
}),
).toBe(true);
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: true,
isGroup: false,
directEnabled: false,
groupMode: "mentions",
wasMentioned: false,
groupActivated: false,
}),
).toBe(false);
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: false,
isGroup: true,
directEnabled: true,
groupMode: "always",
wasMentioned: false,
groupActivated: false,
}),
).toBe(true);
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: false,
isGroup: true,
directEnabled: true,
groupMode: "never",
wasMentioned: true,
groupActivated: true,
}),
).toBe(false);
});
it("honors mentions or activation for group-mentions", () => {
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: false,
isGroup: true,
directEnabled: true,
groupMode: "mentions",
wasMentioned: true,
groupActivated: false,
}),
).toBe(true);
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: false,
isGroup: true,
directEnabled: true,
groupMode: "mentions",
wasMentioned: false,
groupActivated: true,
}),
).toBe(true);
expect(
shouldAckReactionForWhatsApp({
emoji: "👀",
isDirect: false,
isGroup: true,
directEnabled: true,
groupMode: "mentions",
wasMentioned: false,
groupActivated: false,
}),
).toBe(false);
});
});

View File

@@ -1,5 +1,7 @@
export type AckReactionScope = "all" | "direct" | "group-all" | "group-mentions" | "off" | "none"; export type AckReactionScope = "all" | "direct" | "group-all" | "group-mentions" | "off" | "none";
export type WhatsAppAckReactionMode = "always" | "mentions" | "never";
export type AckReactionGateParams = { export type AckReactionGateParams = {
scope: AckReactionScope | undefined; scope: AckReactionScope | undefined;
isDirect: boolean; isDirect: boolean;
@@ -25,3 +27,29 @@ export function shouldAckReaction(params: AckReactionGateParams): boolean {
} }
return false; return false;
} }
export function shouldAckReactionForWhatsApp(params: {
emoji: string;
isDirect: boolean;
isGroup: boolean;
directEnabled: boolean;
groupMode: WhatsAppAckReactionMode;
wasMentioned: boolean;
groupActivated: boolean;
}): boolean {
if (!params.emoji) return false;
if (params.isDirect) return params.directEnabled;
if (!params.isGroup) return false;
if (params.groupMode === "never") return false;
if (params.groupMode === "always") return true;
return shouldAckReaction({
scope: "group-mentions",
isDirect: false,
isGroup: true,
isMentionableGroup: true,
requireMention: true,
canDetectMention: true,
effectiveWasMentioned: params.wasMentioned,
shouldBypassMention: params.groupActivated,
});
}

View File

@@ -117,8 +117,12 @@ export {
resolveMentionGating, resolveMentionGating,
resolveMentionGatingWithBypass, resolveMentionGatingWithBypass,
} from "../channels/mention-gating.js"; } from "../channels/mention-gating.js";
export type { AckReactionGateParams, AckReactionScope } from "../channels/ack-reactions.js"; export type {
export { shouldAckReaction } from "../channels/ack-reactions.js"; AckReactionGateParams,
AckReactionScope,
WhatsAppAckReactionMode,
} from "../channels/ack-reactions.js";
export { shouldAckReaction, shouldAckReactionForWhatsApp } from "../channels/ack-reactions.js";
export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js"; export { resolveChannelMediaMaxBytes } from "../channels/plugins/media-limits.js";
export type { NormalizedLocation } from "../channels/location.js"; export type { NormalizedLocation } from "../channels/location.js";
export { formatLocationText, toLocationContext } from "../channels/location.js"; export { formatLocationText, toLocationContext } from "../channels/location.js";

View File

@@ -1,5 +1,6 @@
import type { loadConfig } from "../../../config/config.js"; import type { loadConfig } from "../../../config/config.js";
import { logVerbose } from "../../../globals.js"; import { logVerbose } from "../../../globals.js";
import { shouldAckReactionForWhatsApp } from "../../../channels/ack-reactions.js";
import { sendReactionWhatsApp } from "../../outbound.js"; import { sendReactionWhatsApp } from "../../outbound.js";
import { formatError } from "../../session.js"; import { formatError } from "../../session.js";
import type { WebInboundMsg } from "../types.js"; import type { WebInboundMsg } from "../types.js";
@@ -24,30 +25,25 @@ export function maybeSendAckReaction(params: {
const groupMode = ackConfig?.group ?? "mentions"; const groupMode = ackConfig?.group ?? "mentions";
const conversationIdForCheck = params.msg.conversationId ?? params.msg.from; const conversationIdForCheck = params.msg.conversationId ?? params.msg.from;
const shouldSendReaction = () => { const activation =
if (!emoji) return false; params.msg.chatType === "group"
? resolveGroupActivationFor({
if (params.msg.chatType === "direct") {
return directEnabled;
}
if (params.msg.chatType === "group") {
if (groupMode === "never") return false;
if (groupMode === "always") return true;
if (groupMode === "mentions") {
const activation = resolveGroupActivationFor({
cfg: params.cfg, cfg: params.cfg,
agentId: params.agentId, agentId: params.agentId,
sessionKey: params.sessionKey, sessionKey: params.sessionKey,
conversationId: conversationIdForCheck, conversationId: conversationIdForCheck,
}); })
if (activation === "always") return true; : null;
return params.msg.wasMentioned === true; const shouldSendReaction = () =>
} shouldAckReactionForWhatsApp({
} emoji,
isDirect: params.msg.chatType === "direct",
return false; isGroup: params.msg.chatType === "group",
}; directEnabled,
groupMode,
wasMentioned: params.msg.wasMentioned === true,
groupActivated: activation === "always",
});
if (!shouldSendReaction()) return; if (!shouldSendReaction()) return;