fix(agents): keep compaction safeguard summary truncation UTF-16 safe#101692
fix(agents): keep compaction safeguard summary truncation UTF-16 safe#101692chengzhichao-xydt wants to merge 3 commits into
Conversation
Replace raw string slicing with truncateUtf16Safe in truncateFailureText, capCompactionSummary, formatRecentTurnsText, and formatSummaryContext so emoji and CJK surrogate pairs in compaction summaries and context are not split mid-pair at the truncation caps. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. Close as superseded: this PR is a useful partial compaction fix, but it still misses the suffix-tail UTF-16 boundary, while #101711 covers the same compaction paths plus the missing tail branch with positive proof. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Canonical path: Close this branch as superseded and land the consolidated UTF-16 bounded-text fix through #101711 after its own review cleanup. So I’m closing this here and keeping the remaining discussion on #101711. Review detailsBest possible solution: Close this branch as superseded and land the consolidated UTF-16 bounded-text fix through #101711 after its own review cleanup. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection plus a raw-slice probe show the remaining Is this the best way to solve the issue? No. Replacing prefix truncations with Security review: Security review cleared: The diff only imports an existing internal normalization helper and adds tests; I found no concrete security or supply-chain regression. AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against c8d95da14c5b. |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Use testing.capCompactionSummaryPreservingSuffix alias instead of destructuring to avoid eslint no-shadow with the upper-scope import. Co-Authored-By: Claude Opus 4.8 <[email protected]>
…existing test The earlier sed fix was too aggressive and renamed the function call in an existing test (line 462) to 'capper', which is only defined in the new test. Restore the correct function reference. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
@clawsweeper re-review |
|
🦞👀 Command router queued. I will update this comment with the next step. |
|
Superseded by #101711 which covers the same compaction UTF-16 truncation paths plus the missing suffix.slice(-maxChars) tail branch. Closing in favor of the canonical consolidated fix. |
|
Superseded by #101711, now landed as The landed compaction fix covers the proposed summary prefixes and recent/workspace sections, and improves the suffix-only fallback by using a UTF-16-safe negative-start slice so the prioritized tail stays intact without a malformed leading surrogate. Exact-head CI, focused compaction tests, full Thanks @chengzhichao-xydt for finding the compaction boundary. |
Summary
truncateFailureText,capCompactionSummary,formatRecentTurnsText, andformatSummaryContextnow preserves UTF-16 boundaries when the character cap lands between the code units of an emoji or CJK surrogate pair.truncateUtf16Safehelper from@openclaw/normalization-core/utf16-sliceinstead of raw.slice(0, N)at five truncation sites.What Problem This Solves
Compaction summaries, failure text, recent-turn text, and summary context are truncated to fit character budgets before being included in the model prompt. When those cap boundaries fall between the two UTF-16 code units of an emoji, the raw
.slice(0, N)produces a lone surrogate — a malformed string that may cause rendering issues or unexpected model behavior.Why This Change Was Made
The existing shared
truncateUtf16Safehelper already handles this boundary correctly and is used by 15+ call sites across the codebase. The five truncation sites incompaction-safeguard.tswere among the remaining raw-slice sites insrc/agents/.Evidence
capCompactionSummarytruncation boundary, emoji attruncateFailureTextboundary (tested viacapCompactionSummarywith marker budget), and emoji atcapCompactionSummaryPreservingSuffixbody truncation. All assert no lone surrogates in the output.node scripts/run-vitest.mjs run src/agents/agent-hooks/compaction-safeguard.test.ts— 100 passed (97 existing + 3 new).