Skip to content

[AI-30] Submit hosted-agent input as a bracketed paste - #237

Merged
alexeyzimarev merged 1 commit into
mainfrom
alexeyzimarev/ai-30-chat-pasted-text-doesnt-finish-the-input
Jul 2, 2026
Merged

alexeyzimarev merged 1 commit into
mainfrom
alexeyzimarev/ai-30-chat-pasted-text-doesnt-finish-the-input

Conversation

@alexeyzimarev

Copy link
Copy Markdown
Member

Problem (AI-30)

Follow-up input to a hosted agent (SendInput → AgentOrchestrator.HandleSendInput) was written to the PTY as raw bytes followed by a fixed 50 ms-delayed carriage return. For a large multi-line paste the CR races the still-ingesting paste and is folded into it as a literal newline instead of a submit, so the message sits in the composer until a later, isolated keystroke finishes it.

  • Codex never submits at all.
  • Claude submits only ~50% of the time (the original AI-30 report, which predates Codex support).

This is also what caused a spec-review flow's round 2 to hang for 11 minutes: the ~17 KB re-submitted spec landed in the reviewer's composer but was never submitted until a manual keystroke flushed it. (Smaller rounds/messages settle within 50 ms, so their CR submits — which is why round 3 and typed messages worked.)

Fix

Deliver the message wrapped in bracketed-paste markers (ESC[200~ … ESC[201~) so the TUI treats it as one pasted block and the trailing CR is an unambiguous submit keypress. Both hosted CLIs enable bracketed-paste mode, so the markers are consumed as delimiters (not echoed). The text/Enter split is kept so the CR lands as a distinct PTY read. As a bonus, bracketed paste also stops message content from being interpreted as slash-commands.

Validation

Reproduced and fixed against the real CLIs (codex 0.142.5, claude 2.1.198) driving each in a PTY with the exact 17 KB paste that hung the flow round:

Pattern Codex Claude
raw bytes + 50 ms + CR (before) ✗ never submits ✗ ~50%
raw + wait-for-quiet + CR ✗ never submits ✓
bracketed paste + 50 ms + CR (this PR) ✓ (3/3 runs) ✓
  • New unit test AgentOrchestratorBracketedPasteTests asserts the bracketed wire shape + separate Enter.
  • Full CLI unit suite: 2069/2069 pass.

Notes

  • Not the same as AI-1142 (fire-and-forget SendInput over a connection blip): this hang was reproduced locally with no connection involved. AI-1142's no-delivery-ack weakness is real but separate/lower priority.
  • HandleStopAgent's /exit split is left unchanged (a 5-char command, unaffected by the paste race).

🤖 Generated with Claude Code

Follow-up input to a hosted agent was written as raw bytes followed by a
50ms-delayed carriage return. For a large multi-line paste the CR races the
still-ingesting paste and is folded into it as a literal newline instead of a
submit, so the message sits in the composer until a later, isolated keystroke
finishes it. Codex never submits at all; Claude only ~50% of the time (the
original AI-30 report, which predates Codex support).

Wrap the message in bracketed-paste markers (ESC[200~ … ESC[201~) so the TUI
treats it as one pasted block and the trailing CR is an unambiguous submit
keypress. Both hosted CLIs enable bracketed-paste mode, so the markers are
consumed as delimiters (not echoed). Keep the text/Enter split so the CR lands
as a distinct PTY read.

Verified against real codex 0.142.5 and claude 2.1.198 with the 17KB paste
that hung a spec-review flow round: raw+CR fails to submit, bracketed+CR
submits on the first Enter on both harnesses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 2, 2026

Copy link
Copy Markdown

AI-30

@qodo-code-review

Copy link
Copy Markdown

Qodo is busy working

Check back in a few minutes. Qodo's code review agents are on it.

Grey Divider

@qodo-code-review

qodo-code-review Bot commented Jul 2, 2026 •

Copy link
Copy Markdown

PR Summary by Qodo

AI-30 Submit hosted-agent input as bracketed paste

🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Wrap hosted-agent PTY input in bracketed-paste markers to prevent paste/Enter race.
• Keep Enter as a separate delayed write so submission is read unambiguously.
• Add a unit test asserting the exact write sequence (paste block, then carriage return).
Diagram

graph TD
  S["SendInput cmd"] --> O["AgentOrchestrator"] -->|"bracketed paste + Enter"| P["PTY process"] --> C["Codex/Claude TUI"]
  T["Unit test"] --> O
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Wait-for-quiet before sending Enter
  • ➕ Avoids emitting terminal escape sequences into the PTY stream
  • ➕ Can improve reliability for some CLIs where timing is the only issue
  • ➖ Still fails for Codex per reported validation; not purely a timing issue
  • ➖ Adds complexity (idle detection/timeouts) and can regress latency for large inputs
2. Increase (or adaptive) fixed delay before Enter
  • ➕ Minimal code change; no protocol/escape sequence dependence
  • ➖ Brittle across machines and input sizes; still race-prone
  • ➖ Does not address Codex behavior and can slow normal interactions

Recommendation: Keep the bracketed-paste approach: it leverages a standard terminal feature already enabled by both hosted CLIs, makes multi-line submissions deterministic, and prevents pasted content from being interpreted as interactive commands. The added unit test and explicit Enter split provide a stable contract for future changes.

Files changed (2) +97 / -2

Bug fix (1) +14 / -2
AgentOrchestrator.csSendInput uses bracketed paste markers and adds test hook +14/-2

SendInput uses bracketed paste markers and adds test hook

• Wraps hosted-agent input in bracketed-paste markers (ESC[200~…ESC[201~) before writing to the PTY, then sends a separate delayed carriage return to submit reliably. Exposes a test-only entry point for driving the private send-input handler in unit tests.

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs

Tests (1) +83 / -0
AgentOrchestratorBracketedPasteTests.csAdd unit test verifying bracketed-paste wire shape and Enter split +83/-0

Add unit test verifying bracketed-paste wire shape and Enter split

• Introduces a focused test that registers a fake agent with a recording PTY and asserts two ordered writes: a single bracketed-paste block containing the message, followed by a separate "\r" submit. Adds a minimal IPtyProcess double to capture both string and byte[] writes.

test/Capacitor.Cli.Tests.Unit/AgentOrchestratorBracketedPasteTests.cs

@alexeyzimarev
alexeyzimarev merged commit 595f956 into main Jul 2, 2026
5 checks passed
@alexeyzimarev
alexeyzimarev deleted the alexeyzimarev/ai-30-chat-pasted-text-doesnt-finish-the-input branch July 2, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant