From 6146acbb6917139bbad68369085279c4ff26f505 Mon Sep 17 00:00:00 2001 From: Azade Date: Thu, 15 Jan 2026 23:21:10 +0000 Subject: [PATCH] fix(telegram): separate thread params for typing vs messages Telegram General topic (id=1) has inconsistent API behavior: - sendMessage: rejects explicit message_thread_id=1 - sendChatAction: requires message_thread_id=1 for typing to show Split into two helper functions: - buildTelegramThreadParams: excludes General topic for messages - buildTypingThreadParams: includes General topic for typing --- src/telegram/bot-message-context.ts | 3 ++- src/telegram/bot/helpers.ts | 21 ++++++++++++++++++++- src/telegram/send.ts | 7 +++---- 3 files changed, 25 insertions(+), 6 deletions(-) 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); }