Cut a long page's text between characters too, not only a control's name - #578
Merged
davidmckayv merged 2 commits intoSep 16, 2026
Merged
davidmckayv merged 2 commits into
davidmckayv merged 2 commits into
Conversation
CopilotKit#539 fixed this for a control's accessible name and value in a page snapshot and left the readable page text a navigation returns, which is the same bug at thirty times the length. `slice` counts UTF-16 code units, an emoji is two, and a limit landing between the halves leaves a lone high surrogate as the last thing the Bot is handed. Measured at the real limit on main: main : last unit d83d JSON tail "aaa\ud83d" UTF-8 tail efbfbd length 6000 branch : last unit 61 JSON tail "aaaa" UTF-8 tail 61 length 5999 `efbfbd` is U+FFFD, so the Bot reads a broken character that is not on the page, in text it is about to answer a question from. More likely to bite here than in a control's name, for the reason the limit is bigger. A 200-unit name rarely reaches an emoji; 6000 units of somebody's page usually passes through several, and whether the cut lands mid-character is decided by whatever happened to be above it. The rule was already written and already correct — it just was not being called. `cutAtCodeUnits` is exported rather than duplicated, and `index.ts` already imported from `aria-snapshot.ts`, so this is one word and one call. It stays declared in the parser module because that module imports no Playwright: `index.ts` does, at load, so a helper declared beside its caller could not be tested at all, which is why the caller was left out of CopilotKit#539 in the first place. `truncated` is unchanged and needs no thought: dropping one more code unit cannot make an over-limit string fit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Hotragn
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso,
mxmzb and
tylerslaton
as code owners
September 16, 2026 10:40
Merged
9 tasks
# Conflicts: # CHANGELOG.md
davidmckayv
approved these changes
Sep 16, 2026
davidmckayv
left a comment
Contributor
There was a problem hiding this comment.
Code-verified clean; CI green on this sha.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
#539 fixed the emoji-safe cut for a control's accessible name and value in a page snapshot. It left the third site — the readable page text a navigation hands back — and noted it as not covered because
agent-computer/src/index.tsimports Playwright at load, so there was no test to run against it.That site is the same bug at thirty times the length. Measured at the real limit, on
main:efbfbdis U+FFFD. So the Bot reads a broken character that is not on the page, in the text it is about to answer a question from.More likely to bite here than in a control's name, for the reason the limit is bigger. A 200-unit accessible name rarely reaches an emoji at all. 6000 units of somebody's page usually passes through several, and whether the cut lands mid-character is decided by whatever happened to be above it.
Where it runs
Boundary and audit
Untouched. A navigation is read-only, nothing acting changes, and only the text of the result differs.
Changelog
Unreleased, saying it now matches what a control's name and value already do.Proof
The fix is one word and one call, because the rule was already written and already correct — it just was not being called.
cutAtCodeUnitsbecomesexport, andindex.ts:3already imported from./aria-snapshot, so there is no new coupling:It stays declared in the parser module rather than moving beside its caller, and that is deliberate:
aria-snapshot.tsimports no Playwright,index.tsdoes at load, so a helper declared beside the caller could not be tested at all — which is exactly why this site was left out of #539.Five tests in
agent-computer/tests/aria-snapshot.test.ts, at 6000 rather than 200, pinning the rule where it is declared:Being straight about what those tests do and do not prove. They do not fail on
main, and they are not regression tests for this bug — the rule was already right, so exporting it onmainwould make them pass there too. What they pin is the rule at the limit this caller uses, including the two edges worth having: a character that ends exactly at the limit is kept whole (so the guard cannot cost a whole emoji every time), and a string ending on a low surrogate is kept (so the guard looks only for an unpaired high half). The evidence for the defect itself is the measurement above, which is the same form #539 used, becausereadablePageTextcannot be reached from a test in this package.What is not covered
readablePageTextitself still has no test, and this does not add one. ThePageit takes comes from Playwright, imported at module load. Reaching it means either a browser in CI or splitting the pure tail of that function out ofindex.ts— a structural change, and not one to smuggle into a two-line fix.grep -rn "slice(0, [A-Z_0-9]" agent-computer/srcreturns only the two Cut a long control name or value in a page snapshot between characters, not through an emoji #539 fixed and this one, and nothing else in that package cuts a string at a constant.🤖 Generated with Claude Code