feat(telegram): add deleteMessage action
Add ability to delete messages in Telegram chats via the message tool. Changes: - Add deleteMessageTelegram function in send.ts - Add deleteMessage action handler in telegram-actions.ts - Add delete action support in telegram message plugin adapter - Add deleteMessage to TelegramActionConfig type - Update message tool description to mention delete action Usage: - Via message tool: action="delete", chatId, messageId - Can be disabled via channels.telegram.actions.deleteMessage=false Limitations (Telegram API): - Bot can delete its own messages in any chat - Bot can delete others' messages only if admin with "Delete Messages" - Messages older than 48h in groups may fail to delete
This commit is contained in:
committed by
Peter Steinberger
parent
9b7df414e6
commit
83a25d26fc
@@ -148,7 +148,7 @@ export function createMessageTool(options?: MessageToolOptions): AnyAgentTool {
|
||||
label: "Message",
|
||||
name: "message",
|
||||
description:
|
||||
"Send messages and channel actions (polls, reactions, pins, threads, etc.) via configured channel plugins.",
|
||||
"Send, delete, and manage messages via channel plugins. Supports actions: send, delete, react, poll, pin, threads, and more.",
|
||||
parameters: schema,
|
||||
execute: async (_toolCallId, args) => {
|
||||
const params = args as Record<string, unknown>;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import type { AgentToolResult } from "@mariozechner/pi-agent-core";
|
||||
import { resolveChannelCapabilities } from "../../config/channel-capabilities.js";
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
import { reactMessageTelegram, sendMessageTelegram } from "../../telegram/send.js";
|
||||
import {
|
||||
deleteMessageTelegram,
|
||||
reactMessageTelegram,
|
||||
sendMessageTelegram,
|
||||
} from "../../telegram/send.js";
|
||||
import { resolveTelegramToken } from "../../telegram/token.js";
|
||||
import {
|
||||
createActionGate,
|
||||
@@ -149,5 +153,29 @@ export async function handleTelegramAction(
|
||||
});
|
||||
}
|
||||
|
||||
if (action === "deleteMessage") {
|
||||
if (!isActionEnabled("deleteMessage")) {
|
||||
throw new Error("Telegram deleteMessage is disabled.");
|
||||
}
|
||||
const chatId = readStringOrNumberParam(params, "chatId", {
|
||||
required: true,
|
||||
});
|
||||
const messageId = readNumberParam(params, "messageId", {
|
||||
required: true,
|
||||
integer: true,
|
||||
});
|
||||
const token = resolveTelegramToken(cfg, { accountId }).token;
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
"Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.",
|
||||
);
|
||||
}
|
||||
await deleteMessageTelegram(chatId ?? "", messageId ?? 0, {
|
||||
token,
|
||||
accountId: accountId ?? undefined,
|
||||
});
|
||||
return jsonResult({ ok: true, deleted: true });
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported Telegram action: ${action}`);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ export const telegramMessageActions: ChannelMessageActionAdapter = {
|
||||
const gate = createActionGate(cfg.channels?.telegram?.actions);
|
||||
const actions = new Set<ChannelMessageActionName>(["send"]);
|
||||
if (gate("reactions")) actions.add("react");
|
||||
if (gate("deleteMessage")) actions.add("delete");
|
||||
return Array.from(actions);
|
||||
},
|
||||
supportsButtons: ({ cfg }) => hasTelegramInlineButtons(cfg),
|
||||
@@ -92,6 +93,22 @@ export const telegramMessageActions: ChannelMessageActionAdapter = {
|
||||
);
|
||||
}
|
||||
|
||||
if (action === "delete") {
|
||||
const chatId = readStringParam(params, "chatId", { required: true });
|
||||
const messageId = readStringParam(params, "messageId", {
|
||||
required: true,
|
||||
});
|
||||
return await handleTelegramAction(
|
||||
{
|
||||
action: "deleteMessage",
|
||||
chatId,
|
||||
messageId: Number(messageId),
|
||||
accountId: accountId ?? undefined,
|
||||
},
|
||||
cfg,
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error(`Action ${action} is not supported for provider ${providerId}.`);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { DmConfig, ProviderCommandsConfig } from "./types.messages.js";
|
||||
export type TelegramActionConfig = {
|
||||
reactions?: boolean;
|
||||
sendMessage?: boolean;
|
||||
deleteMessage?: boolean;
|
||||
};
|
||||
|
||||
export type TelegramAccountConfig = {
|
||||
|
||||
@@ -396,6 +396,44 @@ export async function reactMessageTelegram(
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
type TelegramDeleteOpts = {
|
||||
token?: string;
|
||||
accountId?: string;
|
||||
verbose?: boolean;
|
||||
api?: Bot["api"];
|
||||
retry?: RetryConfig;
|
||||
};
|
||||
|
||||
export async function deleteMessageTelegram(
|
||||
chatIdInput: string | number,
|
||||
messageIdInput: string | number,
|
||||
opts: TelegramDeleteOpts = {},
|
||||
): Promise<{ ok: true }> {
|
||||
const cfg = loadConfig();
|
||||
const account = resolveTelegramAccount({
|
||||
cfg,
|
||||
accountId: opts.accountId,
|
||||
});
|
||||
const token = resolveToken(opts.token, account);
|
||||
const chatId = normalizeChatId(String(chatIdInput));
|
||||
const messageId = normalizeMessageId(messageIdInput);
|
||||
const fetchImpl = resolveTelegramFetch();
|
||||
const client: ApiClientOptions | undefined = fetchImpl
|
||||
? { fetch: fetchImpl as unknown as ApiClientOptions["fetch"] }
|
||||
: undefined;
|
||||
const api = opts.api ?? new Bot(token, client ? { client } : undefined).api;
|
||||
const request = createTelegramRetryRunner({
|
||||
retry: opts.retry,
|
||||
configRetry: account.config.retry,
|
||||
verbose: opts.verbose,
|
||||
});
|
||||
await request(() => api.deleteMessage(chatId, messageId), "deleteMessage");
|
||||
logVerbose(
|
||||
`[telegram] Deleted message ${messageId} from chat ${chatId}`,
|
||||
);
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
function inferFilename(kind: ReturnType<typeof mediaKindFromMime>) {
|
||||
switch (kind) {
|
||||
case "image":
|
||||
|
||||
Reference in New Issue
Block a user