Skip to content

feat(acp): a managed runtime installs only when asked, with progress and cancel - #29023

Merged
brennanb2025 merged 12 commits into
mainfrom
brennanb2025/agy-chat-I1-runtime-install
Oct 17, 2026
Merged

brennanb2025 merged 12 commits into
mainfrom
brennanb2025/agy-chat-I1-runtime-install

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​151 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​150
Prod 11 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​572 $\color{#cf222e}{\Huge{\mathbf{−}}}$​22 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​550

ELI5

Antigravity's chat needs a separate program, its chat server, which Orca downloads for it. When chats fetched that program on their own, the first chat sat on "Working for Ns" for about 18 seconds with no progress and no way to cancel, and opening several chats started several downloads. This stack changes that: nothing downloads until the person clicks Install, with progress and Cancel in Settings and in the chat.

#28460 stopped chat starts from downloading. This PR adds the installer the Install button will drive: one per agent per host, it downloads, checks and puts the program in place only when asked, reports progress, and can be cancelled. Nothing calls it yet (#29024 lets clients reach it), so nothing changes for anyone when this merges alone.

What Changed

This revision (moving the installer to the common pattern; each item is problem, then what changes):

  • The download was stored twice. The app's network stack also kept the 111 MB archive in its HTTP cache for up to a day, so Remove didn't free that space and a reinstall could finish with no network. Runtime downloads now skip the HTTP cache (cache: 'no-store'), so the verified copy is the only one.

  • A refused proxy was blamed on the release. QA ran Install behind a proxy that refused connections, and the row said "The Antigravity download didn't match the release Orca expects…". The wording picked that sentence for any error the retry logic doesn't treat as temporary. Now only a proven mismatch (a missing file, an oversized download or a different checksum) gives that sentence; every other failure says "Couldn't download Antigravity. Check your network connection or proxy, then try again.", as the common pattern keeps its mismatch wording to the size and checksum check.

  • A Linux host without unzip could not install at all. Minimal servers and containers often lack it, and the row could only say "needs unzip". Install now unpacks the zip itself, in-process, with fflate (a small zip library with no dependencies of its own, now bundled into the app's main process). Only the pinned files are written, each at most its pinned size and exactly that size at the end; any other entry fails the install. The unzip check before downloading and the missingProgram status field are gone. The Node runtime download keeps its existing extractor.

  • "Installed" could show for a copy this host can't run (an older system library, a data folder that forbids running programs, the wrong processor type). The file checksums prove the bytes, not that the host can run them. An agent can now provide a start check: Install starts the unpacked server once and publishes it only if it answers as the pinned release. An existing copy is checked the same way before Install reuses it. A failure reads "{agent} couldn't start on this host, so it wasn't installed. This host may not support it." and nothing is published. Antigravity's check comes in feat(acp): Antigravity in the Chat UI over its ACP server #28595.

  • Cancel published a "cancelling" state that every client flashed for about 50 ms. Cancel now answers with the outcome once the work has unwound: cancelled, or succeeded when the release was already in place. The host publishes no "cancelling" phase; the client that clicked shows "Cancelling…" itself while its call is out (feat(acp): one install row shows and drives a managed runtime install, for Settings and chat #29049).

  • A compressed download could be refused for its size. A compressed body declares its compressed size, which can exceed the pinned size. The declared size is now compared only for an uncompressed body; the unpacked bytes are still capped at the pinned size and hashed.

  • A copy whose files were whole but whose completion receipt was missing stayed "damaged" forever. Install hashed the files, reported success and changed nothing. It now rewrites the receipt.

  • Byte progress is published every 250 ms instead of once a second. Disk and PATH are re-read on a first status read and when the operation's phase changes, not for each progress update.

  • The steps that put one release on disk (reuse a whole copy, free space, download, unpack, check, start check, receipt, rename) moved unchanged into their own module, managed-runtime-release-install.ts, so the installer class keeps only its lifecycle and stays under the file-length limit.

  • Before: with chat starts no longer downloading (feat(acp): chat agents can declare a managed runtime that a start runs but never installs #28460), there was no way to get a program Orca provides onto a host.

  • After: ManagedRuntimeInstallation (one per managed agent per host) owns every change to that agent's release folder:

    • Install checks free space (archive + unpacked files + 256 MiB; skipped, with a log line, when the host can't report free space), downloads with byte progress, unpacks only the pinned files, checks every file's SHA-256, runs the agent's start check if it has one, writes the completion receipt, and moves the folder into place in one rename. Each Install downloads into a fresh temporary folder, deleted when it succeeds, fails or is cancelled; the archive is never kept or reused.
    • The rename is the commit point. A Cancel before it removes the partial download and leaves any older copy untouched; a Cancel after it reports success. A second Install while one runs joins it; one started during a cancel waits for that cleanup first.
    • Failures read plainly. A download failure that retrying can fix (network, proxy, server busy) shows "Couldn't download {agent}. Check your network connection or proxy, then try again." One retrying can't fix (a wrong size, a checksum mismatch, a missing file) shows "The {agent} download didn't match the release Orca expects, so nothing was installed. Updating Orca may fix this." The raw error goes to the log either way. A copied file that fails its checksum after unpacking shows "The {agent} download did not match its pinned checksum, so nothing was installed." A 45-minute limit, separate from Cancel, shows "Installing {agent} took longer than 45 minutes. Try again." Too little space shows "{agent} needs N MB of free disk space to install." An archive with an unexpected or short file says so in one sentence.
    • Reinstall of the version already installed re-checks its hashes and runs the start check without downloading.
    • A damaged copy is repaired by Install. Status reports damaged: true; Install downloads and checks a fresh copy, moves the damaged folder into the download's temporary folder (deleted afterwards), then puts the new copy in place.
    • Update publishes the new version beside the old one, so running chats keep theirs.
    • Old versions are removed once per installer lifetime, before any install can run, keeping the version a chat would run today (the function from feat(acp): a reclamation primitive removes all but the kept managed runtime release #28507). If any copy can't be read, the whole pass is skipped and logged, so a transient disk error can't delete a working copy. A failure is logged and never blocks an install. A copy that is definitely broken when the installer starts is removed by this pass, so after a restart the row shows plain Install; "damaged" appears only for damage found while Orca is running.
    • Status is one host-owned value with a revision that rises across operations. In this PR a reader can still wait, bounded, for the next revision; feat(acp): hosts install a managed runtime over RPC, and mark agents whose program Orca provides #29024 replaces that with a pushed subscription before any client reads it. A status read that can't read the installed files (a disk error other than "not there") fails instead of answering "not installed", so each client keeps its last answer rather than swapping an open chat's message box for Install.
    • Status also says whether a start would run a copy found outside Orca (source: 'external').
  • RevisionedState: a small shared value-plus-revision primitive. It holds no lifecycle policy, so the chat sign-in flow can adopt it with its own replace-on-start rule.

  • Download and hashing gain what the installer needs: an optional per-archive size limit (set to the pinned size), a byte-progress callback, the compressed-body size rule above, and abortable hashing.

  • The shared state type already names a remove operation and a removing phase, used by feat(runtime): remove an agent's downloaded runtime only once nothing on the host can still run it #29139 (removes the downloaded program).

  • New dependency: fflate 0.8.3, used only by the managed install.

  • Merged alone: nothing calls the installer, so nothing changes for anyone.

Why

Making install a separate, person-started operation removes the silent download, the duplicate downloads and the missing progress and cancel together, because there is now exactly one owner of the release folder. Running old-version cleanup inside that same owner, instead of at chat setup, is what makes it unable to delete a version an Update is publishing. Unpacking in-process and starting the server once before publishing follow the common pattern: both move a failure the person would otherwise meet at the first chat to the Install click, where it can be reported plainly.

Linked Issue

N/A (maintainer; part of the stack that adds Antigravity to chat).

Visual Proof

N/A: no caller yet; the calls come in #29024 and the button after that.

Testing

  • I manually tested these changes locally

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

  • Whole flow on a fake agent with a fake zip download: progress appears, a second Install joins, Cancel answers cancelled once the run has unwound and leaves no temporary folder, Retry installs, and a fresh installer reads "installed, current, Orca's copy" from disk alone. Deleting the receipt then reads damaged, and Install rewrites it without downloading.

  • Cleanup vs Update: with cleanup paused, an Install does not start downloading; once cleanup runs, the older kept version and the new version both remain and the oldest is gone.

  • Repair: a truncated file reads as damaged: true, and Install puts back a whole copy.

  • Checked in QA before this revision: a fast connection finishes a 111 MB download in a few seconds. This revision's changes (in-process unpack, start check, Cancel outcome) have not been exercised in the app yet.

  • Lint and typecheck: PR CI.

Review

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.

QA, round 2 (M4Air, 10-16, build of 2efa3308959 before this revision's last fixes; Grok drove the hidden window over the Chrome DevTools Protocol only)

  • Install, Cancel, Retry and Remove all worked on the real 111 MB download. It found two problems, both fixed in this revision: a refused proxy was shown as "didn't match the release", and the download was also kept in the app's HTTP cache, so Remove didn't free that space and a reinstall could complete offline.
Failed download before the fix (wrong sentence)

QA, round 2b (M4Air, 10-16, build of d871611d303, the current stack top; Grok over the Chrome DevTools Protocol only)

  • Installing no longer grows the app's HTTP cache (85.7 MB before and after), Remove left the runtime folder empty, and a reinstall behind a refused proxy, with the cache kept, failed at once instead of finishing offline. Chat and Settings both read "Couldn't download Antigravity. Check your network connection or proxy, then try again." with "112 MB download." and Retry installation.

Failed download, chat Failed download, Settings

Notes

  • SSH / remote: the installer runs on the host that runs the agent's chats, against that host's data folder. Folder workspaces need nothing extra.
  • Windows: no managed agent has a Windows release pinned yet; the installer reports a host without a pinned release as unavailable.
  • Stack: based on main.
  • PR author: @BrennanKB5

Differences from the common pattern

  • Intended: Install on a damaged copy downloads it again and swaps it in, instead of failing until the person removes the runtime. The common pattern's own message says "Reinstall it", but its Reinstall reaches the same failure, so only Remove gets out; repair is safe here because a damaged copy is never chosen for a new launch (a chat started from that folder before it was damaged keeps its open files on macOS and Linux while the folder is replaced).
  • Intended: a download retried after a network blip counts its bytes from 0 again, because the retry starts the file over.
  • Intended: a copy whose files hash correctly but whose receipt is missing gets the receipt rewritten by Install; the common pattern has no such path and stops at "incomplete".
  • Intended: the download reuses Orca's existing downloader, so it also retries transient network failures and stops after 120 s with no bytes, within the same 45-minute limit.
  • Intended: installed facts are re-read from disk on a first read and whenever the operation's phase changes, instead of being read once at start-up and kept in memory; the common pattern's kept copy keeps saying "installed" after a file is deleted or truncated outside it.
  • Intended: older releases and leftover download folders are removed once, when the installer is created (the first install-related call on a host, usually opening Settings or a chat), keeping the release a chat start would run; each release is about 400 MB to 1 GB unpacked, and the common pattern keeps every one.
  • Intended: no "active release" pointer file. The receipt plus the pinned version name decide which release runs, so there is no second record to fall out of step.

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)

@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch 2 times, most recently from cf54393 to 0f0c56e Compare October 15, 2026 08:39
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-4-runtime-reclaim branch from e50c315 to b63c823 Compare October 15, 2026 13:33
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from 0f0c56e to c5eb8b2 Compare October 15, 2026 13:33
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-4-runtime-reclaim branch from b63c823 to fe9ee28 Compare October 15, 2026 14:24
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from c5eb8b2 to 244b415 Compare October 15, 2026 14:24
@brennanb2025
brennanb2025 marked this pull request as ready for review October 15, 2026 17:08
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from 0e53d3b to c40df19 Compare October 15, 2026 19:57
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-4-runtime-reclaim branch from fe9ee28 to 2bf27e3 Compare October 15, 2026 19:57
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from c40df19 to d2292f6 Compare October 15, 2026 21:19
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-4-runtime-reclaim branch from 2bf27e3 to ad5633d Compare October 15, 2026 21:20
@brennanb2025
brennanb2025 changed the base branch from brennanb2025/agy-chat-4-runtime-reclaim to main October 16, 2026 01:14
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 105c6455-ce35-4819-901b-ab725bd0965c
📥 Commits

Reviewing files that changed from the base of the PR and between 9509cb5 and 2457c42.

⛔ Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing: 10
  • electron.vite.config.ts
  • package.json
  • src/main/node-runtime/managed-runtime-installation.test.ts
  • src/main/node-runtime/managed-runtime-installation.ts
  • src/main/node-runtime/managed-runtime-release-install.ts
  • src/main/node-runtime/managed-runtime-release.ts
  • src/main/node-runtime/pinned-runtime-materializer.ts
  • src/main/node-runtime/pinned-zip-members.ts
  • src/main/node-runtime/runtime-archive-download.ts
  • src/shared/managed-runtime-install.ts

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

📝 Walkthrough

The changes add managed-runtime state and archive utilities, including streamed ZIP extraction and abort-aware hashing. A release installer verifies or downloads, extracts, validates, and publishes pinned releases. The installation manager reports status, tracks progress, handles cancellation, and reclaims old releases. Tests cover installation, retry, cancellation, reclamation ordering, and repair of damaged releases.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 2457c

No identified issue currently blocks merging; complete the normal build and test checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 38.10% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 19 files. (1 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
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.
Title check Passed The title clearly identifies the main change: managed runtime installation is user-triggered and supports progress and cancellation.
Description check Passed The description covers the required sections and provides detailed user impact, implementation scope, rationale, testing coverage, visual-proof rationale, compatibility notes, and checklist status. Th…
Full details: Description check

Explanation

The description covers the required sections and provides detailed user impact, implementation scope, rationale, testing coverage, visual-proof rationale, compatibility notes, and checklist status. The AI Disclosure and Review sections are empty, and local manual testing plus full test/build verification are not reported, but the description is mostly complete.

Full details: Docstring Coverage

Explanation

Docstring coverage is 38.10% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 19 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • 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.

@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: 09f80d20-f016-49a3-a804-a809eec180e4
📥 Commits

Reviewing files that changed from the base of the PR and between 48d080e and d2292f6.

📒 Files selected for processing: 16
  • src/main/acp/acp-launch-specs.ts
  • src/main/acp/acp-private-temp.ts
  • src/main/acp/acp-structured-acquire.ts
  • src/main/acp/acp-structured-adapter.test-support.ts
  • src/main/acp/acp-structured-private-temp.test.ts
  • src/main/acp/acp-structured-session-adapter-deps.ts
  • src/main/node-runtime/managed-runtime-installation.test.ts
  • src/main/node-runtime/managed-runtime-installation.ts
  • src/main/node-runtime/managed-runtime-release.test.ts
  • src/main/node-runtime/managed-runtime-release.ts
  • src/main/node-runtime/pinned-runtime-materializer.test.ts
  • src/main/node-runtime/pinned-runtime-materializer.ts
  • src/main/node-runtime/runtime-archive-download.ts
  • src/main/runtime/revisioned-state.ts
  • src/main/runtime/structured-agent-runtime-registrations.ts
  • src/shared/managed-runtime-install.ts

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

@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from d2292f6 to 0d08ee8 Compare October 16, 2026 01:33

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Require a valid receipt before committing an existing… · managed-runtime-installation.ts:167-181

src/main/node-runtime/managed-runtime-installation.ts:167-181
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Require a valid receipt before committing an existing release.

verifyMembers checks only the pinned files and permissions. A missing or invalid .install-complete.json therefore reaches run.committed = true without repair. The resolver classifies that folder as broken, so status does not report it as current and ACP launch resolution does not select it. Check the receipt before returning; otherwise continue through the repair path.

Suggested fix
       const whole = await verifyMembers(folder, pin, label, signal).then(
-        () => true,
+        () => resolveInstalledRuntimeRelease(this.root, pin).release?.current ?? false,
         (error: unknown) => {

ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9ed8685d-d658-4bcf-96e4-0f72d92850ce
📥 Commits

Reviewing files that changed from the base of the PR and between d2292f6 and 0d08ee8.

📒 Files selected for processing: 1
  • src/main/node-runtime/managed-runtime-release.ts

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

…and cancel

One installation per runtime owns every change to its releases: it reclaims old ones once, first,
then installs one at a time. An install checks free space, downloads with byte progress, extracts,
hashes each member (abortable), writes the receipt, then publishes by rename, the commit point: a
cancel after it reports success. Reinstall rehashes the pinned release without downloading. A
status read waits, bounded, for a newer revision and rereads the installed release from disk.
…ing before downloading, and reads a failed download plainly

- Install over a damaged pinned copy downloads and verifies a fresh one, then swaps the damaged
  folder into staging, so there is no dead end; status reports the damaged fact.
- A host that cannot unpack the archive (no unzip) reports it in status and refuses Install
  without downloading.
- A network failure while downloading reads "Couldn't download …"; the raw error goes to the log.
- Reclamation skips the whole pass when a release folder could not be read.
… instead of saying not installed, and extraction uses the extractor the preflight found
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from 0d08ee8 to 739531b Compare October 16, 2026 03:21
@brennanb2025
brennanb2025 force-pushed the brennanb2025/agy-chat-I1-runtime-install branch from ad5e7b4 to 9509cb5 Compare October 16, 2026 03:27
…fore publishing, and Cancel answers with the outcome

- The managed install unzips in-process (fflate, bundled into main), so a host without unzip can install; the unzip preflight and the missingProgram status field are gone. The Node runtime download keeps its own extractor.
- A runtime may provide validate(): Install starts the downloaded copy once before publishing it, and an existing copy before reusing it; a failure reads "<agent> couldn't start on this host".
- No 'cancelling' phase: Cancel resolves once the work has unwound and returns cancelled, or succeeded when it had already committed.
- Byte progress every 250 ms; status rereads disk and PATH only on a first read or a phase change.
- The declared download size is checked only for an uncompressed body.
- An existing copy whose files hash correctly but whose receipt is missing gets its receipt rewritten instead of reading as damaged forever.
… the installer

The installer class now holds only its lifecycle: the shared operation state, the one-at-a-time
queue, install, cancel, status, reclaim and progress publishing. Reusing a whole copy, the free
space check, the download, unpacking, checking each file, the start check, the receipt, the
publishing rename and the failure sentences move unchanged into managed-runtime-release-install.ts,
which gets the pin, folder, label, signal and two callbacks (progress, and the commit point right
after the rename) instead of the class. No behavior change; this keeps the installer well under
the file-length limit once Remove lands in it.
…mismatch, so a refused proxy reads as a network problem
@brennanb2025
brennanb2025 merged commit 99788a9 into main Oct 17, 2026
63 checks passed
@brennanb2025
brennanb2025 deleted the brennanb2025/agy-chat-I1-runtime-install branch October 17, 2026 00:38
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