Skip to content

fix(agent-launch): submit dsh launch prompts once its launchpad is live - #33229

Closed
wuuli wants to merge 3 commits into
stablyai:mainfrom
wuuli:wuuli/fix-dsh-startup-prompt-submit
Closed

wuuli wants to merge 3 commits into
stablyai:mainfrom
wuuli:wuuli/fix-dsh-startup-prompt-submit

Conversation

@wuuli

@wuuli wuuli commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

When Orca starts a DeepSeek Harness (dsh) agent with a task, it types the task into the agent's opening screen and presses Enter about 50 ms later. But that opening screen is still booting its session at that moment, so it ignores the Enter and keeps the text. Nothing tells Orca that, so Orca says "task handed over" and walks away; the task waits in the box until a human presses Enter.

This PR makes Orca keep pressing Enter (only Enter — never paste the task again) until the agent actually starts working, for a bounded time.

What Changed

Before: orca worktree create --agent dsh --prompt "<task>" --surface terminal (and orca agent launch --agent dsh --prompt ...) pasted the task into the dsh-tui launchpad and wrote one Enter 50 ms later. dsh-tui 0.17.0 draws its ❯ composer glyph ~1 s before its startup session is live, refuses Enter in that window with its own "still starting — press Enter to send once it is ready" notice, and keeps the draft. No DSH session, no turn, task stuck in the input box; the launch reply still said handed-to-terminal.

After: a fresh dsh launch observes for a turn start after the first Enter; while none is observed it re-sends only \r, up to a bounded budget, and stops the moment the turn starts (title working edge, hook working timestamp, or status flip), a permission dialog appears, or the pane generation/binding changes. The task is pasted exactly once.

Mechanism:

  • TuiAgentConfig.submitRetryUntilTurnStart + dsh: { intervalMs: 500, attempts: 10 } (≈5.5 s budget, 2–3 Enters on a normal boot).
  • launch-prompt-submit-retry.ts: the retry loop, the full turn-start predicate, and the per-agent policy lookup.
  • terminal-agent-prompt.ts: wires it into the composerReady (fresh launch) path after the first Enter; retry Enters count in submits and therefore in bytesWritten/the input_accepted checkpoint.
  • Every retry is preceded by cancellation/generation/binding/write-guard checks and re-validated after the async guard, using the same verifyAgentPromptSubmission lifecycle oracle the runtime already uses.
  • tui-agent-config.ts: the autohand entry was compacted to one line to stay inside the repo's 300-line oxlint cap (no behavior change).

Why

Root cause was measured, not guessed, against the installed dsh-tui 0.17.0 / dsh 0.2.1-rc.2 with a real PTY running the exact launch write (bracketed paste, then Enter 50 ms later). Single-Enter thresholds after the ❯ glyph:

Enter after ❯ Result
50 / 300 / 600 / 800 ms dropped; dsh keeps the draft
1000 / 1500 / 2500 ms submits

The existing dsh-composer-prompt signal is a paste-ready marker; there is no dsh byte-level submit-ready marker to wait for (its readiness is an in-process session open, surfaced only as UI text). A fixed sleep would either miss slow boots or delay fast ones, and re-pasting the task risks a duplicate turn. Retrying the one key dsh itself tells the user to press, and stopping on an observed turn start, is the smallest mechanism that is both adaptive and duplicate-free. submitPasteReadySignal was evaluated and has no dsh equivalent; worker dispatch/reused-pane/desktop-draft paths have different readiness handling and are intentionally out of scope (see Notes).

Linked Issue

Fixes #33227

Related: #29131 (same class — DSH input reported accepted before its composer is ready).

Visual Proof

N/A — no UI change. The behavior is a PTY timing fix; evidence is in the issue (real launch receipts plus a probe transcript).

