feat: add ack reaction defaults
This commit is contained in:
@@ -25,12 +25,14 @@ const useSpy = vi.fn();
|
||||
const onSpy = vi.fn();
|
||||
const stopSpy = vi.fn();
|
||||
const sendChatActionSpy = vi.fn();
|
||||
const setMessageReactionSpy = vi.fn(async () => undefined);
|
||||
const sendMessageSpy = vi.fn(async () => ({ message_id: 77 }));
|
||||
const sendAnimationSpy = vi.fn(async () => ({ message_id: 78 }));
|
||||
const sendPhotoSpy = vi.fn(async () => ({ message_id: 79 }));
|
||||
type ApiStub = {
|
||||
config: { use: (arg: unknown) => void };
|
||||
sendChatAction: typeof sendChatActionSpy;
|
||||
setMessageReaction: typeof setMessageReactionSpy;
|
||||
sendMessage: typeof sendMessageSpy;
|
||||
sendAnimation: typeof sendAnimationSpy;
|
||||
sendPhoto: typeof sendPhotoSpy;
|
||||
@@ -38,6 +40,7 @@ type ApiStub = {
|
||||
const apiStub: ApiStub = {
|
||||
config: { use: useSpy },
|
||||
sendChatAction: sendChatActionSpy,
|
||||
setMessageReaction: setMessageReactionSpy,
|
||||
sendMessage: sendMessageSpy,
|
||||
sendAnimation: sendAnimationSpy,
|
||||
sendPhoto: sendPhotoSpy,
|
||||
@@ -74,6 +77,7 @@ describe("createTelegramBot", () => {
|
||||
loadWebMedia.mockReset();
|
||||
sendAnimationSpy.mockReset();
|
||||
sendPhotoSpy.mockReset();
|
||||
setMessageReactionSpy.mockReset();
|
||||
});
|
||||
|
||||
it("installs grammY throttler", () => {
|
||||
@@ -178,6 +182,42 @@ describe("createTelegramBot", () => {
|
||||
expect(payload.WasMentioned).toBe(true);
|
||||
});
|
||||
|
||||
it("reacts to mention-gated group messages when ackReaction is enabled", async () => {
|
||||
onSpy.mockReset();
|
||||
setMessageReactionSpy.mockReset();
|
||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<
|
||||
typeof vi.fn
|
||||
>;
|
||||
replySpy.mockReset();
|
||||
|
||||
loadConfig.mockReturnValue({
|
||||
messages: { ackReaction: "👀", ackReactionScope: "group-mentions" },
|
||||
routing: { groupChat: { mentionPatterns: ["\\bbert\\b"] } },
|
||||
telegram: { groups: { "*": { requireMention: true } } },
|
||||
});
|
||||
|
||||
createTelegramBot({ token: "tok" });
|
||||
const handler = onSpy.mock.calls[0][1] as (
|
||||
ctx: Record<string, unknown>,
|
||||
) => Promise<void>;
|
||||
|
||||
await handler({
|
||||
message: {
|
||||
chat: { id: 7, type: "group", title: "Test Group" },
|
||||
text: "bert hello",
|
||||
date: 1736380800,
|
||||
message_id: 123,
|
||||
from: { id: 9, first_name: "Ada" },
|
||||
},
|
||||
me: { username: "clawdbot_bot" },
|
||||
getFile: async () => ({ download: async () => new Uint8Array() }),
|
||||
});
|
||||
|
||||
expect(setMessageReactionSpy).toHaveBeenCalledWith(7, 123, [
|
||||
{ type: "emoji", emoji: "👀" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("skips group messages when requireMention is enabled and no mention matches", async () => {
|
||||
onSpy.mockReset();
|
||||
const replySpy = replyModule.__replySpy as unknown as ReturnType<
|
||||
|
||||
@@ -73,6 +73,8 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
const textLimit = resolveTextChunkLimit(cfg, "telegram");
|
||||
const allowFrom = opts.allowFrom ?? cfg.telegram?.allowFrom;
|
||||
const replyToMode = opts.replyToMode ?? cfg.telegram?.replyToMode ?? "off";
|
||||
const ackReaction = (cfg.messages?.ackReaction ?? "").trim();
|
||||
const ackReactionScope = cfg.messages?.ackReactionScope ?? "group-mentions";
|
||||
const mediaMaxBytes =
|
||||
(opts.mediaMaxMb ?? cfg.telegram?.mediaMaxMb ?? 5) * 1024 * 1024;
|
||||
const logger = getChildLogger({ module: "telegram-auto-reply" });
|
||||
@@ -181,11 +183,6 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// React to acknowledge message receipt
|
||||
ctx.react("✍️").catch((err) => {
|
||||
logVerbose(`telegram react failed for chat ${chatId}: ${String(err)}`);
|
||||
});
|
||||
|
||||
const media = await resolveMedia(
|
||||
ctx,
|
||||
mediaMaxBytes,
|
||||
@@ -200,6 +197,39 @@ export function createTelegramBot(opts: TelegramBotOptions) {
|
||||
""
|
||||
).trim();
|
||||
if (!rawBody) return;
|
||||
const shouldAckReaction = () => {
|
||||
if (!ackReaction) return false;
|
||||
if (ackReactionScope === "all") return true;
|
||||
if (ackReactionScope === "direct") return !isGroup;
|
||||
if (ackReactionScope === "group-all") return isGroup;
|
||||
if (ackReactionScope === "group-mentions") {
|
||||
if (!isGroup) return false;
|
||||
if (!resolveGroupRequireMention(chatId)) return false;
|
||||
if (!canDetectMention) return false;
|
||||
return wasMentioned || shouldBypassMention;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (shouldAckReaction() && msg.message_id) {
|
||||
const api = bot.api as unknown as {
|
||||
setMessageReaction?: (
|
||||
chatId: number | string,
|
||||
messageId: number,
|
||||
reactions: Array<{ type: "emoji"; emoji: string }>,
|
||||
) => Promise<void>;
|
||||
};
|
||||
if (typeof api.setMessageReaction === "function") {
|
||||
api
|
||||
.setMessageReaction(chatId, msg.message_id, [
|
||||
{ type: "emoji", emoji: ackReaction },
|
||||
])
|
||||
.catch((err) => {
|
||||
logVerbose(
|
||||
`telegram react failed for chat ${chatId}: ${String(err)}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
const replySuffix = replyTarget
|
||||
? `\n\n[Replying to ${replyTarget.sender}${replyTarget.id ? ` id:${replyTarget.id}` : ""}]\n${replyTarget.body}\n[/Replying]`
|
||||
: "";
|
||||
|
||||
Reference in New Issue
Block a user