Skip to content

feat(agent-launch): the host delivers AI buttons' first prompt across reload - #26168

Closed
brennanb2025 wants to merge 24 commits into
mainfrom
brennanb2025/host-owns-first-prompt
Closed

brennanb2025 wants to merge 24 commits into
mainfrom
brennanb2025/host-owns-first-prompt

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 17 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​918 $\color{#cf222e}{\Huge{\mathbf{−}}}$​247 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​671
Prod 28 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​553 $\color{#cf222e}{\Huge{\mathbf{−}}}$​212 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​341

This PR and #26173 must land together. #26173 preserves the two follow-ups that would otherwise be lost when the prompt survives a reload.

ELI5

Reloading the window mid-launch could lose the agent’s first prompt. The host now sends it once while the window may reload.

The earlier version also saved the first-prompt text and recovered it after an app restart. That restart guarantee is withdrawn: an interrupted paste-only launch after an app restart remains unconfirmed, with no automatic late paste, matching main. The existing quiet uncertainty surfaces remain; no new notice is added.

What Changed

The host remains the single live sender. Same-process retries join the running launch, and later replay reads the recorded result. Original terminal identity, program ownership and original pseudo-terminal guards still apply before every write. The host still checks who may launch and durably records the completed result.

The direct native foreground inspection uses the existing evidence budget. If that inspection exceeds the budget, program ownership remains unproven and the timeout authorizes no paste.

The saved first-prompt text, first-byte claims, five-minute recovery deadline, startup scans, ten-second rescans and resume-before-replay are removed. No replacement delivery or recovery mechanism is added. #26173 keeps durable Notes and Checks follow-ups, with an atomic take only after the prompt is handed over.

Why

Main does not automatically paste an interrupted first prompt after restart. The extra recovery promise added saved state and another later writer that could meet newer user activity. Removing it gives launch unification parity first and reduces that failure class. This is the step that reaches parity with main; a later simplification phase will change how prompts are delivered.

Linked Issue

Step 2 of agent-launch unification after #24934, #25430 and #25624. Stacked follow-ups: #26173; the pair must land together.

Visual Proof

Fresh live QA ran on hidden desktop windows with an isolated profile, a stand-in Codex agent that records every byte it receives, and a closed fake GitHub provider (no real agent, account or GitHub writes). The reload rows and the slow-agent check ran on #26173 at c746688, which contains this branch; restart and Checks rows ran on c6dbbe4 before the final sync with main. Between those builds and the final heads only main's own commits differ (none touch agent launch).

Window reload while the agent is still starting: the same terminal is still waiting (the agent is set to become ready after 12 seconds), nothing has been typed yet.

Original terminal still waiting after the reload

After the agent became ready: the terminal received exactly one copy of the prompt followed by the normal submit keystrokes (from the raw input record; the stand-in does not echo the prompt). A second reload added nothing.

Agent ready after the prompt was delivered once

App restart while the agent is still starting: the launch stays "unconfirmed". For four minutes after the agent became ready it received no prompt bytes and no submit, and no new notice appeared.

Empty composer after restart: no late paste

A slow agent (ready after 35 seconds): the dialog gives up after 20 seconds, the same as main for Codex, with main's existing "Your prompt wasn't sent — paste it once the agent is ready." notice, and nothing is pasted later.

Dialog re-enabled after main's 20-second budget

Testing

QA ran on this laptop with hidden windows because the remote Mac test machine was unreachable that evening. Stand-in agent and fake provider only: no real Codex or GitHub. Windows, WSL and SSH were not exercised.

Review

Fresh adversarial reviews and an independent architecture sketch checked reload ownership, admission/replay, settled receipts, original-terminal write guards and atomic follow-ups. Final readiness review and a fresh narrow review of the last settlement change are complete; no open P0 or P1 was established. Live QA and CI remain separate gates.

Agent skill upstream boundary

  • Not applicable; this change copies no upstream skill-installer implementation.

Notes

  • Intended — app restart: interrupted paste-only delivery stays unconfirmed and is never automatically retried. The earlier restart-recovery guarantee has been withdrawn.
  • Intended — follow-up take: a crash or lost response between taking and executing can lose a follow-up; another take cannot repeat the same reply.
  • Intended — compatibility: older peers keep their existing request/receipt behavior; uncertainty remains capability-qualified.
  • Intended — original terminal: writes check the launched terminal and program ownership; replacement terminals never inherit the text.
  • Temporary — route coverage: managed SSH, direct native-chat and paired web-host routes retain their existing window callbacks and reload gaps. Broader caller unification belongs to later agent-launch work.
  • Intended — readiness wait: a launch started from a desktop dialog waits for the agent as long as main's window did (20 seconds for Codex, 8 seconds by default) before reporting that the prompt was not sent; other callers keep the host's 60 seconds. Without this, a slow or blocked agent kept the dialog open three times longer than on main.
  • Intended — paste frame: the host retains its existing bracketed-frame writer; a relay frame over 2 MiB can refuse. This shrink does not change bytes or timing.

No new UI copy or status surface is added. No merge or auto-merge is enabled. Review, CI and live QA are green.

Author: @BrennanKB5

Checklist

  • Explained problem, user-facing change, mechanism and alternatives.
  • Fresh visual/live proof on the final shrink.
  • Final correctness, compatibility and readiness source review.
  • Required checks and exact-head CI.

…nd finishes it after a restart

The desktop's AI buttons started their agent through agent.launch (#25624), but the
window still pasted the prompt. A window reload or an app restart during the launch
lost the prompt with nobody to finish it.

The window now hands the prompt to agent.launch (temporary `transport: 'paste'`, kept off
the launch line as on main), and the host pastes it with the window's own readiness rule
and bytes. The launch record owes the prompt until a durable mark written just before the
first byte; a host that restarts pastes a still-owed prompt once into the surviving agent,
and never re-pastes one whose write may have begun. Follow-ups run on the host's answer.
…start may paste

Round-1 review of the host-owned first prompt:
- One signal, the host-assigned desktop caller, for every desktop-only behaviour: the
  budget-spent write, owing the prompt, and resuming it. The phone and the CLI keep main's.
- A resume writes only on a recorded W2, and refuses on a host that cannot find the agent.
- An owed prompt has its own 5-minute deadline; a terminal not found yet stays owed and is
  looked for again until then, instead of settling not-delivered.
- The budget-spent write uses main's Enter timing; marker agents get main's budget and blind
  write on the desktop; Codex gives up at its budget, as main did.
- The chat copy is seeded once the agent started; "wasn't sent" only for a definite
  not-delivered; the receipt reads composerUnobserved: false.
…llers quiet on a maybe-landed prompt

Round-2 review of the host-owned first prompt:
- The owed prompt records the PTY the launch started its agent in; a resume pastes into that
  PTY only, and another process in the pane reads as gone (not delivered).
- A failed resume looks again only while the prompt is owed and inside its deadline; a
  prompt whose write may have begun never retries.
- The chat copy is seeded on start but stamped at the click, so the chat view matches it to
  the agent's turn.
- An unconfirmed or missing receipt reports itself as already said, so no caller offers to
  send the prompt again.
…n a respawn changes

A cold restore respawns the pane's shell under the same PTY id with a new incarnation; the
resume tests now cover that case, and a runtime-level test reads the identity an owed prompt
records from a terminal the runtime really created.
…te nothing past the deadline

The restart sweep opened the record store only when the profile held a chat, so a profile that
only ever launched terminal agents never resumed its owed prompt. It now asks, read-only and
without creating the database, whether any launch record still owes one.

The deadline only stopped a resume from starting; one that waited for its agent past it could
still write after the window stopped waiting. The write's compare-and-set now refuses past the
deadline, and the prompt settles as not delivered.
…aste a write this process made unrecorded

- A plain-SSH terminal reports no foreground process, so its host is treated as one that cannot
  find the agent in front, the Windows rule: the desktop's paste writes unless a shell is proven
  there, as main's window did; a resume still refuses.
- When a live launch's write mark fails and it writes anyway, this process remembers it until the
  deadline, so a later resume in the same process settles it unconfirmed instead of pasting again.
@brennanb2025

brennanb2025 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Desktop AI buttons that open a terminal started the agent through Orca's background service while the window sent its first prompt. Reloading the window or restarting Orca during launch could lose the prompt. Notes New agent and Checks Resolve comments also depended on that window to clear notes or resolve threads, so a reload could leave them looking unsent after the prompt arrived.

PR #26168 makes the background service deliver the prompt. PR #26173 records the selected notes or review-thread follow-up with that launch and runs it once after a reload. Pending notes and threads keep their existing sending state. On macOS and Linux, restarting Orca can finish an unsent prompt within five minutes, into the same surviving terminal only. The pair must land together.

Review fixed caller isolation, bounded restart recovery, original terminal identity checks, duplicate chat copies, misleading failure notices, one-time follow-up takes, settlement notifications and pending thread holds. Live Windows QA exposed another failure: a crashed agent could leave the host typing instructions into cmd or PowerShell. The fix shares main's positive readiness decision with the host and checks the original terminal before waiting and before each write. Codex never uses the timeout fallback.

Verified on the reviewed stacked Windows build a42e12a, containing lower f175b66: the crash stand-in received zero bytes; Codex without a composer was refused and received zero bytes throughout its 15-minute lifetime; the positive idle-title case received exactly one bracketed prompt and one Enter, with no further input throughout its 15-minute lifetime. Complete input files and lifetime logs were inspected. The host follow-up check returned the matching follow-up once, then nothing on a second take. That check proves the one-time take, not the Notes or Checks reload interface. Original full screenshots were recovered and inspected; the crash case's initial terminal-stream capture gap remains disclosed.

On hidden laptop builds of the same reviewed stack and the parent-selected main comparator 7f43d9b, both actual AI Fix and Resolve with AI button launches delivered identical complete prompt bytes: one paste and one Enter, with no later input through the stand-ins' configured 15-minute lifetimes. The upper host recorded delivery and removed its owed prompt fields. Each arm's original RuntimeClient, bundled with its own esbuild, returned matching CLI launch receipts and supplied one prompt argument with zero stdin throughout that lifetime. Full original screenshots were inspected. These were isolated stand-ins, not signed-in agent sessions; the setup timings do not establish performance.

The same isolated desktop passed mid-launch reload and restart into the original terminal, an empty-history profile, and a real restart4182ms after the original five-minute deadline. Successful recovery delivered one prompt; expired recovery delivered none and cleared the owed prompt. Complete original15-minute input files and final host records were checked independently. Notes New agent remained in flight after reload, then removed only the unchanged sent note; a note edited after sending and a newly added note survived. Checks Resolve comments remained in flight, then resolved one selected thread and posted one conversation reply through an owned closed provider, leaving the unrelated thread unchanged. Both original launches delivered one prompt frame throughout their complete48-second lifetimes; a second reload caused no duplicate prompt, note removal or review mutation. Full original interface screenshots and action-specific protected-config metadata were inspected. This does not claim signed-in agent or real provider-write verification.

The timing comparison used reviewed combined build a42e12a and main baseline 7f43d9b, before the final main integration. It used three interleaved pairs for each actual AI Fix and Resolve conflicts action. Median paired time-to-prompt changes were −70 ms and +4 ms respectively; individual pairs had mixed signs and unequal observed shared-host load. All prompt-frame bytes matched, normal submit delays stayed 50–54 ms, and all 24 shared queue observations showed no active typecheck or test. This small isolated-agent sample shows no consistent slowdown and does not establish real-agent performance.

On final main-integrated lower 8caa73a and upper 0bb108d, fresh scoped node/web typechecks pass on both trees; named tests pass 203 lower and 109 upper cases. Both trees also passed all 22 required repository checks. Fresh combined source readiness review without counsel found no new proven issues; CI on both exact final heads is green: all ten Node 24 test groups per PR, static analysis, packaging, relay integration, wire compatibility and final verification checks passed; optional platform jobs were skipped.

Additional checks triggered when both PRs were marked ready passed on the same source heads: lower ready checks, upper ready checks, and the packaged Windows serve check. The first lower Windows serve-mode attempt completed every runtime assertion, then failed in an unchanged main cleanup helper reading a disappearing process-ID file. One retry of that job, including its dependencies, passed without a source change. The final main check found seventeen newer commits with no overlap with this pair’s changed files; adjacent terminal and launch contracts were checked, and both branches remain mergeable.

Accepted boundaries and deferred work:

  • Deferred P2, temporary: Windows declines prompt recovery after an app restart until Orca can prove the agent still owns the terminal. Follow-up: Windows support for resuming a launch after a restart; no ticket exists yet.
  • Temporary: managed SSH workspaces keep main's window delivery and reload gap. Phone and CLI callers keep their existing rules.
  • Temporary: native-chat and paired web-host launches, including a structured-chat refusal that falls back to its existing terminal route, keep their live callbacks and reload gap. Recording delivery/follow-ups for those routes remains later agent-launch work.
  • Intended: recovery does not retry after the mark made before the first byte. If that mark and final settlement both fail to save, restarting within the deadline can duplicate input. Restart during a paste shows no extra notice, as on main.
  • Intended: relay SSH refuses a single paste frame over 2 MiB. Normal readiness retains existing dialog checks; the positive timeout fallback adds no extra dialog check, matching main.
  • Intended: a crash between taking and executing a follow-up can lose it. Taking first avoids duplicate external replies; outstanding work has a deadline or expiry.

Final evidence: lower CI and upper CI passed on the exact final heads above. Eight full original screenshots and the precise live-tested build are in the two PR bodies. Windows PowerShell crash was not verified: driver usage quota, an unavailable fallback route and the final contact-window deadline prevented that row; this gap was accepted. The verified crash case used cmd.exe; PowerShell startup and profile behavior were not exercised. Actual SSH restart recovery, GitLab live writes, the inline-reply fallback and signed-in agent sessions have not been verified. Both PRs have been marked ready together; neither is merged or set to auto-merge.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 8, 2026 08:05
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

Launch requests can mark prompt text for paste transport. The host now evaluates readiness and terminal identity before guarded delivery, then reports whether delivery reached the terminal and whether the composer was observed. The renderer uses that receipt to update chat state and delivery callbacks. Shared readiness polling, fallback checks, process-inspection limits, and launch replay coverage also changed.


Priority: ➖ Normal

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 49.38% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 81 functions across 54 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 and concisely describes the main change: host-side delivery of the first AI-button prompt across window reloads.
Description check Passed The description is mostly complete. It includes the user impact, implementation details, rationale, linked work, visual proof, testing results, limitations, review notes, and checklist status. The AI …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.


  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR


  • Autopilot · 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.

@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: Advanced
  • Run ID: a12ed33d-ff02-4ca8-85c3-1bbb470352ae
📥 Commits

Reviewing files that changed from the base of the PR and between e4cd14d and 8caa73a.

📒 Files selected for processing (62)
  • config/scripts/vitest-sqlite-database-runtime-files.mjs
  • src/main/agent-launch/agent-launch-executor.test.ts
  • src/main/agent-launch/agent-launch-executor.ts
  • src/main/agent-launch/agent-launch-owed-prompt-resume.test.ts
  • src/main/agent-launch/agent-launch-owed-prompt-resume.ts
  • src/main/agent-launch/agent-launch-prompt-delivery.ts
  • src/main/agent-launch/agent-launch-surface-factories.ts
  • src/main/native-chat/agent-session-journal/journal-database.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-queued-mutations.ts
  • src/main/orcad/orcad-entry.ts
  • src/main/runtime/agent-launch-fallback-lifecycle.test.ts
  • src/main/runtime/agent-launch-fallback-readiness.test.ts
  • src/main/runtime/agent-launch-fallback.test-fixture.ts
  • src/main/runtime/agent-launch-owed-prompt-record.test.ts
  • src/main/runtime/agent-launch-owed-prompt-record.ts
  • src/main/runtime/agent-launch-persisted-obligations.test.ts
  • src/main/runtime/agent-launch-persisted-obligations.ts
  • src/main/runtime/agent-launch-pty-identity.test.ts
  • src/main/runtime/agent-session-operation-admission.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/launched-agent-composer-readiness.test.ts
  • src/main/runtime/launched-agent-composer-readiness.ts
  • src/main/runtime/launched-agent-exit-delivery.test.ts
  • src/main/runtime/launched-agent-host-proves-agent.test.ts
  • src/main/runtime/launched-agent-write-guard.test.ts
  • src/main/runtime/launched-agent-write-guard.ts
  • src/main/runtime/orca-runtime-activate-managed-worktree.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/orchestration/send-agent-turn-boundary.test.ts
  • src/main/runtime/rpc/methods/agent-launch-active-operations.ts
  • src/main/runtime/rpc/methods/agent-launch-desktop-caller.ts
  • src/main/runtime/rpc/methods/agent-launch-owed-prompt-host.test.ts
  • src/main/runtime/rpc/methods/agent-launch-owed-prompt-host.ts
  • src/main/runtime/rpc/methods/agent-launch-prompt-carry.test.ts
  • src/main/runtime/rpc/methods/agent-launch-replay.ts
  • src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts
  • src/main/runtime/rpc/methods/agent-launch-surfaces.ts
  • src/main/runtime/rpc/methods/agent-launch-terminal-prompt.test.ts
  • src/main/runtime/rpc/methods/agent-launch-terminal-prompt.ts
  • src/main/runtime/rpc/methods/agent-launch.test-fixture.ts
  • src/main/runtime/rpc/methods/agent-launch.ts
  • src/main/startup/main-process-ipc-bootstrap.ts
  • src/main/startup/main-process-runtime-launch.ts
  • src/relay/agent-exec-disposal.test.ts
  • src/renderer/src/components/native-chat/NativeChatComposer.tsx
  • src/renderer/src/components/native-chat/NativeChatInterruptedContinue.test.tsx
  • src/renderer/src/lib/agent-launch-caller-prompt-transport.test.ts
  • src/renderer/src/lib/agent-launch-paste-byte-parity.test.ts
  • src/renderer/src/lib/agent-launch-prompt-delivery.ts
  • src/renderer/src/lib/agent-launch-through-host.ts
  • src/renderer/src/lib/agent-paste-draft.ts
  • src/renderer/src/lib/agent-ready-wait.ts
  • src/renderer/src/lib/launch-agent-in-new-tab.ts
  • src/renderer/src/lib/launch-agent-new-tab-host-route-readiness.test.ts
  • src/renderer/src/lib/launch-agent-new-tab-host-route.test.ts
  • src/renderer/src/lib/launch-agent-new-tab-host-route.ts
  • src/renderer/src/lib/launch-agent-tab-prompt-paste.ts
  • src/shared/agent-launch-intent.ts
  • src/shared/agent-launch-prompt-receipt.test.ts
  • src/shared/agent-ready-evidence.ts
  • src/shared/agent-session-operation-ledger.ts
  • src/shared/rpc-contract/agent-launch-params.ts
💤 Files with no reviewable changes (3)
  • src/renderer/src/lib/launch-agent-in-new-tab.ts
  • src/renderer/src/lib/launch-agent-new-tab-host-route-readiness.test.ts
  • src/renderer/src/lib/launch-agent-tab-prompt-paste.ts

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

Comment on lines +19 to +26
const foreground = process?.foregroundProcess?.toLowerCase() ?? ''
if (isExpectedAgentProcess(foreground, expectedProcess)) {
return 'foreground-match'
}
// Give shell startup children three probes to settle, and never accept a foreground shell.
if (attempt >= 4 && process?.hasChildProcesses && !isShellProcess(foreground)) {
return 'child-process'
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

#!/bin/bash
# How does the runtime's inspectTerminalProcess shape a null foreground with children?
rg -nP -C8 '\binspectTerminalProcess\s*\(' src/main/runtime --type=ts -g '!**/*.test.ts'

Repository: stablyai/orca

Length of output: 9198


🏁 Script executed:

printf '%s\n' '--- inspectTerminalProcess implementation ---'
sed -n '220,285p' src/main/runtime/orca-runtime-restore-structured-agent-session-tabs-once.ts
printf '%s\n' '--- relevant types and providers ---'
rg -n -F --glob '*.ts' 'interface PtyProcessInspection|type PtyProcessInspection|PtyProcessInspection|foregroundProcess|hasChildProcesses' src/main src/shared | head -120
printf '%s\n' '--- readiness source ---'
sed -n '1,120p' src/shared/agent-ready-evidence.ts
sed -n '50,100p' src/main/runtime/orca-runtime.ts

Repository: stablyai/orca

Length of output: 7463


Require a known non-shell foreground for the child-process rule.

inspectTerminalProcess preserves a null foregroundProcess. The readiness code converts it to '', and attempt 4 can then return 'child-process' when child processes exist. This can authorize the desktop fallback without a known foreground process.

🛡️ Proposed guard
-  if (attempt >= 4 && process?.hasChildProcesses && !isShellProcess(foreground)) {
+  if (attempt >= 4 && process?.hasChildProcesses && foreground !== '' && !isShellProcess(foreground)) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const foreground = process?.foregroundProcess?.toLowerCase() ?? ''
if (isExpectedAgentProcess(foreground, expectedProcess)) {
return 'foreground-match'
}
// Give shell startup children three probes to settle, and never accept a foreground shell.
if (attempt >= 4 && process?.hasChildProcesses && !isShellProcess(foreground)) {
return 'child-process'
}
const foreground = process?.foregroundProcess?.toLowerCase() ?? ''
if (isExpectedAgentProcess(foreground, expectedProcess)) {
return 'foreground-match'
}
// Give shell startup children three probes to settle, and never accept a foreground shell.
if (attempt >= 4 && process?.hasChildProcesses && foreground !== '' && !isShellProcess(foreground)) {
return 'child-process'
}

@brennanb2025
brennanb2025 marked this pull request as draft October 8, 2026 19:52
@brennanb2025 brennanb2025 changed the title feat(agent-launch): the host delivers the AI buttons' first prompt, and finishes it after a restart feat(agent-launch): the host delivers AI buttons' first prompt across reload Oct 8, 2026
…s-first-prompt

# Conflicts:
#	src/main/runtime/rpc/methods/agent-launch.ts
…s-first-prompt

# Conflicts:
#	src/main/runtime/orchestration/send-agent-turn-boundary.test.ts
@brennanb2025
brennanb2025 marked this pull request as ready for review October 9, 2026 10:42
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Ready for review: #26168 + #26173 (land together)

The problem. Clicking an AI button (Resolve with AI, Fix with AI, Notes "New agent", Checks "Resolve comments") starts an agent and then types the first prompt once the agent is ready. If the window reloaded during that wait, the prompt could be lost; for Notes and Checks, the "clear sent notes" / "resolve the selected threads" step that should follow could also be lost or run twice, leaving notes looking unsent and threads open after the agent had actually received them.

What changes for you.

  • A window reload while an agent is starting no longer loses the first prompt: the agent receives it exactly once, in the same terminal.
  • Notes and Checks keep their "sending…" state across the reload and, once the prompt has arrived, clear only the notes you sent unchanged and resolve only the threads you picked — once.
  • After an app restart mid-launch, an interrupted prompt is reported as not confirmed and is never typed in late. This matches main; an earlier version of feat(agent-launch): the host delivers AI buttons' first prompt across reload #26168 tried to recover it automatically after restart, and that is withdrawn.
  • A slow or stuck agent makes the dialog give up after the same time as main (20 seconds for Codex), with main's existing "Your prompt wasn't sent" notice.

How. The app's host process (not the window) now sends the first prompt and records the result, so a reloaded window joins the launch already in progress instead of starting over. #26173 stores the Notes/Checks follow-up with that launch and takes it in one step after the prompt is delivered, so no second window or reload can repeat it.

Fixed in this final round.

  • Live QA showed that, on a slow or blocked agent, the dialog could stay open for up to 60 seconds (the host's own wait), against about 20 seconds on main. Desktop launches now use main's per-agent wait; other callers keep 60 seconds. A regression test fails without the fix and passes with it, and live QA confirmed the dialog gives up at 20.2 seconds.
  • Current main requires every host method to declare who may call it; feat(agent-launch): a click's follow-up survives a window reload, once #26173's new follow-up method uses the same level as the other agent-launch methods.
  • Both branches are merged with current main (import-only conflicts, both sides kept).

Deferred (P3, not fixed here). If a launch somehow stays pending past the 24-hour record retention and finishes while the window is mid-navigation, Notes/Checks can stay "sending…" until the next reload. No follow-up runs from an expired record.

Seen, but already on main (not changed here). After the "prompt wasn't sent" timeout, the dialog stays open with Start agent enabled, so a second click would start a second agent. Same code path on main.

Verified.

Not verified.

  • QA ran on this laptop (hidden windows, isolated profile) because the remote Mac test machine was unreachable; Windows, WSL and SSH were not exercised.
  • No real Codex and no real GitHub writes (stand-in and fake provider only).
  • The restart and Checks rows ran before the final merge with main; the final heads differ from that build only by main's own commits, none in agent launch.

Author: @BrennanKB5

@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

🧹 Nitpick comments (1)
src/main/runtime/rpc/methods/agent-launch-terminal-prompt.test.ts (1)

553-581: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the console spies in a finally block.

spies.forEach((spy) => spy.mockRestore()) runs only after the assertions pass. If an assertion fails, the console stays mocked. Later tests in this file then lose their log output. Use try/finally, or use afterEach(() => vi.restoreAllMocks()).


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cd90c2d5-800f-424b-b111-f19058964bfe
📥 Commits

Reviewing files that changed from the base of the PR and between 8caa73a and a297924.

📒 Files selected for processing (21)
  • src/main/agent-launch/agent-launch-executor.test.ts
  • src/main/agent-launch/agent-launch-prompt-delivery.ts
  • src/main/agent-launch/agent-launch-surface-factories.ts
  • src/main/providers/local-pty-foreground-inspection-cheap-tier.test.ts
  • src/main/providers/local-pty-provider.ts
  • src/main/runtime/agent-launch-fallback-lifecycle.test.ts
  • src/main/runtime/agent-session-operation-admission.ts
  • src/main/runtime/orca-runtime-activate-managed-worktree.ts
  • src/main/runtime/rpc/methods/agent-launch-active-operations.ts
  • src/main/runtime/rpc/methods/agent-launch-desktop-caller.ts
  • src/main/runtime/rpc/methods/agent-launch-replay.ts
  • src/main/runtime/rpc/methods/agent-launch-restart-replay.test.ts
  • src/main/runtime/rpc/methods/agent-launch-surfaces.ts
  • src/main/runtime/rpc/methods/agent-launch-terminal-prompt.test.ts
  • src/main/runtime/rpc/methods/agent-launch-terminal-prompt.ts
  • src/main/runtime/rpc/methods/agent-launch.test-fixture.ts
  • src/main/runtime/rpc/methods/agent-launch.ts
  • src/renderer/src/lib/agent-launch-through-host.ts
  • src/renderer/src/lib/launch-agent-in-new-tab.ts
  • src/shared/agent-launch-intent.ts
  • src/shared/rpc-contract/agent-launch-params.ts
💤 Files with no reviewable changes (1)
  • src/renderer/src/lib/launch-agent-in-new-tab.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/runtime/rpc/methods/agent-launch-replay.ts
  • src/main/runtime/agent-session-operation-admission.ts

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

value.outcome === 'not-delivered' ||
value.outcome === 'unconfirmed'
: value.outcome === 'handed-to-terminal'
? !('composerUnobserved' in value) || typeof value.composerUnobserved === 'boolean'

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Reject composerUnobserved: false.

The receipt type at Line 179 allows this field only as true or absent. This guard accepts false, so an invalid RPC receipt passes validation and is narrowed to a type that excludes that value. Require a present field to equal true.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Closed: the agent.launch migration is parity-only. This fixes main's reload-loses-the-prompt bug, which moves to the post-migration bug-fix work, done there by handing the prompt over at agent start instead of pasting.

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