fix(agents): keep tool-result truncation UTF-16 safe#102087
Conversation
Replace raw .slice() calls in tool-result truncation with UTF-16-safe helpers (sliceUtf16Safe/truncateUtf16Safe) so surrogate pairs are not split when capping tool output, error-tail detection, or aggregate elision markers. - hasImportantTail: sliceUtf16Safe(text, -2000) - appendBoundedTruncationSuffix: truncateUtf16Safe + sliceUtf16Safe - truncateToolResultText head/tail/default paths: sliceUtf16Safe - formatAggregateElisionText fallback: truncateUtf16Safe Added regression tests for emoji at char and head+tail boundaries. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
Codex review: needs maintainer review before merge. Reviewed July 8, 2026, 11:40 PM ET / 03:40 UTC. Summary PR surface: Source +3, Tests +26. Total +29 across 2 files. Reproducibility: yes. source-reproducible: current main slices tool-result strings by UTF-16 code units at the affected truncation boundaries, so an emoji crossing those indices can leave a dangling surrogate. The PR body also includes after-fix terminal output for the changed functions and focused Vitest coverage. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Merge the narrow agent formatting fix after ordinary maintainer review and exact-head required checks; keep broader UTF-16 hardening in separate focused PRs. Do we have a high-confidence way to reproduce the issue? Yes, source-reproducible: current main slices tool-result strings by UTF-16 code units at the affected truncation boundaries, so an emoji crossing those indices can leave a dangling surrogate. The PR body also includes after-fix terminal output for the changed functions and focused Vitest coverage. Is this the best way to solve the issue? Yes: using the existing shared UTF-16 helpers at the exact tool-result truncation boundary is the narrowest maintainable fix. The aggregate marker fallback remaining on raw AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 003bb8284bea. Label changesLabel justifications:
Evidence reviewedPR surface: Source +3, Tests +26. Total +29 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (1 earlier review cycle)
|
|
@vincentkoc this is a narrow agent-runtime formatting fix: tool-result truncation was using raw |
|
Land-ready review complete on exact head
No remaining findings or proof gaps. |
|
Merged via squash.
|
* fix(agents): keep tool-result truncation UTF-16 safe Replace raw .slice() calls in tool-result truncation with UTF-16-safe helpers (sliceUtf16Safe/truncateUtf16Safe) so surrogate pairs are not split when capping tool output, error-tail detection, or aggregate elision markers. - hasImportantTail: sliceUtf16Safe(text, -2000) - appendBoundedTruncationSuffix: truncateUtf16Safe + sliceUtf16Safe - truncateToolResultText head/tail/default paths: sliceUtf16Safe - formatAggregateElisionText fallback: truncateUtf16Safe Added regression tests for emoji at char and head+tail boundaries. Co-Authored-By: Claude Opus 4.8 <[email protected]> * test(agents): cover exact tool-result UTF-16 cuts --------- Co-authored-by: chengzhichao-xydt <[email protected]> Co-authored-by: Claude Opus 4.8 <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
* fix(agents): keep tool-result truncation UTF-16 safe Replace raw .slice() calls in tool-result truncation with UTF-16-safe helpers (sliceUtf16Safe/truncateUtf16Safe) so surrogate pairs are not split when capping tool output, error-tail detection, or aggregate elision markers. - hasImportantTail: sliceUtf16Safe(text, -2000) - appendBoundedTruncationSuffix: truncateUtf16Safe + sliceUtf16Safe - truncateToolResultText head/tail/default paths: sliceUtf16Safe - formatAggregateElisionText fallback: truncateUtf16Safe Added regression tests for emoji at char and head+tail boundaries. Co-Authored-By: Claude Opus 4.8 <[email protected]> * test(agents): cover exact tool-result UTF-16 cuts --------- Co-authored-by: chengzhichao-xydt <[email protected]> Co-authored-by: Claude Opus 4.8 <[email protected]> Co-authored-by: Peter Steinberger <[email protected]> (cherry picked from commit 9e75ce9)
Summary
@openclaw/normalization-core/utf16-slicehelpers (sliceUtf16Safe/truncateUtf16Safe) instead of raw string slicing.Linked context
Real behavior proof (required for external PRs)
node --import tsxdirectly drives the exported truncation functions and checks for lone surrogates; plusnode scripts/run-vitest.mjs src/agents/embedded-agent-runner/tool-result-truncation.test.ts.Tests and validation
node scripts/run-vitest.mjs src/agents/embedded-agent-runner/tool-result-truncation.test.tsRisk checklist
Did user-visible behavior change? (
Yes/No)Yes. Malformed truncated tool output is now avoided while preserving existing caps and truncation markers.
Did config, environment, or migration behavior change? (
Yes/No)No.
Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)No.
What is the highest-risk area?
agent tool-result formatting.
How is that risk mitigated?
The patch is limited to the existing truncation boundaries and is covered by focused regression proof above.
Current review state
What is the next action?
ClawSweeper re-review and maintainer review after this proof/body refresh.
What is still waiting on author, maintainer, CI, or external proof?
Nothing is waiting on the author after this proof update; waiting on CI/ClawSweeper/maintainer review.
Which bot or reviewer comments were addressed?
N/A — new PR.