fix(integrations): propagate facade close lifecycle

SH
2mo ago
+504-39

why

Current main already recognizes browser.close() inside the Playwright-shaped worker runtime, thanks to #2769 / 544ec87f. The worker sets closeRequested, but the batch result drops that signal and the Node host never consumes it. A tool call can therefore report success without releasing the host-owned browser resources.

Cleanup must stay in the host: the Chrome extension worker should not receive Browserbase credentials or own session state. This PR establishes the shared facade contract and implements it for the core stdio host. Eve and Pi adoption are intentionally separated into stacked follow-ups so each host's ownership policy can be reviewed independently.

what changed

  • The batch envelope carries closeRequested alongside the model value/error. JSON serialization is preflighted so a circular result cannot discard a prior close request.
  • StagehandFacadeTools awaits a host lifecycle callback before returning. Execution and close failures are both preserved, and hydrated snapshots are cleared.
  • Hosts that have not adopted lifecycle cleanup remain source-compatible, but browser.close() throws a typed StagehandFacadeLifecycleError instead of silently claiming cleanup.
  • The stdio host serializes cleanup, tracks in-flight/failed release targets, retries them before replacement and during shutdown, and preserves cleanup errors.
  • Browserbase release uses the official @browserbasehq/sdk with a 10-second per-attempt timeout and two transient retries. An ambiguous failed update is verified with sessions.retrieve; only COMPLETED is accepted.
  • The canonical prompt and Eve's checked copy distinguish host-owned browser.close() from page-only page.close().
  • Current main intentionally permits unlisted noindex: true docs pages; the navigation invariant now excludes those pages instead of failing every newly based PR.

This is PR 1 of a three-PR stack:

  1. Shared facade and stdio lifecycle (this PR)
  2. Eve host lifecycle (#2793)
  3. Pi host lifecycle (#2794)

behavior before and after

StageBeforeAfter this PR
Worker callbackSets a local close flag.Returns the flag in a serializable envelope.
Shared facadeDrops the close request and returns the model result.Awaits host cleanup before returning.
Adopted hostHas no lifecycle boundary.Owns and reports cleanup through the callback.
Legacy hostCan appear to close while retaining resources.Fails explicitly until its adapter adopts lifecycle cleanup.
Stdio cleanupCan lose failed/racing cleanup ownership.Serializes cleanup and retains retryable release targets.
Browserbase fallbackHand-written, unbounded request path.Official SDK with bounded retries/timeouts and completion verification.

test plan

  • Core integration tests: 37/37
  • Docs SDK-reference/navigation tests: 27/27
  • Existing Eve tests against the compatibility boundary: 5/5
  • Existing Pi tests against the compatibility boundary: 3/3
  • Core, Eve, and Pi typechecks
  • Core build and Eve consumer build
  • Focused oxfmt and oxlint checks
  • Built-helper transport probe: two transient 500 responses produced SDK retry attempts 0/1/2 before success

The live Eve before/after and Online-Mind2Web-style evidence is reported in the stacked Eve PR, where the Eve-owned persistence and release behavior is introduced.

No changeset is included because the shared integration package and both examples are private.