diff --git a/CHANGELOG.md b/CHANGELOG.md index 9716dd89d..fdcb26f8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Usage: add MiniMax coding plan usage tracking. - Auth: label Claude Code CLI auth options. (#915) — thanks @SeanZoR. - Docs: standardize Claude Code CLI naming across docs and prompts. (follow-up to #915) +- Telegram: add message delete action in the message tool. (#903) — thanks @sleontenko. ### Fixes - Mac: pass auth token/password to dashboard URL for authenticated access. (#918) — thanks @rahthakor. diff --git a/docs/channels/telegram.md b/docs/channels/telegram.md index bf746f2f6..c2804fbcb 100644 --- a/docs/channels/telegram.md +++ b/docs/channels/telegram.md @@ -262,8 +262,9 @@ Outbound Telegram API calls retry on transient network/429 errors with exponenti ## Agent tool (messages + reactions) - Tool: `telegram` with `sendMessage` action (`to`, `content`, optional `mediaUrl`, `replyToMessageId`, `messageThreadId`). - Tool: `telegram` with `react` action (`chatId`, `messageId`, `emoji`). +- Tool: `telegram` with `deleteMessage` action (`chatId`, `messageId`). - Reaction removal semantics: see [/tools/reactions](/tools/reactions). -- Tool gating: `channels.telegram.actions.reactions` and `channels.telegram.actions.sendMessage` (default: enabled). +- Tool gating: `channels.telegram.actions.reactions`, `channels.telegram.actions.sendMessage`, `channels.telegram.actions.deleteMessage` (default: enabled). ## Delivery targets (CLI/cron) - Use a chat id (`123456789`) or a username (`@name`) as the target. @@ -322,6 +323,7 @@ Provider options: - `channels.telegram.webhookPath`: local webhook path (default `/telegram-webhook`). - `channels.telegram.actions.reactions`: gate Telegram tool reactions. - `channels.telegram.actions.sendMessage`: gate Telegram tool message sends. +- `channels.telegram.actions.deleteMessage`: gate Telegram tool message deletes. Related global options: - `agents.list[].groupChat.mentionPatterns` (mention gating patterns). diff --git a/docs/cli/message.md b/docs/cli/message.md index 52da57732..ceea3b94d 100644 --- a/docs/cli/message.md +++ b/docs/cli/message.md @@ -81,7 +81,7 @@ Target formats (`--to`): - Optional: `--channel-id` - `delete` - - Channels: Discord/Slack + - Channels: Discord/Slack/Telegram - Required: `--message-id`, `--to` or `--channel-id` - Optional: `--channel-id` diff --git a/src/agents/tools/telegram-actions.test.ts b/src/agents/tools/telegram-actions.test.ts index 08ad175ac..134759464 100644 --- a/src/agents/tools/telegram-actions.test.ts +++ b/src/agents/tools/telegram-actions.test.ts @@ -8,17 +8,20 @@ const sendMessageTelegram = vi.fn(async () => ({ messageId: "789", chatId: "123", })); +const deleteMessageTelegram = vi.fn(async () => ({ ok: true })); const originalToken = process.env.TELEGRAM_BOT_TOKEN; vi.mock("../../telegram/send.js", () => ({ reactMessageTelegram: (...args: unknown[]) => reactMessageTelegram(...args), sendMessageTelegram: (...args: unknown[]) => sendMessageTelegram(...args), + deleteMessageTelegram: (...args: unknown[]) => deleteMessageTelegram(...args), })); describe("handleTelegramAction", () => { beforeEach(() => { reactMessageTelegram.mockClear(); sendMessageTelegram.mockClear(); + deleteMessageTelegram.mockClear(); process.env.TELEGRAM_BOT_TOKEN = "tok"; }); @@ -177,6 +180,43 @@ describe("handleTelegramAction", () => { ).rejects.toThrow(/Telegram sendMessage is disabled/); }); + it("deletes a message", async () => { + const cfg = { + channels: { telegram: { botToken: "tok" } }, + } as ClawdbotConfig; + await handleTelegramAction( + { + action: "deleteMessage", + chatId: "123", + messageId: 456, + }, + cfg, + ); + expect(deleteMessageTelegram).toHaveBeenCalledWith( + "123", + 456, + expect.objectContaining({ token: "tok" }), + ); + }); + + it("respects deleteMessage gating", async () => { + const cfg = { + channels: { + telegram: { botToken: "tok", actions: { deleteMessage: false } }, + }, + } as ClawdbotConfig; + await expect( + handleTelegramAction( + { + action: "deleteMessage", + chatId: "123", + messageId: 456, + }, + cfg, + ), + ).rejects.toThrow(/Telegram deleteMessage is disabled/); + }); + it("throws on missing bot token for sendMessage", async () => { delete process.env.TELEGRAM_BOT_TOKEN; const cfg = {} as ClawdbotConfig; diff --git a/src/channels/plugins/actions/telegram.ts b/src/channels/plugins/actions/telegram.ts index 0b5917d07..0f490ec89 100644 --- a/src/channels/plugins/actions/telegram.ts +++ b/src/channels/plugins/actions/telegram.ts @@ -1,4 +1,8 @@ -import { createActionGate, readStringParam } from "../../../agents/tools/common.js"; +import { + createActionGate, + readStringOrNumberParam, + readStringParam, +} from "../../../agents/tools/common.js"; import { handleTelegramAction } from "../../../agents/tools/telegram-actions.js"; import type { ClawdbotConfig } from "../../../config/config.js"; import { listEnabledTelegramAccounts } from "../../../telegram/accounts.js"; @@ -94,7 +98,10 @@ export const telegramMessageActions: ChannelMessageActionAdapter = { } if (action === "delete") { - const chatId = readStringParam(params, "chatId", { required: true }); + const chatId = + readStringOrNumberParam(params, "chatId") ?? + readStringOrNumberParam(params, "channelId") ?? + readStringParam(params, "to", { required: true }); const messageId = readStringParam(params, "messageId", { required: true, }); diff --git a/src/telegram/send.ts b/src/telegram/send.ts index 96588647c..8e3bc5e01 100644 --- a/src/telegram/send.ts +++ b/src/telegram/send.ts @@ -101,12 +101,12 @@ function normalizeMessageId(raw: string | number): number { if (typeof raw === "string") { const value = raw.trim(); if (!value) { - throw new Error("Message id is required for Telegram reactions"); + throw new Error("Message id is required for Telegram actions"); } const parsed = Number.parseInt(value, 10); if (Number.isFinite(parsed)) return parsed; } - throw new Error("Message id is required for Telegram reactions"); + throw new Error("Message id is required for Telegram actions"); } export function buildInlineKeyboard(