From a5147d4d88f1e2db82568efe9414a41e02cd429d Mon Sep 17 00:00:00 2001 From: AaronLuo00 Date: Sun, 8 Mar 2026 18:44:22 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20address=20bot=20review=20=E2=80=94=20sur?= =?UTF-8?q?rogate-pair=20counting=20and=20CJK=20line=20splitting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use code-point length instead of UTF-16 length in estimateStringChars() so that CJK Extension B+ surrogate pairs (U+20000+) are counted as 1 character, not 2 (fixes ~25% overestimate for rare characters). - Change long-line split step from maxChars to chunking.tokens so that CJK lines are sliced into token-budget-sized segments instead of char-budget-sized segments that produce ~4x oversized chunks. - Add tests for both fixes: surrogate-pair handling and long CJK line splitting. Addresses review feedback from Greptile and Codex bots. --- packages/memory-host-sdk/src/host/internal.ts | 9 +++++++-- src/utils/cjk-chars.test.ts | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/memory-host-sdk/src/host/internal.ts b/packages/memory-host-sdk/src/host/internal.ts index 89fd0030a94..004d91d23e2 100644 --- a/packages/memory-host-sdk/src/host/internal.ts +++ b/packages/memory-host-sdk/src/host/internal.ts @@ -398,8 +398,13 @@ export function chunkMarkdown( if (line.length === 0) { segments.push(""); } else { - for (let start = 0; start < line.length; start += maxChars) { - segments.push(line.slice(start, start + maxChars)); + // Use token count (not maxChars) as the split step so that CJK lines + // – where 1 char ≈ 1 token – are sliced into budget-sized segments. + // For Latin text the token count is ≥ maxChars/4, which still produces + // segments well within the char budget after weighting. + const splitStep = Math.max(1, chunking.tokens); + for (let start = 0; start < line.length; start += splitStep) { + segments.push(line.slice(start, start + splitStep)); } } for (const segment of segments) { diff --git a/src/utils/cjk-chars.test.ts b/src/utils/cjk-chars.test.ts index 0e8327d0a7d..50fe188dd1c 100644 --- a/src/utils/cjk-chars.test.ts +++ b/src/utils/cjk-chars.test.ts @@ -81,7 +81,6 @@ describe("estimateStringChars", () => { // "你" counts as 4, emoji remains 2 => total 6 expect(estimateStringChars("你😀")).toBe(6); }); - it("yields ~1 token per CJK char when divided by CHARS_PER_TOKEN_ESTIMATE", () => { // 10 CJK chars should estimate as ~10 tokens const cjk = "这是一个测试用的句子呢";