refactor: centralize ack reaction gating
This commit is contained in:
@@ -2,6 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|||||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||||
import { EventEmitter } from "node:events";
|
import { EventEmitter } from "node:events";
|
||||||
|
|
||||||
|
import { shouldAckReaction } from "clawdbot/plugin-sdk";
|
||||||
import type { ClawdbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
|
import type { ClawdbotConfig, PluginRuntime } from "clawdbot/plugin-sdk";
|
||||||
import {
|
import {
|
||||||
handleBlueBubblesWebhookRequest,
|
handleBlueBubblesWebhookRequest,
|
||||||
@@ -135,6 +136,9 @@ function createMockRuntime(): PluginRuntime {
|
|||||||
buildMentionRegexes: mockBuildMentionRegexes as unknown as PluginRuntime["channel"]["mentions"]["buildMentionRegexes"],
|
buildMentionRegexes: mockBuildMentionRegexes as unknown as PluginRuntime["channel"]["mentions"]["buildMentionRegexes"],
|
||||||
matchesMentionPatterns: mockMatchesMentionPatterns as unknown as PluginRuntime["channel"]["mentions"]["matchesMentionPatterns"],
|
matchesMentionPatterns: mockMatchesMentionPatterns as unknown as PluginRuntime["channel"]["mentions"]["matchesMentionPatterns"],
|
||||||
},
|
},
|
||||||
|
reactions: {
|
||||||
|
shouldAckReaction,
|
||||||
|
},
|
||||||
groups: {
|
groups: {
|
||||||
resolveGroupPolicy: mockResolveGroupPolicy as unknown as PluginRuntime["channel"]["groups"]["resolveGroupPolicy"],
|
resolveGroupPolicy: mockResolveGroupPolicy as unknown as PluginRuntime["channel"]["groups"]["resolveGroupPolicy"],
|
||||||
resolveRequireMention: mockResolveRequireMention as unknown as PluginRuntime["channel"]["groups"]["resolveRequireMention"],
|
resolveRequireMention: mockResolveRequireMention as unknown as PluginRuntime["channel"]["groups"]["resolveRequireMention"],
|
||||||
|
|||||||
@@ -1521,19 +1521,20 @@ async function processMessage(
|
|||||||
core,
|
core,
|
||||||
runtime,
|
runtime,
|
||||||
});
|
});
|
||||||
const shouldAckReaction = () => {
|
const shouldAckReaction = () =>
|
||||||
if (!ackReactionValue) return false;
|
Boolean(
|
||||||
if (ackReactionScope === "all") return true;
|
ackReactionValue &&
|
||||||
if (ackReactionScope === "direct") return !isGroup;
|
core.channel.reactions.shouldAckReaction({
|
||||||
if (ackReactionScope === "group-all") return isGroup;
|
scope: ackReactionScope,
|
||||||
if (ackReactionScope === "group-mentions") {
|
isDirect: !isGroup,
|
||||||
if (!isGroup) return false;
|
isGroup,
|
||||||
if (!requireMention) return false;
|
isMentionableGroup: isGroup,
|
||||||
if (!canDetectMention) return false;
|
requireMention: Boolean(requireMention),
|
||||||
return effectiveWasMentioned;
|
canDetectMention,
|
||||||
}
|
effectiveWasMentioned,
|
||||||
return false;
|
shouldBypassMention,
|
||||||
};
|
}),
|
||||||
|
);
|
||||||
const ackMessageId = message.messageId?.trim() || "";
|
const ackMessageId = message.messageId?.trim() || "";
|
||||||
const ackReactionPromise =
|
const ackReactionPromise =
|
||||||
shouldAckReaction() && ackMessageId && chatGuidForActions && ackReactionValue
|
shouldAckReaction() && ackMessageId && chatGuidForActions && ackReactionValue
|
||||||
|
|||||||
@@ -410,6 +410,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|||||||
!hasExplicitMention &&
|
!hasExplicitMention &&
|
||||||
commandAuthorized &&
|
commandAuthorized &&
|
||||||
core.channel.text.hasControlCommand(bodyText);
|
core.channel.text.hasControlCommand(bodyText);
|
||||||
|
const canDetectMention = mentionRegexes.length > 0 || hasExplicitMention;
|
||||||
if (isRoom && shouldRequireMention && !wasMentioned && !shouldBypassMention) {
|
if (isRoom && shouldRequireMention && !wasMentioned && !shouldBypassMention) {
|
||||||
logger.info({ roomId, reason: "no-mention" }, "skipping room message");
|
logger.info({ roomId, reason: "no-mention" }, "skipping room message");
|
||||||
return;
|
return;
|
||||||
@@ -515,18 +516,20 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
|
|||||||
|
|
||||||
const ackReaction = (cfg.messages?.ackReaction ?? "").trim();
|
const ackReaction = (cfg.messages?.ackReaction ?? "").trim();
|
||||||
const ackScope = cfg.messages?.ackReactionScope ?? "group-mentions";
|
const ackScope = cfg.messages?.ackReactionScope ?? "group-mentions";
|
||||||
const shouldAckReaction = () => {
|
const shouldAckReaction = () =>
|
||||||
if (!ackReaction) return false;
|
Boolean(
|
||||||
if (ackScope === "all") return true;
|
ackReaction &&
|
||||||
if (ackScope === "direct") return isDirectMessage;
|
core.channel.reactions.shouldAckReaction({
|
||||||
if (ackScope === "group-all") return isRoom;
|
scope: ackScope,
|
||||||
if (ackScope === "group-mentions") {
|
isDirect: isDirectMessage,
|
||||||
if (!isRoom) return false;
|
isGroup: isRoom,
|
||||||
if (!shouldRequireMention) return false;
|
isMentionableGroup: isRoom,
|
||||||
return wasMentioned || shouldBypassMention;
|
requireMention: Boolean(shouldRequireMention),
|
||||||
}
|
canDetectMention,
|
||||||
return false;
|
effectiveWasMentioned: wasMentioned || shouldBypassMention,
|
||||||
};
|
shouldBypassMention,
|
||||||
|
}),
|
||||||
|
);
|
||||||
if (shouldAckReaction() && messageId) {
|
if (shouldAckReaction() && messageId) {
|
||||||
reactMatrixMessage(roomId, messageId, ackReaction, client).catch((err) => {
|
reactMatrixMessage(roomId, messageId, ackReaction, client).catch((err) => {
|
||||||
logVerboseMessage(`matrix react failed for room ${roomId}: ${String(err)}`);
|
logVerboseMessage(`matrix react failed for room ${roomId}: ${String(err)}`);
|
||||||
|
|||||||
134
src/channels/ack-reactions.test.ts
Normal file
134
src/channels/ack-reactions.test.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { shouldAckReaction } from "./ack-reactions.js";
|
||||||
|
|
||||||
|
describe("shouldAckReaction", () => {
|
||||||
|
it("honors direct and group-all scopes", () => {
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "direct",
|
||||||
|
isDirect: true,
|
||||||
|
isGroup: false,
|
||||||
|
isMentionableGroup: false,
|
||||||
|
requireMention: false,
|
||||||
|
canDetectMention: false,
|
||||||
|
effectiveWasMentioned: false,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "group-all",
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: false,
|
||||||
|
canDetectMention: false,
|
||||||
|
effectiveWasMentioned: false,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("skips when scope is off or none", () => {
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "off",
|
||||||
|
isDirect: true,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "none",
|
||||||
|
isDirect: true,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defaults to group-mentions gating", () => {
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: undefined,
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("requires mention gating for group-mentions", () => {
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "group-mentions",
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: false,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "group-mentions",
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: false,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "group-mentions",
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: false,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "group-mentions",
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: true,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldAckReaction({
|
||||||
|
scope: "group-mentions",
|
||||||
|
isDirect: false,
|
||||||
|
isGroup: true,
|
||||||
|
isMentionableGroup: true,
|
||||||
|
requireMention: true,
|
||||||
|
canDetectMention: true,
|
||||||
|
effectiveWasMentioned: false,
|
||||||
|
shouldBypassMention: true,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
27
src/channels/ack-reactions.ts
Normal file
27
src/channels/ack-reactions.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
export type AckReactionScope = "all" | "direct" | "group-all" | "group-mentions" | "off" | "none";
|
||||||
|
|
||||||
|
export type AckReactionGateParams = {
|
||||||
|
scope: AckReactionScope | undefined;
|
||||||
|
isDirect: boolean;
|
||||||
|
isGroup: boolean;
|
||||||
|
isMentionableGroup: boolean;
|
||||||
|
requireMention: boolean;
|
||||||
|
canDetectMention: boolean;
|
||||||
|
effectiveWasMentioned: boolean;
|
||||||
|
shouldBypassMention?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function shouldAckReaction(params: AckReactionGateParams): boolean {
|
||||||
|
const scope = params.scope ?? "group-mentions";
|
||||||
|
if (scope === "off" || scope === "none") return false;
|
||||||
|
if (scope === "all") return true;
|
||||||
|
if (scope === "direct") return params.isDirect;
|
||||||
|
if (scope === "group-all") return params.isGroup;
|
||||||
|
if (scope === "group-mentions") {
|
||||||
|
if (!params.isMentionableGroup) return false;
|
||||||
|
if (!params.requireMention) return false;
|
||||||
|
if (!params.canDetectMention) return false;
|
||||||
|
return params.effectiveWasMentioned || params.shouldBypassMention === true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
extractShortModelName,
|
extractShortModelName,
|
||||||
type ResponsePrefixContext,
|
type ResponsePrefixContext,
|
||||||
} from "../../auto-reply/reply/response-prefix-template.js";
|
} from "../../auto-reply/reply/response-prefix-template.js";
|
||||||
|
import { shouldAckReaction as shouldAckReactionGate } from "../../channels/ack-reactions.js";
|
||||||
import {
|
import {
|
||||||
formatInboundEnvelope,
|
formatInboundEnvelope,
|
||||||
formatThreadStarterEnvelope,
|
formatThreadStarterEnvelope,
|
||||||
@@ -73,6 +74,7 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
|||||||
shouldRequireMention,
|
shouldRequireMention,
|
||||||
canDetectMention,
|
canDetectMention,
|
||||||
effectiveWasMentioned,
|
effectiveWasMentioned,
|
||||||
|
shouldBypassMention,
|
||||||
threadChannel,
|
threadChannel,
|
||||||
threadParentId,
|
threadParentId,
|
||||||
threadParentName,
|
threadParentName,
|
||||||
@@ -95,20 +97,20 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
|||||||
}
|
}
|
||||||
const ackReaction = resolveAckReaction(cfg, route.agentId);
|
const ackReaction = resolveAckReaction(cfg, route.agentId);
|
||||||
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
||||||
const shouldAckReaction = () => {
|
const shouldAckReaction = () =>
|
||||||
if (!ackReaction) return false;
|
Boolean(
|
||||||
if (ackReactionScope === "all") return true;
|
ackReaction &&
|
||||||
if (ackReactionScope === "direct") return isDirectMessage;
|
shouldAckReactionGate({
|
||||||
const isGroupChat = isGuildMessage || isGroupDm;
|
scope: ackReactionScope,
|
||||||
if (ackReactionScope === "group-all") return isGroupChat;
|
isDirect: isDirectMessage,
|
||||||
if (ackReactionScope === "group-mentions") {
|
isGroup: isGuildMessage || isGroupDm,
|
||||||
if (!isGuildMessage) return false;
|
isMentionableGroup: isGuildMessage,
|
||||||
if (!shouldRequireMention) return false;
|
requireMention: Boolean(shouldRequireMention),
|
||||||
if (!canDetectMention) return false;
|
canDetectMention,
|
||||||
return effectiveWasMentioned;
|
effectiveWasMentioned,
|
||||||
}
|
shouldBypassMention,
|
||||||
return false;
|
}),
|
||||||
};
|
);
|
||||||
const ackReactionPromise = shouldAckReaction()
|
const ackReactionPromise = shouldAckReaction()
|
||||||
? reactMessageDiscord(message.channelId, message.id, ackReaction, {
|
? reactMessageDiscord(message.channelId, message.id, ackReaction, {
|
||||||
rest: client.rest,
|
rest: client.rest,
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ 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 { shouldAckReaction } 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";
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { resolveEffectiveMessagesConfig, resolveHumanDelayConfig } from "../../a
|
|||||||
import { createMemoryGetTool, createMemorySearchTool } from "../../agents/tools/memory-tool.js";
|
import { createMemoryGetTool, createMemorySearchTool } from "../../agents/tools/memory-tool.js";
|
||||||
import { handleSlackAction } from "../../agents/tools/slack-actions.js";
|
import { handleSlackAction } from "../../agents/tools/slack-actions.js";
|
||||||
import { handleWhatsAppAction } from "../../agents/tools/whatsapp-actions.js";
|
import { handleWhatsAppAction } from "../../agents/tools/whatsapp-actions.js";
|
||||||
|
import { shouldAckReaction } from "../../channels/ack-reactions.js";
|
||||||
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
|
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
|
||||||
import { discordMessageActions } from "../../channels/plugins/actions/discord.js";
|
import { discordMessageActions } from "../../channels/plugins/actions/discord.js";
|
||||||
import { telegramMessageActions } from "../../channels/plugins/actions/telegram.js";
|
import { telegramMessageActions } from "../../channels/plugins/actions/telegram.js";
|
||||||
@@ -198,6 +199,9 @@ export function createPluginRuntime(): PluginRuntime {
|
|||||||
buildMentionRegexes,
|
buildMentionRegexes,
|
||||||
matchesMentionPatterns,
|
matchesMentionPatterns,
|
||||||
},
|
},
|
||||||
|
reactions: {
|
||||||
|
shouldAckReaction,
|
||||||
|
},
|
||||||
groups: {
|
groups: {
|
||||||
resolveGroupPolicy: resolveChannelGroupPolicy,
|
resolveGroupPolicy: resolveChannelGroupPolicy,
|
||||||
resolveRequireMention: resolveChannelGroupRequireMention,
|
resolveRequireMention: resolveChannelGroupRequireMention,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type SaveMediaBuffer = typeof import("../../media/store.js").saveMediaBuffer;
|
|||||||
type BuildMentionRegexes = typeof import("../../auto-reply/reply/mentions.js").buildMentionRegexes;
|
type BuildMentionRegexes = typeof import("../../auto-reply/reply/mentions.js").buildMentionRegexes;
|
||||||
type MatchesMentionPatterns =
|
type MatchesMentionPatterns =
|
||||||
typeof import("../../auto-reply/reply/mentions.js").matchesMentionPatterns;
|
typeof import("../../auto-reply/reply/mentions.js").matchesMentionPatterns;
|
||||||
|
type ShouldAckReaction = typeof import("../../channels/ack-reactions.js").shouldAckReaction;
|
||||||
type ResolveChannelGroupPolicy =
|
type ResolveChannelGroupPolicy =
|
||||||
typeof import("../../config/group-policy.js").resolveChannelGroupPolicy;
|
typeof import("../../config/group-policy.js").resolveChannelGroupPolicy;
|
||||||
type ResolveChannelGroupRequireMention =
|
type ResolveChannelGroupRequireMention =
|
||||||
@@ -211,6 +212,9 @@ export type PluginRuntime = {
|
|||||||
buildMentionRegexes: BuildMentionRegexes;
|
buildMentionRegexes: BuildMentionRegexes;
|
||||||
matchesMentionPatterns: MatchesMentionPatterns;
|
matchesMentionPatterns: MatchesMentionPatterns;
|
||||||
};
|
};
|
||||||
|
reactions: {
|
||||||
|
shouldAckReaction: ShouldAckReaction;
|
||||||
|
};
|
||||||
groups: {
|
groups: {
|
||||||
resolveGroupPolicy: ResolveChannelGroupPolicy;
|
resolveGroupPolicy: ResolveChannelGroupPolicy;
|
||||||
resolveRequireMention: ResolveChannelGroupRequireMention;
|
resolveRequireMention: ResolveChannelGroupRequireMention;
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ import { buildPairingReply } from "../../../pairing/pairing-messages.js";
|
|||||||
import { upsertChannelPairingRequest } from "../../../pairing/pairing-store.js";
|
import { upsertChannelPairingRequest } from "../../../pairing/pairing-store.js";
|
||||||
import { resolveAgentRoute } from "../../../routing/resolve-route.js";
|
import { resolveAgentRoute } from "../../../routing/resolve-route.js";
|
||||||
import { resolveThreadSessionKeys } from "../../../routing/session-key.js";
|
import { resolveThreadSessionKeys } from "../../../routing/session-key.js";
|
||||||
|
import {
|
||||||
|
shouldAckReaction as shouldAckReactionGate,
|
||||||
|
type AckReactionScope,
|
||||||
|
} from "../../../channels/ack-reactions.js";
|
||||||
import { resolveMentionGatingWithBypass } from "../../../channels/mention-gating.js";
|
import { resolveMentionGatingWithBypass } from "../../../channels/mention-gating.js";
|
||||||
import { resolveConversationLabel } from "../../../channels/conversation-label.js";
|
import { resolveConversationLabel } from "../../../channels/conversation-label.js";
|
||||||
import { resolveControlCommandGate } from "../../../channels/command-gating.js";
|
import { resolveControlCommandGate } from "../../../channels/command-gating.js";
|
||||||
@@ -324,19 +328,20 @@ export async function prepareSlackMessage(params: {
|
|||||||
const ackReaction = resolveAckReaction(cfg, route.agentId);
|
const ackReaction = resolveAckReaction(cfg, route.agentId);
|
||||||
const ackReactionValue = ackReaction ?? "";
|
const ackReactionValue = ackReaction ?? "";
|
||||||
|
|
||||||
const shouldAckReaction = () => {
|
const shouldAckReaction = () =>
|
||||||
if (!ackReaction) return false;
|
Boolean(
|
||||||
if (ctx.ackReactionScope === "all") return true;
|
ackReaction &&
|
||||||
if (ctx.ackReactionScope === "direct") return isDirectMessage;
|
shouldAckReactionGate({
|
||||||
if (ctx.ackReactionScope === "group-all") return isRoomish;
|
scope: ctx.ackReactionScope as AckReactionScope | undefined,
|
||||||
if (ctx.ackReactionScope === "group-mentions") {
|
isDirect: isDirectMessage,
|
||||||
if (!isRoom) return false;
|
isGroup: isRoomish,
|
||||||
if (!shouldRequireMention) return false;
|
isMentionableGroup: isRoom,
|
||||||
if (!canDetectMention) return false;
|
requireMention: Boolean(shouldRequireMention),
|
||||||
return effectiveWasMentioned;
|
canDetectMention,
|
||||||
}
|
effectiveWasMentioned,
|
||||||
return false;
|
shouldBypassMention: mentionGate.shouldBypassMention,
|
||||||
};
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const ackReactionMessageTs = message.ts;
|
const ackReactionMessageTs = message.ts;
|
||||||
const ackReactionPromise =
|
const ackReactionPromise =
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import type { DmPolicy, TelegramGroupConfig, TelegramTopicConfig } from "../conf
|
|||||||
import { logVerbose, shouldLogVerbose } from "../globals.js";
|
import { logVerbose, shouldLogVerbose } from "../globals.js";
|
||||||
import { recordChannelActivity } from "../infra/channel-activity.js";
|
import { recordChannelActivity } from "../infra/channel-activity.js";
|
||||||
import { resolveAgentRoute } from "../routing/resolve-route.js";
|
import { resolveAgentRoute } from "../routing/resolve-route.js";
|
||||||
|
import { shouldAckReaction as shouldAckReactionGate } from "../channels/ack-reactions.js";
|
||||||
import { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
|
import { resolveMentionGatingWithBypass } from "../channels/mention-gating.js";
|
||||||
import { resolveControlCommandGate } from "../channels/command-gating.js";
|
import { resolveControlCommandGate } from "../channels/command-gating.js";
|
||||||
import {
|
import {
|
||||||
@@ -369,19 +370,20 @@ export const buildTelegramMessageContext = async ({
|
|||||||
// ACK reactions
|
// ACK reactions
|
||||||
const ackReaction = resolveAckReaction(cfg, route.agentId);
|
const ackReaction = resolveAckReaction(cfg, route.agentId);
|
||||||
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
const removeAckAfterReply = cfg.messages?.removeAckAfterReply ?? false;
|
||||||
const shouldAckReaction = () => {
|
const shouldAckReaction = () =>
|
||||||
if (!ackReaction) return false;
|
Boolean(
|
||||||
if (ackReactionScope === "all") return true;
|
ackReaction &&
|
||||||
if (ackReactionScope === "direct") return !isGroup;
|
shouldAckReactionGate({
|
||||||
if (ackReactionScope === "group-all") return isGroup;
|
scope: ackReactionScope,
|
||||||
if (ackReactionScope === "group-mentions") {
|
isDirect: !isGroup,
|
||||||
if (!isGroup) return false;
|
isGroup,
|
||||||
if (!requireMention) return false;
|
isMentionableGroup: isGroup,
|
||||||
if (!canDetectMention) return false;
|
requireMention: Boolean(requireMention),
|
||||||
return effectiveWasMentioned;
|
canDetectMention,
|
||||||
}
|
effectiveWasMentioned,
|
||||||
return false;
|
shouldBypassMention: mentionGate.shouldBypassMention,
|
||||||
};
|
}),
|
||||||
|
);
|
||||||
const api = bot.api as unknown as {
|
const api = bot.api as unknown as {
|
||||||
setMessageReaction?: (
|
setMessageReaction?: (
|
||||||
chatId: number | string,
|
chatId: number | string,
|
||||||
|
|||||||
Reference in New Issue
Block a user