fix(browser): keep Playwright truncation UTF-16 safe#101761
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 7, 2026, 1:07 PM ET / 17:07 UTC. Summary PR surface: Source +2, Tests +63. Total +65 across 6 files. Reproducibility: yes. source-level. Current main uses raw Review metrics: none identified. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the helper-based browser truncation fix after refreshing against current main and passing the normal exact-head CI and maintainer review gates. Do we have a high-confidence way to reproduce the issue? Yes, source-level. Current main uses raw Is this the best way to solve the issue? Yes. Reusing the existing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against fa84741f93b9. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +2, Tests +63. Total +65 across 6 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
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Maintainer verification complete on exact head
No proof gaps remain for this local browser truncation change. Proceeding with the native squash-merge path. |
|
Merged via squash.
|
* fix(browser): keep Playwright truncation UTF-16 safe * fix(browser): cover Chrome MCP snapshot truncation
* fix(browser): keep Playwright truncation UTF-16 safe * fix(browser): cover Chrome MCP snapshot truncation
Summary
maxCharsroute contract.What Problem This Solves
Browser tool output can be truncated at a raw JavaScript string index. When the limit lands between the two code units of an emoji or other surrogate pair, OpenClaw can return a dangling surrogate in the browser response body or AI snapshot text.
User Impact
Users inspecting browser response bodies or page snapshots can see malformed Unicode output when content is truncated near an emoji boundary. The fix preserves the existing size limits and truncation markers while avoiding invalid UTF-16 in returned browser tool text.
truncateUtf16Safefromopenclaw/plugin-sdk/text-utility-runtime, which the browser extension already imports, so this patch stays inside the existing plugin architecture boundary.Origin / follow-up
Follows #101591, which fixed another user-visible UI truncation path by making emoji / surrogate-pair clipping UTF-16 safe.
Gap this fills: the browser Playwright response-body, Playwright AI snapshot, and Chrome MCP AI snapshot helpers still used direct
.slice(0, maxChars)/.slice(0, limit)truncation in user-visible browser tool output.Consistency: this patch reuses the existing
truncateUtf16Safehelper already used in the browser extension instead of introducing a new truncation implementation.Competition / linked PR analysis
extensions/browser/src/browser/pw-tools-core.responses.ts,extensions/browser/src/browser/pw-tools-core.snapshot.ts, andextensions/browser/src/browser/chrome-mcp.snapshot.ts; no matching open PR found.Real behavior proof
maxCharscuts through an emoji.maxChars→ browser route/type layer passes typed options into the Playwright or Chrome MCP runtime helper → helper normalizes the limit withMath.floor/ bounded option handling → runtime object reads a Playwright response, callspage.ariaSnapshot({ mode: "ai" }), or converts a Chrome MCP structured snapshot into browser AI snapshot text → helper truncates returned body/snapshot → agent/user receives browser tool output.maxCharscontract requested in review.truncateUtf16Safefromopenclaw/plugin-sdk/text-utility-runtimein both Playwright and Chrome MCP browser snapshot helpers. Provider constraints are N/A because this does not change provider-owned API contracts./media/vdb/code/ai/aispace/openclaw-worktrees/pr-101761, Node 22.22.0, local/usr/bin/google-chromeheadless CDP, local HTTP server on127.0.0.1.cd /media/vdb/code/ai/aispace/openclaw-worktrees/pr-101761 && node --import tsx /media/vdb/code/ai/aispace/openclaw-followup-101591-evidence/browser-playwright-unicode-proof.mjs > /media/vdb/code/ai/aispace/openclaw-pr-101761-evidence/after-pr-review-fix-browser-proof.json/media/vdb/code/ai/aispace/openclaw-pr-101761-evidence/after-pr-review-fix-browser-proof.jsonshowsresponseBodyViaPlaywright.bodyis"",responseBodyViaPlaywright.hasLoneSurrogateisfalse,snapshotAiViaPlaywright.hasLoneSurrogateisfalse, and both Playwright paths remaintruncated: true./media/vdb/code/ai/aispace/openclaw-pr-101761-evidence/vitest-browser-review-fix.txtshows the requested Chrome MCP snapshot regression passed with the two existing browser test files.origin/mainnow returns UTF-16-safe truncated text for Playwright response body and AI snapshot output. The Chrome MCP sibling AI snapshot test now verifies the same surrogate-boundary truncation case uses the shared safe helper.Review findings addressed
status: ⏳ waiting on author): addressed by the code/test update below and ready for a fresh review after push.chrome-mcp.snapshot.tssibling path): fixed by applyingtruncateUtf16SafeinbuildAiSnapshotFromChromeMcpSnapshot.maxCharsbranch instead of leaving the Playwright-only fix.node scripts/run-vitest.mjs extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts extensions/browser/src/browser/pw-tools-core.snapshot.test.ts extensions/browser/src/browser/chrome-mcp.snapshot.test.ts.Regression Test Plan
node scripts/run-vitest.mjs extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts extensions/browser/src/browser/pw-tools-core.snapshot.test.ts extensions/browser/src/browser/chrome-mcp.snapshot.test.ts/media/vdb/code/ai/aispace/openclaw-pr-101761-evidence/vitest-browser-review-fix.txtreports 3 test files passed and 27 tests passed.extensions/browser/src/browser/pw-tools-core.waits-next-download-saves-it.test.ts,extensions/browser/src/browser/pw-tools-core.snapshot.test.ts, andextensions/browser/src/browser/chrome-mcp.snapshot.test.ts.🙂, then verifies the returned browser output does not include the dangling half.Merge risk
merge-risk: compatibilityandmerge-risk: availabilityconsidered; neither should be required because this patch does not change limits, protocol shape, routing, process lifecycle, or external service behavior.Patch quality notes
Risk / Compatibility
Low. The response body byte cap,
maxCharsoption, truncation flag, and snapshot truncation marker behavior stay the same across Playwright and Chrome MCP snapshot output. The only behavior change is that a truncation boundary may move back by one UTF-16 code unit when it would otherwise split a surrogate pair.What was not changed
Root Cause
.slice(0, maxChars)/.slice(0, limit). That caused the runtime browser output path to split surrogate pairs when the caller's limit landed between the emoji code units.page.ariaSnapshot({ mode: "ai" }), and Chrome MCP AI snapshot conversion paths now calltruncateUtf16Safebefore returning text, they no longer emit dangling surrogate halves while preserving the existing truncation semantics.