mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 17:44:33 +00:00
fix: enforce telegram shared outbound chunking
This commit is contained in:
@@ -241,6 +241,58 @@ export function renderTelegramHtmlText(
|
||||
return markdownToTelegramHtml(text, { tableMode: options.tableMode });
|
||||
}
|
||||
|
||||
function splitTelegramChunkByHtmlLimit(
|
||||
chunk: MarkdownIR,
|
||||
htmlLimit: number,
|
||||
renderedHtmlLength: number,
|
||||
): MarkdownIR[] {
|
||||
const currentTextLength = chunk.text.length;
|
||||
if (currentTextLength <= 1) {
|
||||
return [chunk];
|
||||
}
|
||||
const proportionalLimit = Math.floor(
|
||||
(currentTextLength * htmlLimit) / Math.max(renderedHtmlLength, 1),
|
||||
);
|
||||
const candidateLimit = Math.min(currentTextLength - 1, proportionalLimit);
|
||||
const splitLimit =
|
||||
Number.isFinite(candidateLimit) && candidateLimit > 0
|
||||
? candidateLimit
|
||||
: Math.max(1, Math.floor(currentTextLength / 2));
|
||||
const split = chunkMarkdownIR(chunk, splitLimit);
|
||||
if (split.length > 1) {
|
||||
return split;
|
||||
}
|
||||
return chunkMarkdownIR(chunk, Math.max(1, Math.floor(currentTextLength / 2)));
|
||||
}
|
||||
|
||||
function renderTelegramChunksWithinHtmlLimit(
|
||||
ir: MarkdownIR,
|
||||
limit: number,
|
||||
): TelegramFormattedChunk[] {
|
||||
const normalizedLimit = Math.max(1, Math.floor(limit));
|
||||
const pending = chunkMarkdownIR(ir, normalizedLimit);
|
||||
const rendered: TelegramFormattedChunk[] = [];
|
||||
while (pending.length > 0) {
|
||||
const chunk = pending.shift();
|
||||
if (!chunk) {
|
||||
continue;
|
||||
}
|
||||
const html = wrapFileReferencesInHtml(renderTelegramHtml(chunk));
|
||||
if (html.length <= normalizedLimit || chunk.text.length <= 1) {
|
||||
rendered.push({ html, text: chunk.text });
|
||||
continue;
|
||||
}
|
||||
const split = splitTelegramChunkByHtmlLimit(chunk, normalizedLimit, html.length);
|
||||
if (split.length <= 1) {
|
||||
// Worst-case safety: avoid retry loops, deliver the chunk as-is.
|
||||
rendered.push({ html, text: chunk.text });
|
||||
continue;
|
||||
}
|
||||
pending.unshift(...split);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
||||
export function markdownToTelegramChunks(
|
||||
markdown: string,
|
||||
limit: number,
|
||||
@@ -253,11 +305,7 @@ export function markdownToTelegramChunks(
|
||||
blockquotePrefix: "",
|
||||
tableMode: options.tableMode,
|
||||
});
|
||||
const chunks = chunkMarkdownIR(ir, limit);
|
||||
return chunks.map((chunk) => ({
|
||||
html: wrapFileReferencesInHtml(renderTelegramHtml(chunk)),
|
||||
text: chunk.text,
|
||||
}));
|
||||
return renderTelegramChunksWithinHtmlLimit(ir, limit);
|
||||
}
|
||||
|
||||
export function markdownToTelegramHtmlChunks(markdown: string, limit: number): string[] {
|
||||
|
||||
@@ -158,6 +158,14 @@ describe("markdownToTelegramChunks - file reference wrapping", () => {
|
||||
expect(chunks[0].html).toContain("<code>README.md</code>");
|
||||
expect(chunks[0].html).toContain("<code>backup.sh</code>");
|
||||
});
|
||||
|
||||
it("keeps rendered html chunks within the provided limit", () => {
|
||||
const input = "<".repeat(1500);
|
||||
const chunks = markdownToTelegramChunks(input, 512);
|
||||
expect(chunks.length).toBeGreaterThan(1);
|
||||
expect(chunks.map((chunk) => chunk.text).join("")).toBe(input);
|
||||
expect(chunks.every((chunk) => chunk.html.length <= 512)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("edge cases", () => {
|
||||
|
||||
Reference in New Issue
Block a user