Skip to content

fix(agent-prompt): hold the ingest floor on the render-gate submit path - #18196

Open
danielamir-2k1 wants to merge 4 commits into
stablyai:mainfrom
danielamir-2k1:fix/agent-prompt-submit-floor
Open

danielamir-2k1 wants to merge 4 commits into
stablyai:mainfrom
danielamir-2k1:fix/agent-prompt-submit-floor

Conversation

@danielamir-2k1

@danielamir-2k1 danielamir-2k1 commented Sep 2, 2026 •

Copy link
Copy Markdown

ELI5

When Orca pastes a dispatch prompt into a Codex or Claude Code terminal, it waits for the terminal to say "I've redrawn" and then presses Enter. On Windows that redraw can happen before the terminal has actually finished swallowing the paste, so Enter lands mid-paste and is dropped. The prompt sits in the composer forever and Orca reports agent_prompt_stalled. This change makes Orca also wait the byte-count-based minimum it already uses on the open-loop path, so Enter is never written before the paste could possibly have been ingested.

What Changed

src/main/runtime/orca-runtime-write-terminal-agent-prompt.ts: on the render-gate branch, await Promise.all([renderGate.wait(), waitForAgentPromptDelay(getAgentPromptSubmitDelayMs(...))]) instead of the gate alone. The later of the two now governs. The non-gate branch is unchanged.

New test src/main/runtime/agent-prompt-submission-render-gate-floor.test.ts: resolves the render gate immediately and asserts no Enter is written before the ingest floor elapses, exactly one after.

Why

worker-start failed with agent_prompt_stalled at dispatch_input on Windows for both Codex and Claude Code TUIs, five attempts in a row (payloads 10,714 and 12,773 bytes). The paste reached the composer and stayed there unsubmitted; pressing Enter manually minutes later submitted it intact and the worker ran normally. So the paste landed and the Enter was swallowed.

Agents that expose a settlement signal take the renderGate branch, which awaited only the gate and skipped getAgentPromptSubmitDelayMs entirely. The open-loop branch would have waited ~670 ms for these payloads. The render gate is a readiness signal, not proof of ingest: it can resolve on a redraw that fires before the child has attached the completed bracketed paste. agent-prompt-injection.ts already documents that the submit delay is "never capped — a cap silently reintroduces the mid-paste Enter it exists to prevent"; the gate branch was an unconditional bypass of that protection.

Not addressed here (separate ticket-worthy defect): the gate's own ingest-deadline clock starts at gate construction, before the paste chunks are written, while the non-gate floor is computed after the write loop. The floor now covers it either way.

Linked Issue

Fixes #17066
Related: #16377, #16902, #17291

Visual Proof

N/A — no UI change. Behavior change is in prompt-submit timing; evidence is the test below and the live reproduction described under Testing.

Testing

  • New test fails on unfixed main at the pre-floor assertion (expect(countSubmits(writes)).toBe(0)) and passes with the fix. Re-confirmed by reverting the production hunk by hand and re-running.

  • npx vitest run on agent-prompt-submission-render-gate-floor.test.ts, agent-prompt-submission-runtime.test.ts, agent-prompt-submission-windows-submit-delay.test.ts, agent-prompt-submission-verification.test.ts: 69/69 pass.

  • tsc --noEmit -p config/tsconfig.node.json: exit 0. oxlint on the two changed files: clean.

  • Live reproduction on Windows 11 with Orca 1.4.192: agent_prompt_stalled 5/5 (3 Codex, 1 Claude Sonnet, 1 retry); every one recovered by orca terminal send --enter on the stalled terminal, which submitted the already-injected prompt intact. Built this branch (rebased on f737f349) with build:win, installed it, and dispatch acceptance is being run on it now.

  • Platforms actually tested: Windows. macOS/Linux take the same code path; the added wait is bounded by the existing platform-specific getAgentPromptSubmitDelayMs.

  • Note: orca-runtime-tests/terminal-creation-and-readiness-part-07.spec.ts fails 52/52 on pristine main on this Windows machine (selector_not_found), independent of this change.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

AI Disclosure

Root-caused and implemented with Claude Opus 5 (Claude Code); rebased onto current main, re-verified, and packaged with Claude Fable 5.1. The failing test was written and confirmed by a Claude subagent, then independently re-verified by reverting the fix by hand.

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

No security surface touched. Cross-platform: adds a bounded wait already computed per platform; no path or shortcut impact. SSH: the write path is the same; the delay is derived from the write-host platform, not the client. Mobile: N/A. Performance: adds at most the existing open-loop submit delay (~0.5–1 s for typical dispatch payloads) on the closed-loop path, only when the gate resolves earlier than the floor.

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred) — typecheck, targeted tests, oxlint and build:win pass locally; full pnpm test not run locally because of the pre-existing part-07 failure noted above.

🤖 Generated with Claude Code

worker-start failed with agent_prompt_stalled at dispatch_input on Windows for
both Codex and Claude Code TUIs, five attempts in a row. The dispatch payload
(10,714 and 12,773 bytes observed) reached the composer and stayed there
unsubmitted; pressing Enter manually minutes later submitted it and the agent
ran normally. So the paste landed and the Enter was swallowed.

Agents exposing a settlement signal take the renderGate branch, which awaited
only the gate and skipped getAgentPromptSubmitDelayMs entirely. The open-loop
branch would have waited 500 ms settle plus ceil(bytes/64) ms of ConPTY ingest
-- about 670 ms for the observed payloads. The render gate is a readiness
signal, not proof of ingest: it can resolve on a redraw that happens before the
child attaches the completed bracketed paste, so Enter is written too early,
dropped, and no working edge is ever observed.

agent-prompt-injection.ts already says the submit delay is "Never capped -- a
cap silently reintroduces the mid-paste Enter it exists to prevent". The
renderGate branch was an unconditional bypass of exactly that protection. Now
both waits run and the later one governs, so it no longer matters why the gate
resolved early.

The gate's own heuristic is not the whole story: its ingest-deadline clock
starts at gate construction, before the paste chunks are written, while the
non-gate floor is computed after the write loop completes. That asymmetry is
left as-is here; the floor now covers it either way.

Verified: new test fails on unfixed code at the pre-floor assertion and passes
after (re-confirmed by reverting the hunk by hand and re-running). Named
prompt-submission and orchestration suites 6 files / 75 tests pass;
orca-runtime.test.ts 1216 tests pass; tsc --noEmit -p config/tsconfig.node.json
exits 0.

Not yet effective in the installed app: Orca 1.4.192 must be rebuilt from this
checkout before dispatch stops stalling at runtime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsG5xmiAcEkp1vaxutcb1N
@coderabbitai

coderabbitai Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 895825b4-c8a7-4f28-a515-4e5a7f1c2953

📥 Commits

Reviewing files that changed from the base of the PR and between 02618a7 and e133793.

📒 Files selected for processing (4)
  • src/main/runtime/agent-prompt-paste-echo.test.ts
  • src/main/runtime/agent-prompt-paste-echo.ts
  • src/main/runtime/agent-prompt-submission-render-gate-floor.test.ts
  • src/main/runtime/orca-runtime-write-terminal-agent-prompt.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/runtime/agent-prompt-paste-echo.test.ts
  • src/main/runtime/agent-prompt-paste-echo.ts
  • src/main/runtime/orca-runtime-write-terminal-agent-prompt.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The agent prompt submission path now waits for render readiness, the calculated submission delay, and post-paste echo handling. New helpers derive paste probes, detect tail echoes and valid collapsed-paste placeholders, and apply platform-specific timeouts. The runtime tracks output emitted after the paste baseline. Tests cover stale and retry echoes, timeout fallback, placeholder handling, platform deadlines, and settlement-adjusted timing bounds.

Merge Risk: ⚪ Minimal · up to e1337

The render-gated submission path now waits for prompt ingestion and post-paste echo handling before sending Enter, with regression coverage for timing, stale output, retries, placeholders, and timeout behavior. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: enforcing the ingest floor on the render-gate submission path.
Description check ✅ Passed The description is complete and follows the repository template. It explains the problem, implementation, linked issue, testing, platform impact, visual proof, and checklist status. The unchecked full…
Linked Issues check ✅ Passed The changes address issue #17066 by ensuring the render-gate path waits for the byte-count-based ingest delay before sending Enter. The added post-paste echo scoping and regression tests support relia…
Out of Scope Changes check ✅ Passed The changes remain within agent-prompt submission timing and paste-echo detection. The implementation, tests, and timing adjustments directly support the linked issue and stated objectives.
Full details: Description check

Explanation

The description is complete and follows the repository template. It explains the problem, implementation, linked issue, testing, platform impact, visual proof, and checklist status. The unchecked full-suite item is explained with the pre-existing Windows failure.

Full details: Linked Issues check

Explanation

The changes address issue #17066 by ensuring the render-gate path waits for the byte-count-based ingest delay before sending Enter. The added post-paste echo scoping and regression tests support reliable prompt submission behavior.

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

Reviewed the render-gate submit timing fix and its new characterization test.

  • orca-runtime-write-terminal-agent-prompt.ts — the settlement-agent (renderGate) branch now awaits the byte-count ingest floor alongside the gate, so the later of the two governs and Enter can never overtake the paste ingest.
  • agent-prompt-submission-render-gate-floor.test.ts — mocks createAgentPromptRenderGate to resolve immediately and asserts no Enter is written before the floor, exactly one at/beyond it.

The fix is sound: Promise.all takes the later of the gate's settlement and the open-loop floor, so the floor is purely a lower bound — it adds nothing when the gate already waits past 500 ms + ingest. The test is non-vacuous (it fails on unfixed main, where the gate branch awaited only the gate) and mirrors the existing agent-prompt-submission-windows-submit-delay.test.ts conventions. Existing gate-characterization tests (real gate + large prompt, hard-cap arithmetic) still hold under the added floor because they assert >= bounds that the floor cannot shorten. No security, wire-compat, or cross-platform concerns.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

