Skip to content

Commit 7afe307

Browse files
authored
Merge branch 'main' into policy-ingress-channel-conformance
2 parents bd63c8d + 3c5f5ef commit 7afe307

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

extensions/discord/src/chunk.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ describe("chunkDiscordText", () => {
1414
}
1515
});
1616

17+
it("uses default chunk limits for non-finite options", () => {
18+
const text = "x".repeat(2500);
19+
const chunks = chunkDiscordText(text, {
20+
maxChars: Number.NaN,
21+
maxLines: Number.POSITIVE_INFINITY,
22+
});
23+
24+
expect(chunks.length).toBeGreaterThan(1);
25+
expect(chunks.every((chunk) => chunk.length <= 2000)).toBe(true);
26+
expect(chunks.join("")).toBe(text);
27+
});
28+
1729
it("keeps fenced code blocks balanced across chunks", () => {
1830
const body = Array.from({ length: 30 }, (_, i) => `console.log(${i});`).join("\n");
1931
const text = `Here is code:\n\n\`\`\`js\n${body}\n\`\`\`\n\nDone.`;
@@ -40,6 +52,19 @@ describe("chunkDiscordText", () => {
4052
expect(chunks).toEqual([text]);
4153
});
4254

55+
it("uses default newline chunk limits for non-finite max chars", () => {
56+
const text = "x".repeat(2500);
57+
const chunks = chunkDiscordTextWithMode(text, {
58+
maxChars: Number.NaN,
59+
maxLines: 50,
60+
chunkMode: "newline",
61+
});
62+
63+
expect(chunks.length).toBeGreaterThan(1);
64+
expect(chunks.every((chunk) => chunk.length <= 2000)).toBe(true);
65+
expect(chunks.join("")).toBe(text);
66+
});
67+
4368
it("reserves space for closing fences when chunking", () => {
4469
const body = "a".repeat(120);
4570
const text = `\`\`\`txt\n${body}\n\`\`\``;

extensions/discord/src/chunk.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { resolveIntegerOption } from "openclaw/plugin-sdk/number-runtime";
12
import { chunkMarkdownTextWithMode, type ChunkMode } from "openclaw/plugin-sdk/reply-chunking";
23

34
type ChunkDiscordTextOpts = {
@@ -24,6 +25,10 @@ const DEFAULT_MAX_LINES = 17;
2425
const FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
2526
const CJK_PUNCTUATION_BREAK_AFTER_RE = /[]/u;
2627

28+
function resolveDiscordChunkLimit(value: unknown, fallback: number) {
29+
return resolveIntegerOption(value, fallback, { min: 1 });
30+
}
31+
2732
function countLines(text: string) {
2833
if (!text) {
2934
return 0;
@@ -114,7 +119,7 @@ function splitLongLine(
114119
maxChars: number,
115120
opts: { preserveWhitespace: boolean },
116121
): string[] {
117-
const limit = Math.max(1, Math.floor(maxChars));
122+
const limit = resolveDiscordChunkLimit(maxChars, DEFAULT_MAX_CHARS);
118123
if (line.length <= limit) {
119124
return [line];
120125
}
@@ -150,8 +155,8 @@ function splitLongLine(
150155
* while keeping fenced code blocks balanced across chunks.
151156
*/
152157
export function chunkDiscordText(text: string, opts: ChunkDiscordTextOpts = {}): string[] {
153-
const maxChars = Math.max(1, Math.floor(opts.maxChars ?? DEFAULT_MAX_CHARS));
154-
const maxLines = Math.max(1, Math.floor(opts.maxLines ?? DEFAULT_MAX_LINES));
158+
const maxChars = resolveDiscordChunkLimit(opts.maxChars, DEFAULT_MAX_CHARS);
159+
const maxLines = resolveDiscordChunkLimit(opts.maxLines, DEFAULT_MAX_LINES);
155160

156161
const body = text ?? "";
157162
if (!body) {
@@ -262,7 +267,7 @@ export function chunkDiscordTextWithMode(
262267
}
263268
const lineChunks = chunkMarkdownTextWithMode(
264269
text,
265-
Math.max(1, Math.floor(opts.maxChars ?? DEFAULT_MAX_CHARS)),
270+
resolveDiscordChunkLimit(opts.maxChars, DEFAULT_MAX_CHARS),
266271
"newline",
267272
);
268273
const chunks: string[] = [];

0 commit comments

Comments
 (0)