From 27052806eafeb5e5b19195c1159ae77baac47418 Mon Sep 17 00:00:00 2001 From: Ben Sabic Date: Sun, 15 Mar 2026 21:36:15 +1100 Subject: [PATCH] fix(telegram): set parse_mode for markdown messages postMessage and editMessage only set parse_mode when a card was present, causing markdown messages to render as plain text with visible formatting characters. Now also sets parse_mode when the message has a markdown field. Closes #226 --- .../fix-telegram-markdown-parse-mode.md | 5 +++ packages/adapter-telegram/src/index.test.ts | 32 +++++++++++++++++++ packages/adapter-telegram/src/index.ts | 10 ++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/fix-telegram-markdown-parse-mode.md diff --git a/.changeset/fix-telegram-markdown-parse-mode.md b/.changeset/fix-telegram-markdown-parse-mode.md new file mode 100644 index 00000000..51a3210b --- /dev/null +++ b/.changeset/fix-telegram-markdown-parse-mode.md @@ -0,0 +1,5 @@ +--- +"@chat-adapter/telegram": patch +--- + +Set `parse_mode` to `"Markdown"` when posting messages with a `markdown` field, not only for card messages diff --git a/packages/adapter-telegram/src/index.test.ts b/packages/adapter-telegram/src/index.test.ts index a0d64168..cc5d195f 100644 --- a/packages/adapter-telegram/src/index.test.ts +++ b/packages/adapter-telegram/src/index.test.ts @@ -943,6 +943,38 @@ describe("TelegramAdapter", () => { expect(sendMessageBody.text).toBe("raw id message"); }); + it("sets parse_mode for markdown messages", async () => { + mockFetch + .mockResolvedValueOnce( + telegramOk({ + id: 999, + is_bot: true, + first_name: "Bot", + username: "mybot", + }) + ) + .mockResolvedValueOnce(telegramOk(sampleMessage())); + + const adapter = createTelegramAdapter({ + botToken: "token", + mode: "webhook", + logger: mockLogger, + userName: "mybot", + }); + + await adapter.initialize(createMockChat()); + + await adapter.postMessage("telegram:123", { + markdown: "**bold** and _italic_", + }); + + const sendMessageBody = JSON.parse( + String((mockFetch.mock.calls[1]?.[1] as RequestInit).body) + ) as { parse_mode?: string }; + + expect(sendMessageBody.parse_mode).toBe("Markdown"); + }); + it("posts cards with inline keyboard buttons", async () => { mockFetch .mockResolvedValueOnce( diff --git a/packages/adapter-telegram/src/index.ts b/packages/adapter-telegram/src/index.ts index ee2cdd22..272b2e69 100644 --- a/packages/adapter-telegram/src/index.ts +++ b/packages/adapter-telegram/src/index.ts @@ -556,7 +556,10 @@ export class TelegramAdapter const card = extractCard(message); const replyMarkup = card ? cardToTelegramInlineKeyboard(card) : undefined; - const parseMode = card ? TELEGRAM_MARKDOWN_PARSE_MODE : undefined; + const hasMarkdown = + typeof message === "object" && message !== null && "markdown" in message; + const parseMode = + card || hasMarkdown ? TELEGRAM_MARKDOWN_PARSE_MODE : undefined; const text = this.truncateMessage( convertEmojiPlaceholders( card @@ -642,7 +645,10 @@ export class TelegramAdapter const card = extractCard(message); const replyMarkup = card ? cardToTelegramInlineKeyboard(card) : undefined; - const parseMode = card ? TELEGRAM_MARKDOWN_PARSE_MODE : undefined; + const hasMarkdown = + typeof message === "object" && message !== null && "markdown" in message; + const parseMode = + card || hasMarkdown ? TELEGRAM_MARKDOWN_PARSE_MODE : undefined; const text = this.truncateMessage( convertEmojiPlaceholders( card