diff --git a/src/telegram/bot/delivery.test.ts b/src/telegram/bot/delivery.test.ts index 88c4e2a0c..8c58bf9d8 100644 --- a/src/telegram/bot/delivery.test.ts +++ b/src/telegram/bot/delivery.test.ts @@ -167,7 +167,7 @@ describe("deliverReplies", () => { ); }); - it("does not include message_thread_id for DMs (threads don't exist in private chats)", async () => { + it("includes message_thread_id for DM topics", async () => { const runtime = createRuntime(); const sendMessage = vi.fn().mockResolvedValue({ message_id: 4, @@ -179,14 +179,14 @@ describe("deliverReplies", () => { replies: [{ text: "Hello" }], runtime, bot, - thread: { id: 1, scope: "dm" }, + thread: { id: 42, scope: "dm" }, }); expect(sendMessage).toHaveBeenCalledWith( "123", expect.any(String), - expect.not.objectContaining({ - message_thread_id: 1, + expect.objectContaining({ + message_thread_id: 42, }), ); }); diff --git a/src/telegram/bot/helpers.test.ts b/src/telegram/bot/helpers.test.ts index d0f91345d..a03ad3344 100644 --- a/src/telegram/bot/helpers.test.ts +++ b/src/telegram/bot/helpers.test.ts @@ -43,15 +43,21 @@ describe("buildTelegramThreadParams", () => { }); }); - it("skips thread id for dm threads (DMs don't have threads)", () => { - expect(buildTelegramThreadParams({ id: 1, scope: "dm" })).toBeUndefined(); - expect(buildTelegramThreadParams({ id: 2, scope: "dm" })).toBeUndefined(); + it("includes thread id for dm topics", () => { + expect(buildTelegramThreadParams({ id: 1, scope: "dm" })).toEqual({ + message_thread_id: 1, + }); + expect(buildTelegramThreadParams({ id: 2, scope: "dm" })).toEqual({ + message_thread_id: 2, + }); }); - it("normalizes and skips thread id for dm threads even with edge values", () => { + it("normalizes dm thread ids and skips non-positive values", () => { expect(buildTelegramThreadParams({ id: 0, scope: "dm" })).toBeUndefined(); expect(buildTelegramThreadParams({ id: -1, scope: "dm" })).toBeUndefined(); - expect(buildTelegramThreadParams({ id: 1.9, scope: "dm" })).toBeUndefined(); + expect(buildTelegramThreadParams({ id: 1.9, scope: "dm" })).toEqual({ + message_thread_id: 1, + }); }); it("handles thread id 0 for non-dm scopes", () => { diff --git a/src/telegram/bot/helpers.ts b/src/telegram/bot/helpers.ts index a39d5f15d..25c081e60 100644 --- a/src/telegram/bot/helpers.ts +++ b/src/telegram/bot/helpers.ts @@ -114,7 +114,7 @@ export function resolveTelegramThreadSpec(params: { * Build thread params for Telegram API calls (messages, media). * * IMPORTANT: Thread IDs behave differently based on chat type: - * - DMs (private chats): Never send thread_id (threads don't exist) + * - DMs (private chats): Include message_thread_id when present (DM topics) * - Forum topics: Skip thread_id=1 (General topic), include others * - Regular groups: Thread IDs are ignored by Telegram * @@ -130,9 +130,8 @@ export function buildTelegramThreadParams(thread?: TelegramThreadSpec | null) { } const normalized = Math.trunc(thread.id); - // Never send thread_id for DMs (threads don't exist in private chats) if (thread.scope === "dm") { - return undefined; + return normalized > 0 ? { message_thread_id: normalized } : undefined; } // Telegram rejects message_thread_id=1 for General forum topic diff --git a/src/telegram/draft-stream.test.ts b/src/telegram/draft-stream.test.ts index f856f3a6a..9f1f2a7f8 100644 --- a/src/telegram/draft-stream.test.ts +++ b/src/telegram/draft-stream.test.ts @@ -86,12 +86,14 @@ describe("createTelegramDraftStream", () => { await vi.waitFor(() => expect(api.sendMessage).toHaveBeenCalledWith(123, "Hello", undefined)); }); - it("omits message_thread_id for dm threads and clears preview on cleanup", async () => { + it("includes message_thread_id for dm threads and clears preview on cleanup", async () => { const api = createMockDraftApi(); - const stream = createThreadedDraftStream(api, { id: 1, scope: "dm" }); + const stream = createThreadedDraftStream(api, { id: 42, scope: "dm" }); stream.update("Hello"); - await vi.waitFor(() => expect(api.sendMessage).toHaveBeenCalledWith(123, "Hello", undefined)); + await vi.waitFor(() => + expect(api.sendMessage).toHaveBeenCalledWith(123, "Hello", { message_thread_id: 42 }), + ); await stream.clear(); expect(api.deleteMessage).toHaveBeenCalledWith(123, 17);