From 26f51b83077df3cd047a6f687524abd59435a917 Mon Sep 17 00:00:00 2001 From: Tyler Diaz Date: Wed, 28 Jan 2026 13:42:20 -0800 Subject: [PATCH] feat(telegram): add editForumTopic support for thread-edit action - Add editForumTopicTelegram() to telegram/send.ts - Add editForumTopic action handler in telegram-actions.ts - Register thread-edit action in telegram message plugin - Add editForumTopic to TelegramActionConfig type - Add thread-edit to CHANNEL_MESSAGE_ACTION_NAMES Allows agents to rename forum topics and update custom emoji icons via: message({ action: 'thread-edit', channel: 'telegram', target: '', threadId: , threadName: 'New Name' }) --- src/agents/tools/telegram-actions.ts | 34 +++++++++ src/channels/plugins/actions/telegram.ts | 28 ++++++++ src/channels/plugins/message-action-names.ts | 1 + src/config/types.telegram.ts | 2 + src/infra/outbound/message-action-spec.ts | 1 + src/telegram/send.ts | 74 ++++++++++++++++++++ 6 files changed, 140 insertions(+) diff --git a/src/agents/tools/telegram-actions.ts b/src/agents/tools/telegram-actions.ts index e96c384bb..0489e5d30 100644 --- a/src/agents/tools/telegram-actions.ts +++ b/src/agents/tools/telegram-actions.ts @@ -4,6 +4,7 @@ import { resolveTelegramReactionLevel } from "../../telegram/reaction-level.js"; import { createForumTopicTelegram, deleteMessageTelegram, + editForumTopicTelegram, editMessageTelegram, reactMessageTelegram, sendMessageTelegram, @@ -352,5 +353,38 @@ export async function handleTelegramAction( }); } + if (action === "editForumTopic") { + if (!isActionEnabled("editForumTopic", false)) { + throw new Error( + "Telegram editForumTopic is disabled. Set channels.telegram.actions.editForumTopic to true.", + ); + } + const chatId = readStringOrNumberParam(params, "chatId", { + required: true, + }); + const messageThreadId = readNumberParam(params, "messageThreadId", { + required: true, + integer: true, + }); + const name = readStringParam(params, "name"); + const iconCustomEmojiId = readStringParam(params, "iconCustomEmojiId"); + if (!name && !iconCustomEmojiId) { + throw new Error("At least one of name or iconCustomEmojiId is required"); + } + const token = resolveTelegramToken(cfg, { accountId }).token; + if (!token) { + throw new Error( + "Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.", + ); + } + await editForumTopicTelegram(chatId ?? "", messageThreadId ?? 0, { + token, + accountId: accountId ?? undefined, + name: name ?? undefined, + iconCustomEmojiId: iconCustomEmojiId ?? undefined, + }); + return jsonResult({ ok: true }); + } + throw new Error(`Unsupported Telegram action: ${action}`); } diff --git a/src/channels/plugins/actions/telegram.ts b/src/channels/plugins/actions/telegram.ts index 01759c01f..797f5efb6 100644 --- a/src/channels/plugins/actions/telegram.ts +++ b/src/channels/plugins/actions/telegram.ts @@ -55,6 +55,9 @@ export const telegramMessageActions: ChannelMessageActionAdapter = { if (gate("createForumTopic", false)) { actions.add("thread-create"); } + if (gate("editForumTopic", false)) { + actions.add("thread-edit"); + } return Array.from(actions); }, supportsButtons: ({ cfg }) => { @@ -204,6 +207,31 @@ export const telegramMessageActions: ChannelMessageActionAdapter = { ); } + if (action === "thread-edit") { + const chatId = + readStringOrNumberParam(params, "chatId") ?? + readStringOrNumberParam(params, "channelId") ?? + readStringParam(params, "target") ?? + readStringParam(params, "to", { required: true }); + const messageThreadId = readNumberParam(params, "threadId", { + required: true, + integer: true, + }); + const name = readStringParam(params, "threadName"); + const iconCustomEmojiId = readStringParam(params, "iconCustomEmojiId"); + return await handleTelegramAction( + { + action: "editForumTopic", + chatId, + messageThreadId, + name: name ?? undefined, + iconCustomEmojiId: iconCustomEmojiId ?? undefined, + accountId: accountId ?? undefined, + }, + cfg, + ); + } + throw new Error(`Action ${action} is not supported for provider ${providerId}.`); }, }; diff --git a/src/channels/plugins/message-action-names.ts b/src/channels/plugins/message-action-names.ts index 1884cacb0..193282c16 100644 --- a/src/channels/plugins/message-action-names.ts +++ b/src/channels/plugins/message-action-names.ts @@ -21,6 +21,7 @@ export const CHANNEL_MESSAGE_ACTION_NAMES = [ "list-pins", "permissions", "thread-create", + "thread-edit", "thread-list", "thread-reply", "search", diff --git a/src/config/types.telegram.ts b/src/config/types.telegram.ts index 354ec7d76..5fec12831 100644 --- a/src/config/types.telegram.ts +++ b/src/config/types.telegram.ts @@ -20,6 +20,8 @@ export type TelegramActionConfig = { sticker?: boolean; /** Enable creating forum topics in supergroups. */ createForumTopic?: boolean; + /** Enable editing forum topics in supergroups. */ + editForumTopic?: boolean; }; export type TelegramNetworkConfig = { diff --git a/src/infra/outbound/message-action-spec.ts b/src/infra/outbound/message-action-spec.ts index 639e641d0..07d525323 100644 --- a/src/infra/outbound/message-action-spec.ts +++ b/src/infra/outbound/message-action-spec.ts @@ -26,6 +26,7 @@ export const MESSAGE_ACTION_TARGET_MODE: Record { + if (!opts.name && !opts.iconCustomEmojiId) { + throw new Error("At least one of name or iconCustomEmojiId is required to edit a forum topic"); + } + + const cfg = loadConfig(); + const account = resolveTelegramAccount({ + cfg, + accountId: opts.accountId, + }); + const token = resolveToken(opts.token, account); + const chatId = normalizeChatId(String(chatIdInput)); + const client = resolveTelegramClientOptions(account); + const api = opts.api ?? new Bot(token, client ? { client } : undefined).api; + + const request = createTelegramRetryRunner({ + retry: opts.retry, + configRetry: account.config.retry, + verbose: opts.verbose, + }); + const logHttpError = createTelegramHttpLogger(cfg); + const requestWithDiag = (fn: () => Promise, label?: string) => + withTelegramApiErrorLogging({ + operation: label ?? "request", + fn: () => request(fn, label), + }).catch((err) => { + logHttpError(label ?? "request", err); + throw err; + }); + + const params: Record = {}; + if (opts.name) { + params.name = opts.name; + } + if (opts.iconCustomEmojiId) { + params.icon_custom_emoji_id = opts.iconCustomEmojiId; + } + + await requestWithDiag( + () => api.editForumTopic(chatId, messageThreadId, params), + "editForumTopic", + ); + + logVerbose(`[telegram] Edited forum topic ${messageThreadId} in chat ${chatId}`); + + return { ok: true }; +} + /** * Create a new forum topic in a Telegram supergroup with topics enabled. * @param chatIdInput - Chat ID of the supergroup