fix(native-chat): lower unframed single-line paste threshold to 512 bytes (#41280)

macOS PTYs split unframed writes into 1,022-byte reads, so UNFRAMED_AGENT_INPUT_MAX_BYTES = 1024 left a gap where single-line chat inputs could split across multiple unframed paste reads in Claude Code and other agent TUIs. Lower UNFRAMED_AGENT_INPUT_MAX_BYTES to 512 UTF-8 bytes so long single-line inputs are bracket-framed.

Fixes #32071
This commit is contained in:
Neil
2026-11-11 15:08:16 -08:00
committed by GitHub
parent 1f1158f7cb
commit af2d650c4f
2 changed files with 5 additions and 5 deletions
@@ -31,13 +31,13 @@ describe('buildNativeChatPasteBytes', () => {
expect(buildNativeChatPasteBytes('hi\x1b there')).toBe('hi␛ there')
})
it('frames single-line text over 1 KiB of UTF-8 so agents keep every read (#13332)', () => {
const atBoundary = 'é'.repeat(512)
it('frames single-line text over 512 UTF-8 bytes so agents keep every read (#13332, #32071)', () => {
const atBoundary = 'é'.repeat(256)
const overBoundary = `${atBoundary}x`
expect(buildNativeChatPasteBytes(atBoundary)).toBe(atBoundary)
expect(buildNativeChatPasteBytes(overBoundary)).toBe(`${BEGIN}${overBoundary}${END}`)
// Each ESC becomes a 3-byte ␛, so the sent length, not the typed one, decides.
expect(buildNativeChatPasteBytes('\x1b'.repeat(400))).toBe(`${BEGIN}${'␛'.repeat(400)}${END}`)
expect(buildNativeChatPasteBytes('\x1b'.repeat(200))).toBe(`${BEGIN}${'␛'.repeat(200)}${END}`)
})
})
@@ -3,8 +3,8 @@
const ESCAPE = '\u001b'
export const BRACKETED_PASTE_START = `${ESCAPE}[200~`
export const BRACKETED_PASTE_END = `${ESCAPE}[201~`
// Agents can keep only the last read of unframed input longer than this (#13332).
export const UNFRAMED_AGENT_INPUT_MAX_BYTES = 1024
// Agents can split or keep only the last read of unframed input longer than a PTY read (#13332, #32071).
export const UNFRAMED_AGENT_INPUT_MAX_BYTES = 512
// Replace embedded ESC with printable ␛ (U+241B) so pasted framing bytes cannot close the frame and execute its tail.
export function sanitizeBracketedPasteText(text: string): string {