Skip to content

Claude paste submit: inlined (non-placeholder) pastes race the accumulator — blind \r gets swallowed, no turn starts #279

Closed

Description

@Juliusolsson05

What happens

A prompt that we classify as paste-like (input.includes('\n') || input.length > CLAUDE_PASTE_THRESHOLD, threshold 100) is bracketed-pasted, after which we wait for Claude's [Pasted text #N] placeholder and send the submit \r once it appears. But Claude only renders that placeholder when a paste crosses its inline→collapse threshold, which is far higher than 100. For everything in the band — roughly 100 chars up to Claude's collapse size, plus short multi-line pastes — Claude inlines the text, no placeholder ever renders, our detector times out, and we fire a blind \r. Under load that \r races Claude's paste accumulator and is swallowed: the prompt sits in the composer, Claude looks busy, no real turn starts, and the user has to press Enter a second time.

This is the still-open tail of #90, isolated to one concrete, reproducible case.

Evidence (from the ClaudePasteDetection dev module, #101 / PR #278)

With AGENT_CODE_DEV_DEBUG=1 and the module enabled on a Claude pane:

  • Headless Snapshot Probe: \[Pasted text #\d+ → NO MATCH against a live ~2.1k-char screen. The placeholder genuinely is not on screen.
  • Submit timeline: every row's issued→detected is — (i.e. placeholder:appeared fired for zero submits), and paste-like rows land on placeholder:timeout → write:submit-cr { strategy: 'timeout-skip-timer' }. The wall-clock/blind fallback is firing on every paste, not as a rare fallback.

Root cause

  • packages/claude-code-headless/src/ClaudeCodeHeadless.ts:1258 awaitPastePlaceholder matches only /\[Pasted text #\d+/ (:1267). No placeholder ⇒ guaranteed timeout for inlined pastes.
  • src/renderer/src/workspace/tile-tree/TileLeaf/claudePaste.ts:187-196 — on timeout we send \r blind (timeout-skip-timer). The code comment at :57-65 already acknowledges this band ("pastes that DO NOT cross Claude's inline→collapse threshold … hit the timeout fallback every time") but treats the blind \r as "always safe by 500ms" — under load it is not.
  • Threshold mismatch: our paste-routing threshold (100) is unrelated to Claude's placeholder-collapse threshold, so a large band is routed to a detector that can never succeed for it.

Why our diagnostics don't catch it

We record that we sent the submit \r (write:submit-cr) and that the renderer's submit fn returned (OUTCOME:submit:returned), but nothing verifies that a turn actually started afterward. A swallowed \r is byte-identical in the journal to a successful one. The user-facing failure ("had to press Enter twice") produces no event.

Proposed fix

Stop depending on the placeholder as the sole timing signal; confirm the submit and retry the way a human does:

  1. Submit confirmation (main-side): after the submit \r, poll for turn-start evidence within a short window (~300 ms) — the composer clearing (pasted text leaves the input line), spinner/activity appearing (isWorking()), or a semantic turn_started. Whichever first.
  2. Bounded auto-retry: if not confirmed, resend \r (up to ~2×). This automates the manual "press Enter again" workaround and is robust to whatever Claude's paste-state does — placeholder or not.
  3. New diagnostic events so the glitch is finally visible: submit:confirmed / submit:retry / submit:unconfirmed, surfaced as a column in the ClaudePasteDetection timeline.
  4. (Optional, complementary) make awaitPastePlaceholder resolve on the inline case too (e.g. the bracketed-paste tail appearing in the composer), so the happy path doesn't always eat the 500 ms timeout.

This also dovetails with #90's own sketch (detect completion off an authoritative signal, not the screen regex) and #99 (semantic events alongside screen parsing).

Files

  • src/renderer/src/workspace/tile-tree/TileLeaf/claudePaste.ts (routing + submit timing)
  • packages/claude-code-headless/src/ClaudeCodeHeadless.ts (awaitPastePlaceholder → add a confirm/await-turn-start helper)
  • src/renderer/src/features/debug/devModules/ClaudePasteDetection/ (surface the confirm/retry outcome)

Refs #90, #99, #101.

Activity

  1. added a commit that references this issue on Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions