diff --git a/src/telegram/bot.test.ts b/src/telegram/bot.test.ts index b67bb3f083f..05b6590914c 100644 --- a/src/telegram/bot.test.ts +++ b/src/telegram/bot.test.ts @@ -967,6 +967,42 @@ describe("createTelegramBot", () => { expect(payload.ReplyToSender).toBe("unknown sender"); }); + it("uses external_reply quote text for partial replies", async () => { + onSpy.mockReset(); + sendMessageSpy.mockReset(); + const replySpy = replyModule.__replySpy as unknown as ReturnType; + replySpy.mockReset(); + + createTelegramBot({ token: "tok" }); + const handler = getOnHandler("message") as (ctx: Record) => Promise; + + await handler({ + message: { + chat: { id: 7, type: "private" }, + text: "Sure, see below", + date: 1736380800, + external_reply: { + message_id: 9002, + text: "Can you summarize this?", + from: { first_name: "Ada" }, + quote: { + text: "summarize this", + }, + }, + }, + me: { username: "openclaw_bot" }, + getFile: async () => ({ download: async () => new Uint8Array() }), + }); + + expect(replySpy).toHaveBeenCalledTimes(1); + const payload = replySpy.mock.calls[0][0]; + expect(payload.Body).toContain("[Quoting Ada id:9002]"); + expect(payload.Body).toContain('"summarize this"'); + expect(payload.ReplyToId).toBe("9002"); + expect(payload.ReplyToBody).toBe("summarize this"); + expect(payload.ReplyToSender).toBe("Ada"); + }); + it("sends replies without native reply threading", async () => { onSpy.mockReset(); sendMessageSpy.mockReset(); diff --git a/src/telegram/bot/delivery.test.ts b/src/telegram/bot/delivery.test.ts index 50c0537a8a3..036f4e7175b 100644 --- a/src/telegram/bot/delivery.test.ts +++ b/src/telegram/bot/delivery.test.ts @@ -194,7 +194,7 @@ describe("deliverReplies", () => { ); }); - it("uses reply_parameters when quote text is provided", async () => { + it("uses reply_to_message_id when quote text is provided", async () => { const runtime = { error: vi.fn(), log: vi.fn() }; const sendMessage = vi.fn().mockResolvedValue({ message_id: 10, @@ -217,10 +217,14 @@ describe("deliverReplies", () => { "123", expect.any(String), expect.objectContaining({ - reply_parameters: { - message_id: 500, - quote: "quoted text", - }, + reply_to_message_id: 500, + }), + ); + expect(sendMessage).toHaveBeenCalledWith( + "123", + expect.any(String), + expect.not.objectContaining({ + reply_parameters: expect.anything(), }), ); }); diff --git a/src/telegram/bot/delivery.ts b/src/telegram/bot/delivery.ts index f5eca9bfa56..4dce22e5991 100644 --- a/src/telegram/bot/delivery.ts +++ b/src/telegram/bot/delivery.ts @@ -484,16 +484,8 @@ function buildTelegramSendParams(opts?: { }): Record { const threadParams = buildTelegramThreadParams(opts?.thread); const params: Record = {}; - const quoteText = opts?.replyQuoteText?.trim(); if (opts?.replyToMessageId) { - if (quoteText) { - params.reply_parameters = { - message_id: Math.trunc(opts.replyToMessageId), - quote: quoteText, - }; - } else { - params.reply_to_message_id = opts.replyToMessageId; - } + params.reply_to_message_id = opts.replyToMessageId; } if (threadParams) { params.message_thread_id = threadParams.message_thread_id; diff --git a/src/telegram/bot/helpers.ts b/src/telegram/bot/helpers.ts index 533ab705e68..6f7ceb8d92b 100644 --- a/src/telegram/bot/helpers.ts +++ b/src/telegram/bot/helpers.ts @@ -226,31 +226,33 @@ export type TelegramReplyTarget = { export function describeReplyTarget(msg: Message): TelegramReplyTarget | null { const reply = msg.reply_to_message; - const quote = msg.quote; + const externalReply = msg.external_reply; + const quoteText = msg.quote?.text ?? reply?.quote?.text ?? externalReply?.quote?.text; let body = ""; let kind: TelegramReplyTarget["kind"] = "reply"; - if (quote?.text) { - body = quote.text.trim(); + if (typeof quoteText === "string") { + body = quoteText.trim(); if (body) { kind = "quote"; } } - if (!body && reply) { - const replyBody = (reply.text ?? reply.caption ?? "").trim(); + const replyLike = reply ?? externalReply; + if (!body && replyLike) { + const replyBody = (replyLike.text ?? replyLike.caption ?? "").trim(); body = replyBody; if (!body) { - if (reply.photo) { + if (replyLike.photo) { body = ""; - } else if (reply.video) { + } else if (replyLike.video) { body = ""; - } else if (reply.audio || reply.voice) { + } else if (replyLike.audio || replyLike.voice) { body = ""; - } else if (reply.document) { + } else if (replyLike.document) { body = ""; } else { - const locationData = extractTelegramLocation(reply); + const locationData = extractTelegramLocation(replyLike); if (locationData) { body = formatLocationText(locationData); } @@ -260,11 +262,11 @@ export function describeReplyTarget(msg: Message): TelegramReplyTarget | null { if (!body) { return null; } - const sender = reply ? buildSenderName(reply) : undefined; + const sender = replyLike ? buildSenderName(replyLike) : undefined; const senderLabel = sender ?? "unknown sender"; return { - id: reply?.message_id ? String(reply.message_id) : undefined, + id: replyLike?.message_id ? String(replyLike.message_id) : undefined, sender: senderLabel, body, kind,