fix(discord): rebalance reasoning italics

This commit is contained in:
Peter Steinberger
2026-01-12 21:57:52 +00:00
parent 256304037e
commit 21405b0dfc
3 changed files with 99 additions and 1 deletions

View File

@@ -67,4 +67,64 @@ describe("chunkDiscordText", () => {
expect(hasBalancedFences(chunk)).toBe(true);
}
});
it("keeps reasoning italics balanced across chunks", () => {
const body = Array.from({ length: 25 }, (_, i) => `${i + 1}. line`).join(
"\n",
);
const text = `Reasoning:\n_${body}_`;
const chunks = chunkDiscordText(text, { maxLines: 10, maxChars: 2000 });
expect(chunks.length).toBeGreaterThan(1);
for (const chunk of chunks) {
// Each chunk should have balanced italics markers (even count).
const count = (chunk.match(/_/g) || []).length;
expect(count % 2).toBe(0);
}
// Ensure italics reopen on subsequent chunks
expect(chunks[0]).toContain("_1. line");
// Second chunk should reopen italics at the start
expect(chunks[1].trimStart().startsWith("_")).toBe(true);
});
it("keeps reasoning italics balanced when chunks split by char limit", () => {
const longLine = "This is a very long reasoning line that forces char splits.";
const body = Array.from({ length: 5 }, () => longLine).join("\n");
const text = `Reasoning:\n_${body}_`;
const chunks = chunkDiscordText(text, { maxChars: 80, maxLines: 50 });
expect(chunks.length).toBeGreaterThan(1);
for (const chunk of chunks) {
const underscoreCount = (chunk.match(/_/g) || []).length;
expect(underscoreCount % 2).toBe(0);
}
});
it("reopens italics while preserving leading whitespace on following chunk", () => {
const body = [
"1. line",
"2. line",
"3. line",
"4. line",
"5. line",
"6. line",
"7. line",
"8. line",
"9. line",
"10. line",
" 11. indented line",
"12. line",
].join("\n");
const text = `Reasoning:\n_${body}_`;
const chunks = chunkDiscordText(text, { maxLines: 10, maxChars: 2000 });
expect(chunks.length).toBeGreaterThan(1);
const second = chunks[1];
expect(second.startsWith("_")).toBe(true);
expect(second).toContain(" 11. indented line");
});
});

View File

@@ -187,5 +187,42 @@ export function chunkDiscordText(
if (payload.trim().length) chunks.push(payload);
}
return chunks;
return rebalanceReasoningItalics(text, chunks);
}
// Keep italics intact for reasoning payloads that are wrapped once with `_…_`.
// When Discord chunking splits the message, we close italics at the end of
// each chunk and reopen at the start of the next so every chunk renders
// consistently.
function rebalanceReasoningItalics(source: string, chunks: string[]): string[] {
if (chunks.length <= 1) return chunks;
const opensWithReasoningItalics =
source.startsWith("Reasoning:\n_") && source.trimEnd().endsWith("_");
if (!opensWithReasoningItalics) return chunks;
const adjusted = [...chunks];
for (let i = 0; i < adjusted.length; i++) {
const isLast = i === adjusted.length - 1;
const current = adjusted[i];
// Ensure current chunk closes italics so Discord renders it italicized.
const needsClosing = !current.trimEnd().endsWith("_");
if (needsClosing) {
adjusted[i] = `${current}_`;
}
if (isLast) break;
// Re-open italics on the next chunk if needed.
const next = adjusted[i + 1];
const leadingWhitespaceLen = next.length - next.trimStart().length;
const leadingWhitespace = next.slice(0, leadingWhitespaceLen);
const nextBody = next.slice(leadingWhitespaceLen);
if (!nextBody.startsWith("_")) {
adjusted[i + 1] = `${leadingWhitespace}_${nextBody}`;
}
}
return adjusted;
}