Testing

  • New src/main/runtime/terminal/input/dsh-launch-prompt-submit.test.ts drives the real runtime writer/title parser: retries until turn start (3 Enters, 1 paste), stops at the budget, single Enter for an agent without the policy, long 40-line task pasted once, checkpoint bytes match the retry count, and no retry Enter when a cancellation or a turn start lands while the write guard is pending.
  • New launch-prompt-submit-retry.test.ts covers every turn-start evidence form (title edge, hook timestamp, status flip) and rejects redraws/already-working baselines.
  • pnpm test on the touched suites: 47 tests pass (new DSH suites + agent-prompt-submission-runtime). Related suites (launched-agent-composer-readiness, terminal-prompt-delivery-receipt, draft-paste-ready-scanner) also pass.
  • pnpm tc (typecheck), pnpm run check:code-quality:changed, oxlint and oxfmt --check pass on the changed files.
  • Real-TUI acceptance (macOS arm64, dsh-tui 0.17.0): with the shipped retry schedule, the long and short tasks each pasted once, took 3–4 Enters (the early ones refused with dsh's own "still starting" notice), started a turn, and issued no further Enter after the working title.
  • Pre-existing on origin/main: src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts has 8 failing cases on a clean base (verified by stashing this change); unrelated to this PR.
  • Platform coverage: exercised on macOS. Windows/ConPTY and SSH use the same PTY write path and \r constant, and the working-title evidence is transport-independent, but neither was run here.

AI Disclosure

Implemented by an AI coding agent (DeepSeek Harness / dsh) in an Orca worktree. An independent read-only review was run in a separate Orca Pi session using Magpie sg/codex/gpt-6-astra, reasoning high (verified from the Pi session record: provider magpie, model sg/codex/gpt-6-astra, thinking high).

Review

Independent Pi review (GPT-6-Astra, high) — read-only, three rounds:

  1. CHANGES REQUIRED — (major) the retry Enter could cross a cancellation/generation/permission change that landed while the async write guard was pending; (minor) the input_accepted checkpoint undercounted retry bytes.
  2. Both fixed (revalidation after the guard, full turn-start predicate, + submits accounting, new guard-race tests). Re-review found one remaining case: a hook-only working timestamp could land without a title edge.
  3. Fixed by applying the verifier's complete turn-start predicate (workingSequence, explicitWorkingStartedAt, status flip) plus a focused predicate test. Final verdict: APPROVE — no remaining blockers.

Reviewer notes carried into this PR: the retry budget bounds the wait (a startup slower than ~5.5 s can still leave the task in the launchpad), the launch receipt remains the honest write-level handed-to-terminal (dsh has no settlement provider, so it still does not prove execution), and the consumer paths not gated on composerReady (reused terminal, worker dispatch, renderer draft paste) do not get this policy.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Scope boundary: only the fresh terminal launch path (composerReady) applies the retry. A reused dsh terminal, orchestration worker dispatch, and the renderer's direct draft paste use their own readiness waits and are unchanged; this PR does not claim they reproduce the same failure.
  • A dsh startup that exceeds the retry budget still leaves the task in the launchpad, and the launch still reports handed-to-terminal (accurate about the write, not about execution). Extending the budget trades latency for coverage; 5.5 s covers the measured ~1 s window several times over.
  • No replay/deduplication change: the prompt is pasted once by one writer, and only the Enter key is repeated.
  • Windows/ConPTY and SSH were not exercised locally.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • 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) — pnpm tc, the touched test suites, check:code-quality:changed, and oxlint/oxfmt on changed files pass locally; full-suite pnpm lint/pnpm test/pnpm build were not run. Workflow runs are action_required pending maintainer approval for this fork PR.

Xulin Wu added 3 commits October 25, 2026 02:05
A fresh `--agent dsh --prompt` launch pasted the task into dsh-tui's
launchpad and pressed Enter 50 ms later, but the launchpad draws its `❯`
before the startup session opens: Enter in that window is refused with
"still starting — press Enter once it is ready" and the draft stays. The
launch still reported `handed-to-terminal`, so the task sat in the input
box and no turn ever started.

dsh now declares a submit-retry policy: after a fresh launch's Enter, wait
for a turn start and repeat only Enter (never the paste) until the turn
starts or the budget ends. Measured against dsh-tui 0.17.0 / dsh
0.2.1-rc.2: Enter at +50…800 ms after the glyph is dropped, +1000…1300 ms
submits, so a fixed sleep would either miss slow starts or add latency to
fast ones.

The compacted autohand entry keeps tui-agent-config.ts inside the 300-line
oxlint cap.
Review findings on the dsh submit retry:

- The guard ahead of a retry Enter is async. Re-check cancellation,
  generation, binding and activity after it returns, and stop when a turn
  already started or a dialog is up, so an obsolete request cannot type
  into the pane.
- The input-accepted checkpoint now counts every retry Enter, matching the
  final receipt's byte count.
- Tests cover a cancellation and a turn start that land while the guard is
  pending, plus the checkpoint bytes.
A hook's working timestamp can arrive without a title working edge. Apply
the verifier's full turn-start predicate after the retry guard, including
explicitWorkingStartedAt and a status flip, and cover each evidence form
plus the redraw case in a focused unit test.
@coderabbitai

coderabbitai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 989fb262-e16e-4d73-8375-b842d7425027
Commits

Reviewing files that changed from the base of the PR and between 13db649 and 50801e0.

Files selected for processing: 6
  • src/main/runtime/terminal/input/dsh-launch-prompt-submit.test.ts
  • src/main/runtime/terminal/input/launch-prompt-submit-retry.test.ts
  • src/main/runtime/terminal/input/launch-prompt-submit-retry.ts
  • src/main/runtime/terminal/input/terminal-agent-prompt.ts
  • src/shared/tui-agent-config-types.ts
  • src/shared/tui-agent-config.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

Walkthrough

The change adds a configurable retry policy for launch prompt submission and applies it to DSH. When the composer is ready but the initial submit was not sent with the paste, runtime code can retry Enter until it detects a turn start or reaches the retry limit. The prompt is not pasted again. Tests cover turn-start detection, retries, cancellation, and accepted-receipt byte counts.

Priority: Normal

Severity of issue fixed: Medium

Merge Risk: Minimal · up to 50801

The launch can still remain in the launchpad after retries are exhausted, but the receipt indicates that input was handed to the terminal, not that execution started. No established issue blocks merging.

Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Linked Issues check Warning Issue #33227 requires a fresh --agent dsh --prompt launch to start execution exactly once and not report the brief as handed over while it remains in the launchpad. The PR adds Enter-only retries, s… Change the fresh DSH launch result so it does not report handed-to-terminal when the bounded retry period ends without turn-start evidence. Add regression coverage for retry-budget exhaustion and verify the success receipt separately from…
Docstring Coverage Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 6 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: retrying DSH launch prompt submission after the launchpad becomes live.
Description check Passed The description follows the repository template and provides a clear user-facing explanation, implementation details, rationale, linked issue, testing evidence, scope limits, AI disclosure, and checkl…
Out of Scope Changes check Passed The changed files implement the linked issue's launch retry policy, turn-start detection, DSH configuration, prompt wiring, byte accounting, and regression tests. The one-line autohand formatting ch…
Full details: Description check

Explanation

The description follows the repository template and provides a clear user-facing explanation, implementation details, rationale, linked issue, testing evidence, scope limits, AI disclosure, and checklist status. It also documents that full lint, test, and build commands were not run.

Full details: Out of Scope Changes check

Explanation

The changed files implement the linked issue's launch retry policy, turn-start detection, DSH configuration, prompt wiring, byte accounting, and regression tests. The one-line autohand formatting change is a local configuration formatting adjustment required by the repository line limit and does not add unrelated behavior. No demonstrated unrelated change is present.

Full details: Linked Issues check

Explanation

Issue #33227 requires a fresh --agent dsh --prompt launch to start execution exactly once and not report the brief as handed over while it remains in the launchpad. The PR adds Enter-only retries, stops on turn-start evidence, limits retries to the configured budget, and tests one paste for short and long prompts. However, terminal-agent-prompt.ts still creates an accepted checkpoint with prompt: inputAccepted and the documented receipt remains handed-to-terminal when the retry budget ends without a turn start. The PR description confirms this case. Therefore, the launch can still report handoff while the task remains in the launchpad.

Resolution

Change the fresh DSH launch result so it does not report handed-to-terminal when the bounded retry period ends without turn-start evidence. Add regression coverage for retry-budget exhaustion and verify the success receipt separately from the write-level acceptance receipt.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@wuuli

wuuli commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

@nwparker @brennanb2025 — would you be the right reviewers for this one? It touches the dsh readiness signal you added (dsh-composer-prompt / draft-paste-ready-scanner) and the terminal launch-prompt delivery path you built, so I'd rather have your eyes than merge on local checks alone.

Short version: dsh-composer-prompt (❯) is paste-ready, not submit-ready. On dsh-tui 0.17.0 the launchpad draws it ~1 s before the startup session is live and refuses Enter in that window (its own "still starting" notice), keeping the draft, while Orca still reported handed-to-terminal. Measured single-Enter thresholds after the glyph: +50/300/600/800 ms dropped, +1000/1500/2500 ms submit. Fix: after a fresh launch's first Enter, retry only Enter (never the paste) until a turn start is observed or a bounded 5.5 s budget ends; revalidate cancellation/generation/binding/permission after the async write guard. Reused-terminal, worker-dispatch and renderer draft-paste paths are untouched.

Two asks:

  1. Workflow runs on this PR are action_required (fork PR), so CI has not started — could one of you approve the runs? Local pnpm tc, the touched suites, check:code-quality:changed, oxlint/oxfmt all pass.
  2. An independent read-only review (separate Orca Pi session, Magpie sg/codex/gpt-6-astra, high) ran three rounds and ended APPROVE; findings and the residual limits (retry budget bound, receipt still write-level handed-to-terminal, Windows/SSH not exercised) are in the PR body.

Happy to adjust the mechanism if you'd prefer this as a dsh-specific submit signal instead of a retry loop.

@nwparker

Copy link
Copy Markdown
Contributor

Thanks @wuuli! Your diagnosis (dsh refusing Enter while its session starts) landed via #33316 (credited with Co-authored-by). It reuses the shared resubmit loop from #33295 instead of a second retry mechanism, and only re-presses while the launchpad still shows the prompt, so it never presses Enter into dsh's first-run guide. Closing as superseded.

@nwparker nwparker closed this Oct 25, 2026
nwparker added a commit that referenced this pull request Oct 25, 2026
…he prompt (#33316)

DSH: Orca re-presses Enter (up to a 30s launch budget) while dsh's launchpad still visibly holds the launch prompt — dsh refuses Enter while its session is starting — and stops as soon as the prompt leaves the screen, so no Enter reaches the first-run guide. The shared draft reader recognises dsh's boxed launchpad composer. Fixes #29131, #33227. Supersedes #33229.

Co-authored-by: Xulin Wu <35489799+wuuli@users.noreply.github.com>
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.

[Bug]: dsh --prompt launch leaves the task in the launchpad (Enter arrives before the startup session is submit-ready)

2 participants