fix(discord): default non-finite chunk limits

This commit is contained in:
Peter Steinberger
2026-05-29 00:51:17 -04:00
parent 59cec74d89
commit 3c5f5efc8c
2 changed files with 34 additions and 4 deletions
+25
View File
@@ -14,6 +14,18 @@ describe("chunkDiscordText", () => {
}
});
it("uses default chunk limits for non-finite options", () => {
const text = "x".repeat(2500);
const chunks = chunkDiscordText(text, {
maxChars: Number.NaN,
maxLines: Number.POSITIVE_INFINITY,
});
expect(chunks.length).toBeGreaterThan(1);
expect(chunks.every((chunk) => chunk.length <= 2000)).toBe(true);
expect(chunks.join("")).toBe(text);
});
it("keeps fenced code blocks balanced across chunks", () => {
const body = Array.from({ length: 30 }, (_, i) => `console.log(${i});`).join("\n");
const text = `Here is code:\n\n\`\`\`js\n${body}\n\`\`\`\n\nDone.`;
@@ -40,6 +52,19 @@ describe("chunkDiscordText", () => {
expect(chunks).toEqual([text]);
});
it("uses default newline chunk limits for non-finite max chars", () => {
const text = "x".repeat(2500);
const chunks = chunkDiscordTextWithMode(text, {
maxChars: Number.NaN,
maxLines: 50,
chunkMode: "newline",
});
expect(chunks.length).toBeGreaterThan(1);
expect(chunks.every((chunk) => chunk.length <= 2000)).toBe(true);
expect(chunks.join("")).toBe(text);
});
it("reserves space for closing fences when chunking", () => {
const body = "a".repeat(120);
const text = `\`\`\`txt\n${body}\n\`\`\``;
+9 -4
View File
@@ -1,3 +1,4 @@
import { resolveIntegerOption } from "openclaw/plugin-sdk/number-runtime";
import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-chunking";
type ChunkDiscordTextOpts = {
@@ -24,6 +25,10 @@ const DEFAULT_MAX_LINES = 17;
const FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
const CJK_PUNCTUATION_BREAK_AFTER_RE = /[]/u;
function resolveDiscordChunkLimit(value: unknown, fallback: number) {
return resolveIntegerOption(value, fallback, { min: 1 });
}
function countLines(text: string) {
if (!text) {
return 0;
@@ -114,7 +119,7 @@ function splitLongLine(
maxChars: number,
opts: { preserveWhitespace: boolean },
): string[] {
const limit = Math.max(1, Math.floor(maxChars));
const limit = resolveDiscordChunkLimit(maxChars, DEFAULT_MAX_CHARS);
if (line.length <= limit) {
return [line];
}
@@ -150,8 +155,8 @@ function splitLongLine(
* while keeping fenced code blocks balanced across chunks.
*/
export function chunkDiscordText(text: string, opts: ChunkDiscordTextOpts = {}): string[] {
const maxChars = Math.max(1, Math.floor(opts.maxChars ?? DEFAULT_MAX_CHARS));
const maxLines = Math.max(1, Math.floor(opts.maxLines ?? DEFAULT_MAX_LINES));
const maxChars = resolveDiscordChunkLimit(opts.maxChars, DEFAULT_MAX_CHARS);
const maxLines = resolveDiscordChunkLimit(opts.maxLines, DEFAULT_MAX_LINES);
const body = text ?? "";
if (!body) {
@@ -262,7 +267,7 @@ export function chunkDiscordTextWithMode(
}
const lineChunks = chunkMarkdownTextWithMode(
text,
Math.max(1, Math.floor(opts.maxChars ?? DEFAULT_MAX_CHARS)),
resolveDiscordChunkLimit(opts.maxChars, DEFAULT_MAX_CHARS),
"newline",
);
const chunks: string[] = [];