fix(remote): deliver initial prompt to interpreter-wrapped agents (aider/vibe) + surface drops#8099
fix(remote): deliver initial prompt to interpreter-wrapped agents (aider/vibe) + surface drops#8099Jinwoo-H wants to merge 2 commits into
Conversation
…agents (aider/vibe) Co-authored-by: Orca <help@stably.ai>
… is dropped Co-authored-by: Orca <help@stably.ai>
📝 WalkthroughWalkthroughInterpreter-wrapped agent processes are now treated as ready when they are non-shell foreground processes with child processes after repeated polling. Startup terminal setup now displays a notification when follow-up prompt delivery fails or draft prompt pasting times out. Tests cover wrapper detection, shell refusal, exact process matches, delivery outcomes, timeout callbacks, and updated mock expectations. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/renderer/src/lib/agent-followup-delivery.test.ts (1)
35-73: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test case for wrapper foreground without child processes.
The parameterized loop tests
python3+hasChildProcesses: true(delivers) andzsh+hasChildProcesses: false(refuses), but no case verifies thatpython3+hasChildProcesses: falseis refused. Without this, someone could remove theprocess.hasChildProcessesguard and all tests would still pass.✅ Suggested additional test case
it(`still refuses to type into a bare ${agent} shell foreground`, async () => { vi.mocked(inspectRuntimeTerminalProcess).mockResolvedValue({ foregroundProcess: 'zsh', hasChildProcesses: false }) const delivered = await sendFollowupPromptWhenAgentReady({ ptyId: 'pty-1', expectedProcess, prompt: 'ship it', settings: null }) expect(delivered).toBe(false) expect(sendRuntimePtyInputVerified).not.toHaveBeenCalled() }) + + it(`refuses to type into a ${agent} wrapper with no live child`, async () => { + // Foreground is python3 (a recognized wrapper) but no child process is + // running — the agent hasn't taken over the PTY yet, so don't write. + vi.mocked(inspectRuntimeTerminalProcess).mockResolvedValue({ + foregroundProcess: 'python3', + hasChildProcesses: false + }) + + const delivered = await sendFollowupPromptWhenAgentReady({ + ptyId: 'pty-1', + expectedProcess, + prompt: 'ship it', + settings: null + }) + + expect(delivered).toBe(false) + expect(sendRuntimePtyInputVerified).not.toHaveBeenCalled() + }) }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 057b3c66-3ab9-4753-a863-30b8ca9d2803
📒 Files selected for processing (4)
src/renderer/src/lib/agent-followup-delivery.test.tssrc/renderer/src/lib/agent-followup-delivery.tssrc/renderer/src/lib/new-workspace.test.tssrc/renderer/src/lib/new-workspace.ts
Summary
Interpreter-wrapped agents (aider, mistral-vibe — both pip console-scripts) silently dropped their initial prompt when launched via the stdin-after-start delivery path, and a dropped delivery had no user-visible surface. Two commits:
HIGH — prompt delivery (
fix(remote): deliver stdin-after-start prompt to interpreter-wrapped agents…).sendFollowupPromptWhenAgentReady→waitForAgentForegroundgated solely onisExpectedAgentProcess(foreground, expectedProcess)(exact/prefix name match). aider/mistral-vibe run aspython3 …/bin/aider, so the PTY foreground comm ispython3(orpython) — neveraider/vibe. The wait polled 30×150ms (~4.5s), returned false, and the prompt was dropped with no error. This bit both locally (when theps-table resolver can't pin the wrapped child to a single candidate) and over SSH (when the relay'sgetForegroundProcessNamefalls back to the bare interpreter name). Fix: after a few polls, also accept the foreground when it's a known agent wrapper process (node/python*, via the existingisAgentForegroundWrapperProcess), is not a shell, and the PTY has a non-shell child — the same readiness signalwaitForAgentReady(the Use-button flow) already uses. Client-side only; uses justforegroundProcess+hasChildProcesses, both already inRuntimeTerminalProcessInspection, so no relay/RPC protocol change and it works identically on local and SSH.MEDIUM — failure surface (
fix(remote): surface a toast when agent startup prompt/draft delivery is dropped).deliverAgentStartupToTerminalignoredsendFollowupPromptWhenAgentReady's boolean and passed noonTimeouttopasteDraftToAgentPtyWhenReady, so a genuine drop was silent. Wired both to the existingshowAutomationPromptNotSentToast(agent)(already a standalone, generically-named module — reused directly, not moved).Screenshots
No visual change.
Testing
pnpm typecheck(green)pnpm oxlinton all touched files (clean)agent-followup-delivery.test.ts— NEW. Pins the real config entries (aider,mistral-vibe) rather than synthetic agents. Thepython3-wrapper-with-live-child cases fail on pre-fix code (prompt dropped after full ~4.5s poll, no write) and pass post-fix; the bare-shell cases still correctly refuse to type; the already-resolved (foreground === 'aider') case keeps working.new-workspace.test.ts— added toast-on-drop tests for both the follow-up and draft branches (drop → toast; success → no toast; draftonTimeoutinvokes the toast), and updated the existing exact-matchpasteDraftassertions for the newonTimeoutarg.agent-ready-wait,agent-process-recognition,pty-shell-utilssuites alongside — 65 passed / 5 files.AI Review Report
Reviewed for: correctness of the readiness relaxation (the new branch is gated behind
attempt >= 4, requires a non-shell wrapper foreground AND a live non-shell child — identical to the existing acceptedwaitForAgentReadyheuristic, so it doesn't newly type into an arbitrary shell); SSH parity (traced the relay path:getForegroundProcessNameresolves the wrapped descendant when it can, and falls back topython3otherwise;hasChildProcessesover SSH ispgrepon the shell pid, which is true when the agent child is live — so the new signal fires on both transports); no protocol change; file-boundary compliance (did NOT touchagent-paste-draft.ts,draft-paste-ready-scanner.ts, ortui-agent-config.ts— PR #7862's territory). Cross-platform:isAgentForegroundWrapperProcessalready coversnode/python/python3; Windows foreground resolution has its own path and is unaffected; no shell/path/shortcut assumptions added.Security Audit
The follow-up path still refuses to write into a bare shell — the relaxation only accepts a recognized non-shell agent-wrapper foreground with a live child, so user/task text is not typed into an arbitrary prompt. No new input handling, command execution, path handling, auth, secrets, dependency, or IPC surface. The toast wiring only surfaces an existing best-effort UI message.
Notes
foregroundProcess,hasChildProcesses), so it works over SSH where the relay reports remotepython3.Made with Orca 🐋