Skip to content

Vercel sandboxes stop after every completed turn and remain falsely Ready #1827

Description

@ColeMurray

Summary

Vercel sandbox sessions stop immediately after every completed agent turn, while OpenInspect transitions the sandbox back to ready. The UI therefore reports the sandbox as available even though Vercel shows the underlying session as stopped.

This is not caused by the configured sandbox timeout. Vercel snapshots are destructive: creating a snapshot automatically shuts down the sandbox and makes it unreachable.

Reproduction

  1. Configure SANDBOX_PROVIDER=vercel with a working base or repository image.
  2. Start a session and wait for the sandbox runtime to report ready.
  3. Complete a turn successfully.
  4. Observe the sandbox in Vercel and the status shown in OpenInspect.
  5. Send a follow-up prompt.

Observed behavior

The production sequence reproduced twice:

  • The turn completed successfully.
  • About 90 ms later, OpenInspect started an execution_complete snapshot.
  • About 130-170 ms after snapshotting began, the sandbox WebSocket disconnected with code 1006 while local status was snapshotting.
  • The snapshot completed successfully about 12 seconds later.
  • OpenInspect restored and broadcast the previous status, ready, even though the Vercel session was stopped.
  • The follow-up prompt reported reason=no_sandbox and created a replacement session from the repository prebuild instead of restoring the newly created session snapshot.

No explicit stopSession request occurred at turn completion. The snapshot operation itself stopped the Vercel session.

Root cause

The provider-neutral lifecycle assumes snapshots preserve a running sandbox:

  1. Every execution_complete schedules triggerSnapshot("execution_complete") in packages/control-plane/src/session/sandbox-events/execution.handler.ts.
  2. VercelSandboxProvider.takeSnapshot() calls the Vercel session snapshot endpoint in packages/control-plane/src/sandbox/providers/vercel/provider.ts.
  3. Vercel stops the running session while creating that snapshot.
  4. SandboxLifecycleManager.triggerSnapshot() transitions ready -> snapshotting -> ready in packages/control-plane/src/sandbox/lifecycle/manager.ts.
  5. Although the Vercel snapshot response includes the resulting session.status, the adapter discards it and returns only the snapshot ID.
  6. The frontend correctly renders the persisted ready state; it never receives stopped until delayed heartbeat reconciliation marks the sandbox stale.

Existing tests encode the incompatible assumption by using a running session in the mocked Vercel snapshot response and expecting successful snapshots to restore ready.

Impact

  • The UI exposes stale terminal and preview access as if the sandbox were available.
  • Every completed turn unnecessarily terminates the Vercel compute session.
  • Follow-up prompts pay replacement startup latency.
  • Because snapshot restore selection requires stopped, stale, or failed, a follow-up can start from the repository prebuild rather than the saved session snapshot, risking loss of uncommitted filesystem changes.
  • A queued prompt can race the snapshot that stops the sandbox before queue dispatch.

Proposed remediation

Add a provider capability such as snapshotStopsSandbox or supportsLiveSnapshots and set it appropriately for Vercel. Skip routine execution_complete snapshots for providers whose snapshots stop the running session.

Continue snapshotting through the existing inactivity/termination path, which already persists stopped, clears access, and broadcasts the terminal state before taking the snapshot.

If per-turn snapshots are mandatory, snapshot success must instead transition Vercel from snapshotting to stopped, clear access, detach the bridge, and restore that snapshot on the next prompt. That alternative is accurate but intentionally stops the sandbox after every turn.

Longer term, Vercel's persistent named-sandbox resume lifecycle could be modeled explicitly. The current provider advertises supportsPersistentResume: false.

Acceptance criteria

  • Completing a turn does not stop a Vercel sandbox before the configured inactivity boundary.
  • OpenInspect never broadcasts ready for a Vercel session that snapshotting has stopped.
  • Inactivity still transitions to stopped, clears access, snapshots once, and allows the next prompt to restore the saved state.
  • A follow-up prompt preserves filesystem changes from the previous turn.
  • Provider/lifecycle tests model Vercel's destructive snapshot behavior instead of returning a running session.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions