fix(telegram): wire delete action for message tool (#903) - thanks @sleontenko
Co-authored-by: Stan <sleontenko@users.noreply.github.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
- Usage: add MiniMax coding plan usage tracking.
|
- Usage: add MiniMax coding plan usage tracking.
|
||||||
- Auth: label Claude Code CLI auth options. (#915) — thanks @SeanZoR.
|
- Auth: label Claude Code CLI auth options. (#915) — thanks @SeanZoR.
|
||||||
- Docs: standardize Claude Code CLI naming across docs and prompts. (follow-up to #915)
|
- 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
|
### Fixes
|
||||||
- Mac: pass auth token/password to dashboard URL for authenticated access. (#918) — thanks @rahthakor.
|
- Mac: pass auth token/password to dashboard URL for authenticated access. (#918) — thanks @rahthakor.
|
||||||
|
|||||||
@@ -262,8 +262,9 @@ Outbound Telegram API calls retry on transient network/429 errors with exponenti
|
|||||||
## Agent tool (messages + reactions)
|
## Agent tool (messages + reactions)
|
||||||
- Tool: `telegram` with `sendMessage` action (`to`, `content`, optional `mediaUrl`, `replyToMessageId`, `messageThreadId`).
|
- Tool: `telegram` with `sendMessage` action (`to`, `content`, optional `mediaUrl`, `replyToMessageId`, `messageThreadId`).
|
||||||
- Tool: `telegram` with `react` action (`chatId`, `messageId`, `emoji`).
|
- Tool: `telegram` with `react` action (`chatId`, `messageId`, `emoji`).
|
||||||
|
- Tool: `telegram` with `deleteMessage` action (`chatId`, `messageId`).
|
||||||
- Reaction removal semantics: see [/tools/reactions](/tools/reactions).
|
- 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)
|
## Delivery targets (CLI/cron)
|
||||||
- Use a chat id (`123456789`) or a username (`@name`) as the target.
|
- 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.webhookPath`: local webhook path (default `/telegram-webhook`).
|
||||||
- `channels.telegram.actions.reactions`: gate Telegram tool reactions.
|
- `channels.telegram.actions.reactions`: gate Telegram tool reactions.
|
||||||
- `channels.telegram.actions.sendMessage`: gate Telegram tool message sends.
|
- `channels.telegram.actions.sendMessage`: gate Telegram tool message sends.
|
||||||
|
- `channels.telegram.actions.deleteMessage`: gate Telegram tool message deletes.
|
||||||
|
|
||||||
Related global options:
|
Related global options:
|
||||||
- `agents.list[].groupChat.mentionPatterns` (mention gating patterns).
|
- `agents.list[].groupChat.mentionPatterns` (mention gating patterns).
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ Target formats (`--to`):
|
|||||||
- Optional: `--channel-id`
|
- Optional: `--channel-id`
|
||||||
|
|
||||||
- `delete`
|
- `delete`
|
||||||
- Channels: Discord/Slack
|
- Channels: Discord/Slack/Telegram
|
||||||
- Required: `--message-id`, `--to` or `--channel-id`
|
- Required: `--message-id`, `--to` or `--channel-id`
|
||||||
- Optional: `--channel-id`
|
- Optional: `--channel-id`
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,20 @@ const sendMessageTelegram = vi.fn(async () => ({
|
|||||||
messageId: "789",
|
messageId: "789",
|
||||||
chatId: "123",
|
chatId: "123",
|
||||||
}));
|
}));
|
||||||
|
const deleteMessageTelegram = vi.fn(async () => ({ ok: true }));
|
||||||
const originalToken = process.env.TELEGRAM_BOT_TOKEN;
|
const originalToken = process.env.TELEGRAM_BOT_TOKEN;
|
||||||
|
|
||||||
vi.mock("../../telegram/send.js", () => ({
|
vi.mock("../../telegram/send.js", () => ({
|
||||||
reactMessageTelegram: (...args: unknown[]) => reactMessageTelegram(...args),
|
reactMessageTelegram: (...args: unknown[]) => reactMessageTelegram(...args),
|
||||||
sendMessageTelegram: (...args: unknown[]) => sendMessageTelegram(...args),
|
sendMessageTelegram: (...args: unknown[]) => sendMessageTelegram(...args),
|
||||||
|
deleteMessageTelegram: (...args: unknown[]) => deleteMessageTelegram(...args),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe("handleTelegramAction", () => {
|
describe("handleTelegramAction", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
reactMessageTelegram.mockClear();
|
reactMessageTelegram.mockClear();
|
||||||
sendMessageTelegram.mockClear();
|
sendMessageTelegram.mockClear();
|
||||||
|
deleteMessageTelegram.mockClear();
|
||||||
process.env.TELEGRAM_BOT_TOKEN = "tok";
|
process.env.TELEGRAM_BOT_TOKEN = "tok";
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -177,6 +180,43 @@ describe("handleTelegramAction", () => {
|
|||||||
).rejects.toThrow(/Telegram sendMessage is disabled/);
|
).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 () => {
|
it("throws on missing bot token for sendMessage", async () => {
|
||||||
delete process.env.TELEGRAM_BOT_TOKEN;
|
delete process.env.TELEGRAM_BOT_TOKEN;
|
||||||
const cfg = {} as ClawdbotConfig;
|
const cfg = {} as ClawdbotConfig;
|
||||||
|
|||||||
@@ -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 { handleTelegramAction } from "../../../agents/tools/telegram-actions.js";
|
||||||
import type { ClawdbotConfig } from "../../../config/config.js";
|
import type { ClawdbotConfig } from "../../../config/config.js";
|
||||||
import { listEnabledTelegramAccounts } from "../../../telegram/accounts.js";
|
import { listEnabledTelegramAccounts } from "../../../telegram/accounts.js";
|
||||||
@@ -94,7 +98,10 @@ export const telegramMessageActions: ChannelMessageActionAdapter = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action === "delete") {
|
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", {
|
const messageId = readStringParam(params, "messageId", {
|
||||||
required: true,
|
required: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -101,12 +101,12 @@ function normalizeMessageId(raw: string | number): number {
|
|||||||
if (typeof raw === "string") {
|
if (typeof raw === "string") {
|
||||||
const value = raw.trim();
|
const value = raw.trim();
|
||||||
if (!value) {
|
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);
|
const parsed = Number.parseInt(value, 10);
|
||||||
if (Number.isFinite(parsed)) return parsed;
|
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(
|
export function buildInlineKeyboard(
|
||||||
|
|||||||
Reference in New Issue
Block a user