mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-16 11:16:13 +00:00
fix(telegram): keep streamed final pages on word boundaries (#104608)
* fix(telegram): align draft final pagination * chore: drop release-owned changelog entry * style(telegram): format pagination parity test
This commit is contained in:
committed by
GitHub
parent
473df17bd7
commit
fe3884a7ad
File diff suppressed because one or more lines are too long
@@ -726,6 +726,10 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
expect(renderText?.("# Heading")).toEqual({
|
||||
text: "Heading",
|
||||
parseMode: "HTML",
|
||||
markdownSource: {
|
||||
text: "# Heading",
|
||||
tableMode: "preserve",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -948,6 +948,7 @@ export const dispatchTelegramMessage = async ({
|
||||
: {
|
||||
text: renderTelegramHtmlText(text, { tableMode }),
|
||||
parseMode: "HTML",
|
||||
markdownSource: { text, tableMode },
|
||||
};
|
||||
const accountBlockStreamingEnabled =
|
||||
resolveChannelStreamingBlockEnabled(telegramCfg) ??
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
import type { Bot } from "grammy";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { createTelegramDraftStream } from "./draft-stream.js";
|
||||
import { renderTelegramHtmlText, telegramHtmlToPlainTextFallback } from "./format.js";
|
||||
import {
|
||||
markdownToTelegramChunks,
|
||||
renderTelegramHtmlText,
|
||||
telegramHtmlToPlainTextFallback,
|
||||
} from "./format.js";
|
||||
import { buildTelegramRichMarkdown, type TelegramInputRichMessage } from "./rich-message.js";
|
||||
|
||||
type TelegramDraftStreamParams = Parameters<typeof createTelegramDraftStream>[0];
|
||||
@@ -1278,6 +1282,34 @@ describe("createTelegramDraftStream", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("shares durable Markdown chunk boundaries with final draft pagination", async () => {
|
||||
const api = createMockDraftApi();
|
||||
const text = Array.from(
|
||||
{ length: 12 },
|
||||
(_, index) =>
|
||||
`**${String(index).padStart(2, "0")}** overflow pagination line with filler text`,
|
||||
).join("\n");
|
||||
const maxChars = 80;
|
||||
const expectedChunks = markdownToTelegramChunks(text, maxChars);
|
||||
const stream = createDraftStream(api, {
|
||||
maxChars,
|
||||
renderText: (value) => ({
|
||||
text: renderTelegramHtmlText(value),
|
||||
parseMode: "HTML",
|
||||
markdownSource: { text: value },
|
||||
}),
|
||||
});
|
||||
|
||||
stream.update(text);
|
||||
await stream.stop();
|
||||
|
||||
const pages = api.sendMessage.mock.calls.map((call) => call[1]);
|
||||
expect(pages).toEqual(expectedChunks.map((chunk) => chunk.html));
|
||||
expect(pages.map(telegramHtmlToPlainTextFallback)).toEqual(
|
||||
expectedChunks.map((chunk) => chunk.text),
|
||||
);
|
||||
});
|
||||
|
||||
it("paginates one rendered rich-code plan without reparsing Markdown tails", async () => {
|
||||
const api = createMockDraftApi();
|
||||
const onSupersededPreview = vi.fn();
|
||||
|
||||
@@ -4,12 +4,13 @@ import {
|
||||
createFinalizableDraftStreamControlsForState,
|
||||
takeMessageIdAfterStop,
|
||||
} from "openclaw/plugin-sdk/channel-outbound";
|
||||
import type { ReplyToMode } from "openclaw/plugin-sdk/config-contracts";
|
||||
import type { MarkdownTableMode, ReplyToMode } from "openclaw/plugin-sdk/config-contracts";
|
||||
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
||||
import { isSingleUseReplyToMode } from "openclaw/plugin-sdk/reply-reference";
|
||||
import { buildTelegramThreadParams, type TelegramThreadSpec } from "./bot/helpers.js";
|
||||
import {
|
||||
escapeTelegramHtml,
|
||||
markdownToTelegramChunks,
|
||||
renderTelegramHtmlText,
|
||||
splitTelegramHtmlChunks,
|
||||
telegramHtmlToPlainTextFallback,
|
||||
@@ -102,6 +103,10 @@ export type TelegramDraftPreview = {
|
||||
text: string;
|
||||
parseMode?: "HTML";
|
||||
richMessage?: TelegramInputRichMessage;
|
||||
markdownSource?: {
|
||||
text: string;
|
||||
tableMode?: MarkdownTableMode;
|
||||
};
|
||||
};
|
||||
|
||||
type PlannedTelegramDraftPage = TelegramDraftMessageSnapshot & {
|
||||
@@ -172,6 +177,17 @@ function planTelegramDraftPages(
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
if (preview.markdownSource) {
|
||||
// Keep streaming-final pagination on the durable send funnel's chunker;
|
||||
// splitting pre-rendered HTML loses Markdown word and block boundaries.
|
||||
return markdownToTelegramChunks(preview.markdownSource.text, maxChars, {
|
||||
tableMode: preview.markdownSource.tableMode,
|
||||
}).map((chunk) => ({
|
||||
text: chunk.text,
|
||||
sourceText: chunk.html,
|
||||
sourceTextMode: "html",
|
||||
}));
|
||||
}
|
||||
const htmlText = preview.richMessage?.html
|
||||
? telegramRichHtmlToParseModeHtml(preview.richMessage.html)
|
||||
: preview.richMessage?.markdown
|
||||
|
||||
Reference in New Issue
Block a user