…g Enter

On Windows, Codex 0.144 consumes a bracketed paste as per-keystroke composer
redraws. For a 10-30 KB dispatch preamble that outlasts the render gate's hard
cap (CLAUDE_AGENT_PROMPT_RENDER_TIMEOUT_MS + ingest), so the gate resolved on
its timer and Enter was written while the composer was still ingesting; Codex
treated it as a newline and the prompt sat unsubmitted (agent_prompt_stalled).
Reproduced live on a warm, verified-idle Codex pane (dispatch ctx_0853813f2cd5);
a Claude Sonnet pane on the same build submitted in 24 s because its composer
collapses the paste to a placeholder almost immediately.

Time floors cannot cover a CPU-bound redraw burst, so the render-gate branch now
polls the pane's waitText until it contains the paste tail (last 24
whitespace-stripped chars) or a paste placeholder ("[Pasted text", "[Pasted
Content"), then settles 250 ms and proceeds. Capped at 20 s on win32 write
hosts and 3 s elsewhere; on timeout it falls through to today's behavior. The
open-loop branch is unchanged.

Verified: 12 new unit tests + 4 new render-gate-floor tests; the five
prompt-submission suites pass 85/85; tsc --noEmit -p config/tsconfig.node.json
exits 0; oxlint clean on changed files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MG6S695eZtECtDNakW3EUJ

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 799b3955-01a8-4b59-b8f8-c494cf06f880

📥 Commits

Reviewing files that changed from the base of the PR and between 0e5ee8b and 02618a7.

📒 Files selected for processing (5)
  • src/main/runtime/agent-prompt-paste-echo.test.ts
  • src/main/runtime/agent-prompt-paste-echo.ts
  • src/main/runtime/agent-prompt-submission-render-gate-floor.test.ts
  • src/main/runtime/agent-prompt-submission-windows-submit-delay.test.ts
  • src/main/runtime/orca-runtime-write-terminal-agent-prompt.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

The paste-echo wait can be satisfied by stale scrollback text rather than this paste's echo (see the inline comment). In the retry path this PR targets, that can let Enter overtake the still-running redraw burst again.

Reviewed changes

Since the prior Pullfrog review, this PR layered a paste-echo confirmation on top of the render-gate ingest floor.

  • agent-prompt-paste-echo.ts — new module deriving a 24-char whitespace-stripped probe from the paste tail and matching it (or a [Pasted ...] placeholder) against pane text, with win32/other timeout constants.
  • orca-runtime-write-terminal-agent-prompt.ts — the render-gate branch now polls waitText after the floor for the paste echo, settles 250 ms, then writes Enter, capped at 20 s (win32) / 3 s with fall-through on timeout.
  • Tests — new unit tests for the module plus five echo-path tests in the render-gate-floor suite; the windows-submit-delay suite updated for the added settle.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

CodeRabbit found that generic collapsed-paste placeholders could be supplied by the prompt itself. Pullfrog found that whole-scrollback matching reused prior-attempt echoes.\n\nCapture the PTY output sequence after each paste write and inspect only subscribed output that follows it; keep collapsed-placeholder recognition inside that scoped stream. Added prompt-supplied-placeholder, pre-write-scrollback, and retry-paste regressions in agent-prompt-paste-echo.test.ts and agent-prompt-submission-render-gate-floor.test.ts.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

Since the prior Pullfrog review, this PR scoped the paste-echo confirmation to terminal output emitted after the paste write and guarded the placeholder path against payload-supplied fragments.

  • orca-runtime-write-terminal-agent-prompt.ts — captured an outputSequence baseline immediately after the paste write, subscribed to terminal data to accumulate a postPasteOutput buffer limited to bytes past that baseline, and required outputSequence > baseline before accepting a tail or placeholder match.
  • agent-prompt-paste-echo.ts — split the match into isAgentPromptPasteEchoObserved (literal tail) and isAgentPromptPasteEchoPlaceholderObserved (collapse marker), and added pastePayloadContainsPlaceholderFragment to disable placeholder evidence when the payload itself supplies a fragment.
  • Tests — new cases for a probe already in scrollback before the write and for the retry path (the first attempt's echo no longer satisfies the second), plus a payload-supplied-placeholder guard; the windows-submit-delay suite updated to emit a placeholder and account for the settle.

The prior concern is resolved: the echo wait can no longer be satisfied by tail or placeholder text that pre-dates the paste write, so a retry's Enter can no longer be gated by the previous attempt's echo. The two new production functions are narrowly scoped and the added tests fail without the fix (the scrollback-probe and retry cases assert countSubmits(writes) stays at the prior count across the floor+settle window). Targeted suites pass (36/36).

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

This branch has not been deployed

No deployments
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.

orchestration dispatch --inject: revoked as agent_prompt_stalled ~7s after injection (prompt lands unsubmitted); worker lifecycle messages then rejected

2 participants