diff --git a/src/telegram/bot-message-context.ts b/src/telegram/bot-message-context.ts index bc43a1ded..30075564d 100644 --- a/src/telegram/bot-message-context.ts +++ b/src/telegram/bot-message-context.ts @@ -18,6 +18,7 @@ import { buildTelegramGroupFrom, buildTelegramGroupPeerId, buildTelegramThreadParams, + buildTypingThreadParams, describeReplyTarget, extractTelegramLocation, hasBotMention, @@ -92,7 +93,7 @@ export const buildTelegramMessageContext = async ({ const sendTyping = async () => { try { - await bot.api.sendChatAction(chatId, "typing", buildTelegramThreadParams(resolvedThreadId)); + await bot.api.sendChatAction(chatId, "typing", buildTypingThreadParams(resolvedThreadId)); } catch (err) { logVerbose(`telegram typing cue failed for chat ${chatId}: ${String(err)}`); } diff --git a/src/telegram/bot/helpers.ts b/src/telegram/bot/helpers.ts index c3b74b76a..8d6a5980c 100644 --- a/src/telegram/bot/helpers.ts +++ b/src/telegram/bot/helpers.ts @@ -19,8 +19,27 @@ export function resolveTelegramForumThreadId(params: { return params.messageThreadId ?? undefined; } +/** + * Build thread params for Telegram API calls (messages, media). + * Excludes General topic (id=1) as Telegram rejects explicit message_thread_id=1 + * for sendMessage calls in forum supergroups ("message thread not found" error). + */ export function buildTelegramThreadParams(messageThreadId?: number) { - return messageThreadId != null ? { message_thread_id: messageThreadId } : undefined; + if (messageThreadId == null || messageThreadId === TELEGRAM_GENERAL_TOPIC_ID) { + return undefined; + } + return { message_thread_id: messageThreadId }; +} + +/** + * Build thread params for typing indicators (sendChatAction). + * Unlike sendMessage, sendChatAction accepts message_thread_id=1 for General topic. + */ +export function buildTypingThreadParams(messageThreadId?: number) { + if (messageThreadId == null) { + return undefined; + } + return { message_thread_id: messageThreadId }; } export function resolveTelegramStreamMode( diff --git a/src/telegram/send.ts b/src/telegram/send.ts index d2c54ff49..615872c83 100644 --- a/src/telegram/send.ts +++ b/src/telegram/send.ts @@ -20,6 +20,7 @@ import { markdownToTelegramHtml } from "./format.js"; import { recordSentMessage } from "./sent-message-cache.js"; import { parseTelegramTarget, stripTelegramInternalPrefixes } from "./targets.js"; import { resolveTelegramVoiceSend } from "./voice.js"; +import { buildTelegramThreadParams } from "./bot/helpers.js"; type TelegramSendOpts = { token?: string; @@ -166,12 +167,10 @@ export async function sendMessageTelegram( // Build optional params for forum topics and reply threading. // Only include these if actually provided to keep API calls clean. - const threadParams: Record = {}; const messageThreadId = opts.messageThreadId != null ? opts.messageThreadId : target.messageThreadId; - if (messageThreadId != null) { - threadParams.message_thread_id = Math.trunc(messageThreadId); - } + const threadIdParams = buildTelegramThreadParams(messageThreadId); + const threadParams: Record = threadIdParams ? { ...threadIdParams } : {}; if (opts.replyToMessageId != null) { threadParams.reply_to_message_id = Math.trunc(opts.replyToMessageId); }