diff --git a/extensions/telegram/src/bot/delivery.test.ts b/extensions/telegram/src/bot/delivery.test.ts index a6de461a8e30..81ca014f3f6e 100644 --- a/extensions/telegram/src/bot/delivery.test.ts +++ b/extensions/telegram/src/bot/delivery.test.ts @@ -323,6 +323,25 @@ describe("deliverReplies", () => { expect(firstMockCallArg(sendMessage, 1)).toBe("hello"); }); + it("keeps native-command tables visible in non-rich block-mode replies", async () => { + const { runtime, sendMessage, bot } = createSendMessageHarness(); + const table = "| A | B |\n| --- | --- |\n| 1 | 2 |"; + + await deliverWith({ + replies: [{ text: `Before\n\n${table}\n\nAfter` }], + runtime, + bot, + tableMode: "block", + }); + + expect(sendMessage).toHaveBeenCalledTimes(1); + const sent = firstSendText(sendMessage); + expect(sent).toContain("Before"); + expect(sent).toContain(`
${table}\n`);
+ expect(sent).toContain("After");
+ expectRecordFields(firstMockCallArg(sendMessage, 2), { parse_mode: "HTML" });
+ });
+
it("delivers prepared HTML without reparsing visible syntax as Markdown", async () => {
const runtime = createRuntime();
const sendMessage = vi.fn().mockResolvedValue({ message_id: 1, chat: { id: "123" } });
diff --git a/extensions/telegram/src/format.test.ts b/extensions/telegram/src/format.test.ts
index 77fc0cb35d7e..e62abc150b4c 100644
--- a/extensions/telegram/src/format.test.ts
+++ b/extensions/telegram/src/format.test.ts
@@ -139,12 +139,24 @@ describe("markdownToTelegramHtml", () => {
);
});
- it("renders block-mode tables as code in legacy Telegram HTML", () => {
+ it.each([
+ { name: "a table-only reply", before: "", after: "" },
+ { name: "a table between surrounding prose", before: "Before\n\n", after: "\n\nAfter" },
+ ])("keeps $name visible in one-shot and chunked legacy Telegram HTML", ({ before, after }) => {
const table = "| A | B |\n| --- | --- |\n| 1 | 2 |";
+ const markdown = `${before}${table}${after}`;
+ const html = markdownToTelegramHtml(markdown, { tableMode: "block" });
+ const chunks = markdownToTelegramChunks(markdown, 4096, { tableMode: "block" });
- expect(markdownToTelegramHtml(table, { tableMode: "block" })).toBe(
- "| A | B |\n| --- | --- |\n| 1 | 2 |\n",
- );
+ expect(html).toContain(`${table}\n`);
+ expect(chunks.map((chunk) => chunk.html)).toEqual([html]);
+ expect(chunks[0]?.text).toContain("| 1 | 2 |");
+ if (before) {
+ expect(html).toContain("Before");
+ }
+ if (after) {
+ expect(html).toContain("After");
+ }
});
it("normalizes raw code language HTML without leaking tags", () => {
diff --git a/extensions/telegram/src/format.ts b/extensions/telegram/src/format.ts
index 2670b60f9368..7efc4899ad79 100644
--- a/extensions/telegram/src/format.ts
+++ b/extensions/telegram/src/format.ts
@@ -147,19 +147,22 @@ function preserveTelegramListBoundarySpacing(markdown: string): string {
return out.join("\n");
}
-export function markdownToTelegramHtml(
- markdown: string,
- options: { tableMode?: MarkdownTableMode; wrapFileRefs?: boolean } = {},
-): string {
- const tableMode = options.tableMode === "block" ? "code" : options.tableMode;
- const ir = markdownToIR(preserveTelegramListBoundarySpacing(markdown ?? ""), {
+function parseTelegramLegacyMarkdown(markdown: string, tableMode?: MarkdownTableMode): MarkdownIR {
+ return markdownToIR(preserveTelegramListBoundarySpacing(markdown ?? ""), {
assistantTranscriptRoleHeaders: true,
linkify: true,
enableSpoilers: true,
headingStyle: "none",
blockquotePrefix: "",
- tableMode,
+ tableMode: tableMode === "block" ? "code" : tableMode,
});
+}
+
+export function markdownToTelegramHtml(
+ markdown: string,
+ options: { tableMode?: MarkdownTableMode; wrapFileRefs?: boolean } = {},
+): string {
+ const ir = parseTelegramLegacyMarkdown(markdown, options.tableMode);
const html = renderTelegramHtml(ir);
const telegramHtml = renderSupportedTelegramHtml(html);
// Apply file reference wrapping if requested (for chunked rendering)
@@ -910,14 +913,7 @@ export function markdownToTelegramChunks(
limit: number,
options: { tableMode?: MarkdownTableMode } = {},
): TelegramFormattedChunk[] {
- const ir = markdownToIR(preserveTelegramListBoundarySpacing(markdown ?? ""), {
- assistantTranscriptRoleHeaders: true,
- linkify: true,
- enableSpoilers: true,
- headingStyle: "none",
- blockquotePrefix: "",
- tableMode: options.tableMode,
- });
+ const ir = parseTelegramLegacyMarkdown(markdown, options.tableMode);
return renderTelegramChunksWithinHtmlLimit(ir, limit);
}