From 1d7dd5f261492b4cfd0219871abbfcb8a975b6ac Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Mon, 2 Feb 2026 09:05:36 +0530 Subject: [PATCH] fix: require thread specs for telegram sends --- src/telegram/bot/delivery.ts | 8 ++++---- src/telegram/bot/helpers.test.ts | 10 +++++++--- src/telegram/bot/helpers.ts | 14 ++++---------- src/telegram/draft-stream.ts | 2 +- src/telegram/send.ts | 8 ++++++-- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/telegram/bot/delivery.ts b/src/telegram/bot/delivery.ts index e81effe359..f5eca9bfa5 100644 --- a/src/telegram/bot/delivery.ts +++ b/src/telegram/bot/delivery.ts @@ -39,7 +39,7 @@ export async function deliverReplies(params: { bot: Bot; replyToMode: ReplyToMode; textLimit: number; - thread?: TelegramThreadSpec | number | null; + thread?: TelegramThreadSpec | null; tableMode?: MarkdownTableMode; chunkMode?: ChunkMode; /** Callback invoked before sending a voice message to switch typing indicator. */ @@ -451,7 +451,7 @@ async function sendTelegramVoiceFallbackText(opts: { replyToId?: number; replyToMode: ReplyToMode; hasReplied: boolean; - thread?: TelegramThreadSpec | number | null; + thread?: TelegramThreadSpec | null; linkPreview?: boolean; replyMarkup?: ReturnType; replyQuoteText?: string; @@ -479,7 +479,7 @@ async function sendTelegramVoiceFallbackText(opts: { function buildTelegramSendParams(opts?: { replyToMessageId?: number; - thread?: TelegramThreadSpec | number | null; + thread?: TelegramThreadSpec | null; replyQuoteText?: string; }): Record { const threadParams = buildTelegramThreadParams(opts?.thread); @@ -509,7 +509,7 @@ async function sendTelegramText( opts?: { replyToMessageId?: number; replyQuoteText?: string; - thread?: TelegramThreadSpec | number | null; + thread?: TelegramThreadSpec | null; textMode?: "markdown" | "html"; plainText?: string; linkPreview?: boolean; diff --git a/src/telegram/bot/helpers.test.ts b/src/telegram/bot/helpers.test.ts index 026f2ef77b..c52575f520 100644 --- a/src/telegram/bot/helpers.test.ts +++ b/src/telegram/bot/helpers.test.ts @@ -34,11 +34,13 @@ describe("resolveTelegramForumThreadId", () => { describe("buildTelegramThreadParams", () => { it("omits General topic thread id for message sends", () => { - expect(buildTelegramThreadParams(1)).toBeUndefined(); + expect(buildTelegramThreadParams({ id: 1, scope: "forum" })).toBeUndefined(); }); it("includes non-General topic thread ids", () => { - expect(buildTelegramThreadParams(99)).toEqual({ message_thread_id: 99 }); + expect(buildTelegramThreadParams({ id: 99, scope: "forum" })).toEqual({ + message_thread_id: 99, + }); }); it("keeps thread id=1 for dm threads", () => { @@ -48,7 +50,9 @@ describe("buildTelegramThreadParams", () => { }); it("normalizes thread ids to integers", () => { - expect(buildTelegramThreadParams(42.9)).toEqual({ message_thread_id: 42 }); + expect(buildTelegramThreadParams({ id: 42.9, scope: "forum" })).toEqual({ + message_thread_id: 42, + }); }); }); diff --git a/src/telegram/bot/helpers.ts b/src/telegram/bot/helpers.ts index f54e11bc55..6915f68d65 100644 --- a/src/telegram/bot/helpers.ts +++ b/src/telegram/bot/helpers.ts @@ -69,18 +69,12 @@ export function resolveTelegramThreadSpec(params: { * General forum topic (id=1) must be treated like a regular supergroup send: * Telegram rejects sendMessage/sendMedia with message_thread_id=1 ("thread not found"). */ -export function buildTelegramThreadParams(thread?: TelegramThreadSpec | number | null) { - let spec: TelegramThreadSpec | undefined; - if (typeof thread === "number") { - spec = { id: thread, scope: "forum" }; - } else if (thread && typeof thread === "object") { - spec = thread; - } - if (!spec?.id) { +export function buildTelegramThreadParams(thread?: TelegramThreadSpec | null) { + if (!thread?.id) { return undefined; } - const normalized = Math.trunc(spec.id); - if (normalized === TELEGRAM_GENERAL_TOPIC_ID && spec.scope === "forum") { + const normalized = Math.trunc(thread.id); + if (normalized === TELEGRAM_GENERAL_TOPIC_ID && thread.scope === "forum") { return undefined; } return { message_thread_id: normalized }; diff --git a/src/telegram/draft-stream.ts b/src/telegram/draft-stream.ts index 55d8ee3362..87a443cdb8 100644 --- a/src/telegram/draft-stream.ts +++ b/src/telegram/draft-stream.ts @@ -15,7 +15,7 @@ export function createTelegramDraftStream(params: { chatId: number; draftId: number; maxChars?: number; - thread?: TelegramThreadSpec | number | null; + thread?: TelegramThreadSpec | null; throttleMs?: number; log?: (message: string) => void; warn?: (message: string) => void; diff --git a/src/telegram/send.ts b/src/telegram/send.ts index cf5f802987..29cbede999 100644 --- a/src/telegram/send.ts +++ b/src/telegram/send.ts @@ -221,7 +221,9 @@ export async function sendMessageTelegram( // Only include these if actually provided to keep API calls clean. const messageThreadId = opts.messageThreadId != null ? opts.messageThreadId : target.messageThreadId; - const threadIdParams = buildTelegramThreadParams(messageThreadId); + const threadSpec = + messageThreadId != null ? { id: messageThreadId, scope: "forum" as const } : undefined; + const threadIdParams = buildTelegramThreadParams(threadSpec); const threadParams: Record = threadIdParams ? { ...threadIdParams } : {}; const quoteText = opts.quoteText?.trim(); if (opts.replyToMessageId != null) { @@ -694,7 +696,9 @@ export async function sendStickerTelegram( const messageThreadId = opts.messageThreadId != null ? opts.messageThreadId : target.messageThreadId; - const threadIdParams = buildTelegramThreadParams(messageThreadId); + const threadSpec = + messageThreadId != null ? { id: messageThreadId, scope: "forum" as const } : undefined; + const threadIdParams = buildTelegramThreadParams(threadSpec); const threadParams: Record = threadIdParams ? { ...threadIdParams } : {}; if (opts.replyToMessageId != null) { threadParams.reply_to_message_id = Math.trunc(opts.replyToMessageId);