docs(sandbox): add GET /api/sandbox/reconnect reference#195
Conversation
The third Session Sandboxes endpoint required for the chat loading-UX cutover. Unlike GET /api/sandbox/status (DB-only read), /reconnect runs a live runtime probe inside the sandbox to verify it is reachable. Used by the chat UI on session re-entry / tab refocus to decide whether to flip out of "loading sandbox..." or surface a "resume" affordance. Response distinguishes three operational outcomes via `status`: - `connected` — runtime probe succeeded; `expiresAt` reflects the freshly-probed expiry - `expired` — recorded runtime state is no longer reachable; UI should offer resume-from-snapshot or fresh-create - `no_sandbox` — session has never had a sandbox provisioned Refactor: extracted the inline `lifecycle` envelope previously on `SandboxStatusResponse` into a shared `SandboxLifecycle` component schema. Both `/status` and `/reconnect` now reference one source of truth, and we won't drift the field set between them. Files: - api-reference/openapi/sandbox.json: new path + ReconnectResponse + SandboxLifecycle component (status response now $refs it) - api-reference/sandbox/reconnect.mdx: frontmatter-only reference page - docs.json: nav adds reconnect under "Session Sandboxes" Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
To continue reviewing without waiting, purchase usage credits in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
* feat(sandbox): port GET /api/sandbox/reconnect from open-agents Implements the live runtime probe endpoint required for the chat loading-UX cutover on session re-entry / tab refocus. Matches the contract documented in recoupable/docs#195 (now merged on main). Unlike GET /api/sandbox/status (DB-only read), /reconnect actually runs `sandbox.exec("pwd")` inside the runtime so the UI can distinguish a truly-alive sandbox from a DB row whose sandbox no longer exists. Behavior: - 200 status="no_sandbox" when sandbox_state lacks runtime metadata (delegates to hasRuntimeSandboxState — the same gate /status uses) - 200 status="connected" with sandbox.expiresAt when the probe succeeds - 200 status="expired" when the probe throws — also clears sandbox_state on the session row and sets lifecycle_state to "hibernated" so subsequent /status reads agree with the probe - hasSnapshot derived from snapshot_url across all three outcomes - 4xx for auth (401), missing sessionId (400), forbidden (403), not-found (404) — same envelope as /status Files follow the existing api conventions established by PR #522: - app/api/sandbox/reconnect/route.ts: thin GET delegation + OPTIONS - lib/sandbox/getSandboxReconnectHandler.ts: handler logic - Reuses validateAuthContext, selectSessions, hasRuntimeSandboxState, buildLifecycle, connectSandbox, updateSession - Error envelope { status, error } matches sessions PRs TDD red -> green: - Handler tests cover auth fail, missing sessionId, 404, 403, no_sandbox, hasSnapshot derivation, connected (with expiresAt), expired (with state-clear assertion), and lifecycle envelope shape - Thin route shell test asserts delegation - Suite: 2516 -> 2526 (+10 net new tests), pnpm lint:check clean Out of scope (deferred per the gap analysis): - Transient vs unavailable error distinction. open-agents preserves runtime state on transient errors (network blip != dead sandbox). v1 treats every probe failure as expired, which is safer for the loading UX (user can retry). Worth porting once we have a real signal that this is happening in production. - Stale-state lifecycle workflow kick (open-agents' /status has it too — needs workflow infra in api). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(sandbox): extract noSandboxResponse to its own file (SRP) Per review feedback on PR #525 — pulls the inline `noSandboxResponse` helper out of `getSandboxReconnectHandler.ts` into its own file so it can be reused by future endpoints (e.g., `/snapshot` resume) and so the handler file stops carrying response-shape construction logic. The narrowed `ReconnectBody` type in the handler now only covers the two outcomes the handler actually constructs locally (`connected` / `expired`); the `no_sandbox` shape lives with its builder. TDD red -> green: 3 unit tests for the extracted helper covering 200 status, hasSnapshot derivation, and lifecycle envelope projection. Suite: 2526 -> 2529. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(sandbox): extract validateSandboxReconnectRequest + fix preview build Two changes bundled: 1) SRP per review feedback (sweetmantech) — extract the auth + sessionId-from-query + session lookup + ownership check pre-flight from `getSandboxReconnectHandler` into its own `validateSandboxReconnectRequest.ts`. Mirrors the `validateCreateSandboxBody` pattern: returns either a 4xx NextResponse describing the first failure, or `{ row, auth }` for the handler to consume. 2) Type fix for `next build` — `connectSandbox(row.sandbox_state as SandboxState)` failed to compile against `Json` (union includes primitives + arrays); cast through `unknown` first. The `hasRuntimeSandboxState` gate above ensures the runtime shape is safe at the call site, so the double cast is justified — comment added explaining why. The vitest pass alone wasn't enough to catch the type error — `next build` runs a separate `tsc` step that the test runner skips. Caught by the Vercel preview build failing on the previous commit. TDD red -> green: - 5 unit tests for the new validator covering auth fail (passes through), missing sessionId (400), session not found (404), ownership mismatch (403), and happy-path return shape ({row, auth}) - Existing handler tests pass unchanged — the module-level mocks for validateAuthContext / selectSessions still intercept the calls now that they're behind the new validator - Suite: 2529 -> 2534, pnpm lint:check clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pulls in three commits from main: - Sandbox API: GET /api/sandbox/reconnect added (PR #195) — wired into our Sessions group alongside sandbox/create + sandbox/status - Sandbox API: POST /api/sandbox request schema dropped branch + isNewBranch (PR #194) — auto-merged - Music-video workflow: substantive content updates (PR #193) — async pipeline section, sandbox file fetch path, resolution. Took main's version verbatim then re-applied this PR's prose sweep (no em-dashes, no 'recipe' synonym for 'workflow').
Summary
Adds the OpenAPI spec and reference page for
GET /api/sandbox/reconnect— the third Session Sandboxes endpoint required for the chat loading-UX cutover. Sequel to:/api/sandbox+ GET/api/sandbox/status, merged)branch/isNewBranchfrom POST request, merged)The matching api PR will follow once this lands.
Why now
Per the gap analysis on the open-agents → api cutover: `/reconnect` is the missing endpoint that drives the loading-state UX on session re-entry (user closes tab, comes back). Unlike `GET /api/sandbox/status` which is a DB-only read, `/reconnect` runs a live runtime probe inside the sandbox (`sandbox.exec("pwd")`) so the UI can distinguish:
Without this endpoint, returning to a hibernated session leaves the UI stuck in a polling loop.
Response shape
{ \"status\": \"connected\" | \"expired\" | \"no_sandbox\", \"hasSnapshot\": boolean, \"expiresAt\": number, // present only when status=\"connected\" \"lifecycle\": { /* SandboxLifecycle */ } }statusdistinguishes three operational outcomes (errors come back as 4xx with{status, error}):connectedexpiresAtreflects the freshly-probed expiry, which may differ fromlifecycle.sandboxExpiresAtif the sandbox extended itself between writes.expiredhasSnapshotis true, otherwise fresh-create.no_sandboxRefactor included
The inline
lifecycleenvelope previously onSandboxStatusResponseis extracted into a sharedSandboxLifecyclecomponent schema. Both/statusand/reconnectnow$refthe same definition, so the field set can't drift between them. Previously inline; now one source of truth.File layout
api-reference/openapi/sandbox.json/api/sandbox/reconnectpath; +ReconnectResponseschema; +SandboxLifecyclecomponent (status response refactored to$ref)api-reference/sandbox/reconnect.mdxdocs.jsonNet diff: +156 / -47 lines.
Test plan
sessionIdquery param + 200 / 400 / 401 / 403 / 404 responses$refextraction (regression check)What follows
After this lands:
🤖 Generated with Claude Code
Summary by cubic
Adds the OpenAPI spec and docs page for GET
/api/sandbox/reconnectto power session re-entry by running a live sandbox probe. Also extracts a sharedSandboxLifecycleschema used by both status and reconnect responses.New Features
/api/sandbox/reconnectto the OpenAPI spec withsessionIdquery param.status(connected|expired|no_sandbox),hasSnapshot, optionalexpiresAt, andlifecycle.api-reference/sandbox/reconnect.mdx; added to Session Sandboxes nav.Refactors
SandboxLifecyclecomponent schema./api/sandbox/statusto$refSandboxLifecycleto keep fields consistent.Written for commit c41992f. Summary will update on new commits.