Repository navigation
[docs]: sync docs-production w/ main - #3272
Merged
Merged
Conversation
## What's the issue? Browse can fail to connect to a healthy local Chrome because it trusts an old browser connection URL saved in the profile's `DevToolsActivePort` file. The existing check only confirms that something is listening on the cached port; it does not confirm that the saved browser target still exists. For example, the file points to `ws://127.0.0.1:9222/devtools/browser/old-id`, while the running Chrome exposes `/devtools/browser/new-id`. Browse selects `old-id`, and the connection fails with a 404 or connection reset. This PR checks the cached target against Chrome's live `/json/version` response. If they disagree, Browse discards the stale candidate and uses its existing live-endpoint fallback. It compares URL paths so `localhost` versus `127.0.0.1` does not invalidate a matching target, and probes each port only once per discovery call. ## When does it happen? 1. A Chrome instance leaves a `DevToolsActivePort` file behind after exiting. 2. A later browser instance uses the same debugging port, but has a different browser target ID. An old profile file can therefore point to a port now owned by another instance. 3. Browse discovers that stale file while attaching to a local browser, such as through `browse open --auto-connect` or the discovery used by `browse doctor`. The port is reachable, so the old check accepts the file even though its target is gone. A restart alone is not sufficient to trigger this: the stale file must remain visible and its port must be reused. ## Why is it important? Local browser attachment fails even though Chrome is running and its debugging endpoint works. Users and agents cannot reliably reuse that browser session, and diagnostics can select a dead endpoint. Validating the browser target prevents leftover profile state from making a working browser look broken. This is a reproduced connection-correctness bug; we have not established how frequently users encounter it. ## How was it verified? Verification on September 23, 2026, for head `b96dea6`: - **Real Chromium:** created an isolated stale profile file pointing at a live browser's port, then ran both discovery APIs before and after the fix. Main `fbcdf6169` selected the stale target and failed with 404 / connection reset. The patch selected the live target, completed both WebSocket upgrades with HTTP 101, and successfully called `Browser.getVersion` (`Chrome/153.0.8010.12`). This was a Linux Chromium smoke test; the temporary browser and profile were cleaned up. - **401 CLI tests passed across 29 files**, including six regressions covering stale and fresh caches, host spelling, fallback discovery, probe deduplication, and no live browser. - **Build and lint passed**, including formatting, ESLint, and TypeScript checks. The diff contains the discovery fix, its regression tests, and a Browse patch changeset. The PR targets `main`.
# why SDK changes must include documentation, but merging those docs into `main` should not publish unreleased APIs to the public site ## what changed - Add Mintlify previews for docs PRs targeting `main` and a persistent preview updated by docs pushes to `main`. Report the URL and wait for deployment success. - Run docs reference tests and Mintlify validation independently of SDK path filters, including on docs-only PRs and production backports. - Include Go SDK source in the docs test cache inputs. - Add explicit `main`-only guards to SDK publishing jobs, including the reusable Python publisher. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Separates docs previews from production publishing so unreleased API docs aren't published to the public site. - Adds Mintlify previews for docs PRs targeting `main` and persistent previews for docs pushes to `main`, reporting the URL and waiting for deployment success. - Runs docs reference tests and Mintlify validation on every PR, including docs-only PRs and backports. - Includes Go SDK source in the docs test cache inputs. - Adds `main`-only guards to SDK publishing jobs. <sup>Written for commit 6fd167a. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3042?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why - clean up copy & test the editorial docs change workflow <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Cleans up the introduction copy by removing redundant phrasing and tests the editorial docs change workflow. <sup>Written for commit aff9504. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3048?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
Mirrored from external contributor PR #2738 after approval by @miguelg719. Original author: @abhinavkr26104 Original PR: #2738 Approved source head SHA: `e77c269fcc7ab33d2b76f213f26da62b77b1e826` @abhinavkr26104, please continue any follow-up discussion on this mirrored PR. When the external PR gets new commits, this same internal PR will be marked stale until the latest external commit is approved and refreshed here. ## Original description # why The v4 init schema supplied `https://example.com/v1/traces` whenever callers omitted telemetry. The extension treated that placeholder as an intentional OTLP destination, creating guaranteed-failing background exports and possible shutdown delays for otherwise default Stagehand instances. Fixes #2732 # what changed - Make `stagehand.init` telemetry optional instead of injecting a placeholder endpoint. - Leave extension tracing inert when no telemetry configuration is supplied while preserving explicit OTLP export behavior. - Regenerate Python and Go protocol models and the embedded Go extension bundle. - Keep Go's existing value-style public telemetry option while omitting its zero value from the wire. - Document that telemetry export is disabled by default and add protocol/runtime/SDK regression coverage. - Add patch Changesets for the extension and SDKs. # test plan - Protocol unit suite: 26 files passed, 359 tests passed. - Extension unit suite: 45 files passed, 334 tests passed, 10 existing TODOs. - Focused TypeScript SDK create tests passed, including omitted and explicit telemetry. - Python focused tests: 200 passed, 1 skipped; generated-model freshness, Ruff format, and Ruff lint checks passed. - Full Python suite attempted: 455 passed, 2 skipped; only the two pre-existing Windows path assertions tracked by #2733 failed. - Go SDK suite excluding the intentionally separate examples package passed. - Protocol type-check and extension production build passed. - Targeted Oxfmt, Oxlint, Changesets validation, and `git diff --check` passed. - The full JavaScript unit run was attempted; unrelated Windows/environment failures remain in SDK path assertions, package-manager spawning, and file metadata handling. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Makes telemetry export opt-in so omitted telemetry no longer injects a placeholder endpoint that caused guaranteed-failing exports and shutdown delays. `stagehand.init` no longer defaults to `https://example.com/v1/traces`; omitting telemetry leaves tracing inert, while explicit telemetry keeps OTLP export. - Protocol: `stagehand.init.telemetry` is now optional with no default; schema, integrity, and wire-casing tests updated. - Extension: `createStagehandTracing.configure` accepts `undefined` and skips runtime creation; flush/shutdown become no-ops when telemetry is absent. - SDKs: TypeScript omits `telemetry` from the wire when unset; Go's `StagehandInitParams.Telemetry` is now `*TelemetryConfig` and omits the zero value via `optionalTelemetry`, while `CreateOptions.Telemetry` stays value-style; Python marks `telemetry` as `Optional` with the placeholder default removed. - Release: Patch changesets added for the five affected packages. **Migration** - No action needed; placeholder export errors and shutdown delays disappear. - Set `telemetry.traces.endpoint` to an OTLP collector (ending in `/v1/traces`) with required headers to enable export. - Go: pass `nil` to omit telemetry or set a non-empty endpoint/headers to enable; direct `StagehandInitParams` construction now requires `*TelemetryConfig`. <sup>Written for commit fecc5a6. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3045?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> <!-- external-contributor-pr:owned source-pr=2738 source-sha=e77c269fcc7ab33d2b76f213f26da62b77b1e826 claimer=miguelg719 --> --------- Co-authored-by: Abhinav Kumar Singh <abhinav.kr.singh.2610@gmail.com> Co-authored-by: miguel <miguelg71921@gmail.com> Co-authored-by: Miguel <36487034+miguelg719@users.noreply.github.com>
thanks @mikhail-koviazin for the contribution here! ## why The composed-tree XPath parser evaluates `text()` and `.` through the same helper, `element.textContent`. In XPath these are not the same thing: `.` is the string-value of the element, so it covers the whole subtree, while `text()` is the node-set of the element's **direct child text nodes**. This parser is not a rare path. It takes over whenever the document contains a shadow root anywhere, so a single unrelated web component on the page changes what a locator matches, silently and with no error. Measured against `document.evaluate()` on a build of `main` (`a73da68b`), fixture served over http. The only difference between a run that matches native and a run that does not is one unrelated `attachShadow()` call elsewhere in the same document: | XPath | `document.evaluate()` | Stagehand | | --- | --- | --- | | `//button[text()='Save']` | 1 | 2 | | `//div[text()='a']` | 1 | 0 | | `//div[contains(text(),'b')]` | 0 | 1 | | `//div[@id='split'][text()='y']` | 1 | 0 | | `//div[@id='split'][contains(text(),'y')]` | 0 | 1 | | `//div[@id='split'][normalize-space(text())='x']` | 1 | 0 | | `//button[.='Save']` | 2 | 2 (control: `.` is already correct) | Fixture: `<button id="wrapped"><span>Save</span></button>` before `<button id="direct">Save</button>`, plus `<div id="mixed">a<span>b</span></div>` and `<div id="split">x<br/>y</div>`. The count is not the worst part. The button whose label sits inside a `<span>` comes first in document order, so `//button[text()='Save']` returns it first and `.first().click()` clicks the wrong button. Nothing throws, nothing logs, and the run continues on the wrong element. The other direction is a silent zero on markup as ordinary as `a<span>b</span>`. ## what changed `text()` now reads its own node-set, and `.` keeps exactly the meaning it has today: - `text()='v'` is true when **any** direct child text node equals `v`. Comparing a node-set to a string is existential in XPath. - `contains(text(),'v')` and `normalize-space(text())='v'` read the string-value of the **first** node, because both functions take a string, so the node-set collapses. - `.='v'`, `contains(.,'v')` and `normalize-space(.)='v'` keep reading the string-value of the element, unchanged. Mechanically, in `packages/extension/dom/locatorScripts/xpathParser.ts`: the three patterns that accepted `(?:text\(\)|\.)` now capture which token they matched, and `textEquals` / `textContains` carry a `source: "self" | "text"` field that `evaluatePredicate` reads. The field is optional and absent means `self`, so predicates constructed anywhere else keep their current behavior. `and`, `or` and `not` carry it through without changes. ## test plan `packages/extension/tests/xpath-text-predicates.test.ts` (new, unit): the parser keeps `text()` and `.` apart for `=`, `contains()` and `normalize-space()`, and carries the source through `or` and `not`. `packages/sdk-ts/tests/integration/locatorXPathTextPredicates.test.ts` (new, integration): the table above against real Chrome. It has to be served over http, since `data:` URLs stay on the native engine and never reach this parser at all. Registered in `scripts/test-integration.ts` next to the other locator groups. Both are red on `main` and green with the change. On `main` the wrong-button case fails with `expected 2 to be 1` and the silent-zero case with `expected +0 to be 1`. Context: #1679 consolidated the parser copies and #1683 taught this one `text()`, `contains()` and `normalize-space()`. This is the same layer, one step further in. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes the composed-tree XPath parser so `text()` reads only direct child text nodes. Previously it read `element.textContent` (same as `.`), causing diverging matches and wrong clicks on pages with any shadow root. - Old: `text()` behaved like `.`. New: `text()` evaluates direct child text nodes; `.` still reads the element's subtree string-value. This aligns with `document.evaluate()`. - If a locator relied on `text()` to match nested text, use `.` instead. - `text()='v'` is existential across child text nodes; `contains(text(),'v')` and `normalize-space(text())='v'` collapse to the first text node. - Adds unit and integration tests; integration runs over http and is registered in `scripts/test-integration.ts`. <sup>Written for commit 482e0a9. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3052?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Mikhail Koviazin <mikhail.koviazin@gmail.com>
# why Add the extension-side PDF implementation separately from exposing a new SDK operation, so capture behavior can be reviewed on its own. This is **PR1 of 2**. Follow-up #3030 adds the public protocol/RPC registration, TypeScript/Python/Go SDK wiring, generated models, documentation, release notes, and final extension archive. # what changed - Add internal Understudy `Page.pdf()` using native CDP request/response types; keep the result base64-encoded for the later transport layer. - Share the existing capture queue with screenshots, including a configurable 30-second deadline, late-response recovery, and prevention of expired queued work. - Preserve the original timeout in a typed recovery error and its safe diagnostic message. - Add focused capture tests for serialization, failures, timeouts, queued expiry, and independent pages. - Refresh only the embedded extension snapshot required by the repository's artifact-drift check. PR2 regenerates it again when the public wiring lands. No PDF RPC is registered here. No public SDK methods, protocol schemas, generated models, or documentation are changed. # test plan - `pnpm check`: **36 tasks passed**. - Extension, SDK, protocol, documentation, parity, and discovery regressions: **975 passed** across 102 files (10 existing TODOs). - Local Chromium screenshot integration: **7 passed**. - Go SDK tests and generated-model/archive consistency checks passed. - Python generated-model consistency check passed. - Formatting and `git diff --check` passed.
# why Expose PDF rendering through the existing Stagehand SDK conventions after the internal extension implementation is in place. This is **PR2 of 2**, stacked directly on #3034 (`amel/pdf-render-extension`). Merge the parent first and follow the repository's stacked-PR handoff rules when moving this PR to `main`. # what changed - Register the `page.pdf` protocol operation and connect the extension router, controller, and runtime to the internal implementation from #3034. Replace its temporary native-CDP signature with the canonical protocol types. - Add TypeScript and Python `page.pdf()` and Go `Page.PDF()`, returning PDF bytes. TypeScript and Python optionally write a local file using their existing screenshot conventions. - Add typed print options and matching SDK response deadlines: 30 seconds for capture by default, with `timeout: 0` disabling the deadline. Preserve error causes and include computed timeout durations in diagnostics. - Regenerate the protocol document, Python and Go models, and the final embedded extension ZIP. Keep the public API documentation and release changeset with the SDK exposure. - Add wire/tracing, SDK, file-output, and local Chrome integration coverage. Fix integration-test discovery and validate its mapping against repository files. The capture implementation and recovery tests are reviewed in #3034, not repeated in this diff. The complete stack's Git tree is identical to the previously reviewed implementation at `2b416e172`; this split changes review boundaries, not behavior. # test plan - Complete-stack local Chromium PDF and screenshot integration: **9 passed**. Verify PDF bytes and file equality, page count, CSS dimensions, tags, page ranges, and captures after a rejected print. - Extension, TypeScript SDK, protocol, reference documentation, SDK parity, and integration discovery: **989 passed** across 102 files (10 existing TODOs). - `pnpm check`: **36 tasks passed**. Generated Go extension matches the final extension build; `git diff --check` passes. - The identical final tree was also verified with **235 Python tests**, Ruff/type checks, Go SDK tests, `go vet`, and generated-artifact checks. - Parent #3034 was independently verified with **975 regressions**, **7 screenshot integration tests**, all **36 repository checks**, and Go/Python generated-artifact checks.
## Summary Make the integrations overview a general directory for connecting Stagehand to agents, frameworks, and application workflows. Organize the overview and sidebar into Agent Frameworks, CLI Agents, and Automations. - Add dedicated overviews for Agent Frameworks and CLI Agents. Cover framework connections separately from MCP adapter setup for coding agents, with Pi documented as a native extension. - Update navigation and security links, and replace the removed MCP best-practices entry with the CLI Agents guide. - Add Stripe under Automations, documenting the Checkout sample from stripe-samples/webmcp#5, its setup, WebMCP flow, and final Pay click. - Pin the Stripe sample commit while the upstream PR is open and explain its spending limit and result-handling limitations. ## Validation - `mint validate` - `mint broken-links --check-anchors --check-redirects --check-snippets` - `mint a11y --skip-contrast` - Formatting check for `docs.json` and `git diff --check` All passed using Node.js 24. Checkout was not executed; the Stripe guide was verified against the upstream sample source. --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
# why - example.com changed, this broke some smoke tests in our ci # what changed - swapped it to a hosted eval site that is similar to example.com <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes failing CI smoke tests by replacing `https://example.com` with a hosted eval site that mirrors example.com across the Go, Python, and TypeScript SDK examples and the TypeScript Browserbase smoke test. <sup>Written for commit dfd525e. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3069?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why * Before Browserbase had secrets support, `functions init` would install a playwright template. But now we support secrets so we can update the starter template to showcase Stagehand. * There were some rough edges around the `functions publish` command related to pnpm 11. Added a few updates so that the functions CLI works out of the box. # what changed # test plan It works if nothing in this path errors: 1. [in stagehand repo] `pnpm build && cd packages/cli` 2. `alias browse-dev="node $HOME/[your dev path]/stagehand/packages/cli/bin/run.js"` to set a local version of the `browse` cli called `browse-dev` 3. `cd [your dev path, _not_ in stagehand repo] && browse-dev functions init branch-test && cd branch-test` 4. `browse-dev cloud extensions upload node_modules/@browserbasehq/stagehand/dist/assets/stagehand-extension.zip` and then replace `your-extension-id` in `index.ts` 5. `browse-dev cloud secrets create BROWSERBASE_API_KEY --env BROWSERBASE_API_KEY` to store your secret API key for use in the deployed function 6. `browse-dev functions dev index.ts` 7. (in a new terminal) `curl -X POST http://127.0.0.1:14113/v1/functions/my-function/invoke -H 'Content-Type: application/json' --data '{}'` to make sure it works locally 8. `npm_config_min_release_age=0 browse-dev functions publish index.ts` 9. `browse-dev functions secrets attach <functionId> <secretId>` 10. `browse-dev functions invoke <functionId>` to make sure you got the same result as (7) above 11. Success! <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Swaps the Playwright starter in `functions init` for a Stagehand one, and fixes `functions init` and `functions publish` on pnpm 11 and private npm registries. - Local dev now sends an empty `secrets` object to invocations, matching production, so the starter's `context.secrets.BROWSERBASE_API_KEY` lookup needs no null check and falls back to `process.env.BROWSERBASE_API_KEY`. - `functions init` installs `@browserbasehq/stagehand` instead of `playwright-core`, pins zod to Stagehand's version so schemas pass type checks, and writes a Stagehand starter that extracts Hacker News top stories through the Model Gateway. - The starter connects with `browserbase.connect` into `Stagehand.create` and expects you to upload the Stagehand extension and paste its ID into `index.ts`. - `functions init` writes `pnpm-workspace.yaml` so pnpm 11 allows esbuild's build script, and its next steps use `browse` commands. - `functions publish` builds `package-lock.json` from the uploaded files (so local `file:` dependencies resolve), omits registry-resolved URLs for private registries, checks for an existing lockfile, and prints npm output when generation fails. <sup>Written for commit b630e73. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3055?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why * The release of Function Secrets enables us to support Stagehand deployments on Browserbase. This PR showcases that in the new deployment guide # what changed # test plan <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Updates the Stagehand deployment guide to recommend Browserbase Functions with encrypted project secrets as the primary deployment path instead of Vercel. - Adds setup, extension upload, Function development, local testing, publishing, secret attachment, invocation, and troubleshooting steps. - Uses the Model Gateway in the example, so no model provider setup is needed. - Moves the Vercel guide under "Other deployment options" and adds a Features section. - Clarifies the introduction's description of Stagehand's control layers. <sup>Written for commit 83c9e20. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3056?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
Release Browse independently of the Stagehand SDKs. Merging this PR publishes the CLI from the merged commit. ## 0.11.1 ### Patch Changes - [#3055](#3055) [`8308d8d`](8308d8d) Thanks [@akeimach](https://github.com/akeimach)! - `functions init` now scaffolds a Stagehand project. It installs `@browserbasehq/stagehand` instead of `playwright-core`, installs the zod version that Stagehand uses, and writes a Stagehand starter function. - [#3055](#3055) [`8308d8d`](8308d8d) Thanks [@akeimach](https://github.com/akeimach)! - Fix Functions builds that failed because of how `functions publish` generated `package-lock.json` or how `functions init` set up pnpm: - `functions publish` now generates `package-lock.json` without registry URLs, so private npm registries work. - `functions publish` now resolves local `file:` dependencies by building `package-lock.json` from the uploaded files rather than just `package.json`. - `functions publish` now prints npm's error output when it can't generate `package-lock.json`. - `functions init` now writes a `pnpm-workspace.yaml` that allows the esbuild build script, required by pnpm 11+. - [#2542](#2542) [`514970e`](514970e) Thanks [@shrey150](https://github.com/shrey150)! - Fix local browser discovery (`--auto-connect`, `browse doctor`) trusting a stale cached debugging port after a different Chrome process later reuses that same port. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# why Fixing a prose issue surfaced in another PR, and while in there, added clarity about the functions starter code and what could be replaced # what changed * Updates docs prose from "we recommend" to "Browserbase recommends" * Specifies which node version * Adds a note about the template code and what must stay vs be replaced # test plan <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes prose in the deployment guide and clarifies that the Functions template is starter code you replace. - Changes "we recommend" to "Browserbase recommends" and specifies Node.js 22.18 or later. - Explains that the template contains a starter Function to replace, and notes to keep the `defineFn` call and update the function name consistently. <sup>Written for commit 1f6ff65. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3077?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why Three links in the v3 docs are broken, and two Go code samples were rewritten into links, so they no longer show valid Go. # what changed - `v3/sdk/go.mdx`: restore `param.Override[T](value)` and `param.Override[stagehand.FooParams](12)`. Both had been turned into links to non-existent files (`stagehand-go/blob/main/value` and `/12`). The restored text matches the stagehand-go README. - `v3/sdk/java.mdx`: the OkHttp logging interceptor link pointed at `square/okhttp/tree/master`. That repo's default branch is `main`, and `master` no longer resolves. - `v3/basics/evals.mdx`: `evals.config.json` moved to `packages/evals/evals.config.json`. The link used the old top-level path. # test plan Checked each new target on GitHub (`packages/evals/evals.config.json` on main, `okhttp-logging-interceptor` on okhttp main) and compared the Go snippets against the stagehand-go README. Docs-only change, no Changeset needed per CONTRIBUTING.md. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes three broken links in the v3 docs. - Go: the `param.Override[T](value)` and `param.Override[stagehand.FooParams](12)` code samples were accidentally converted into links to non-existent files and are now back to valid Go. - Java: the OkHttp logging interceptor link now uses `main` instead of `master`. - Evals: the `evals.config.json` link now points to `packages/evals/evals.config.json`. <sup>Written for commit c427fb1. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3076?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why a `locator` action needs one timeout covering all of its downstream code (eg, checking frame readiness, finding the element, & taking the action). if setup uses three seconds of a five-second timeout, the action should have two seconds left this pr adds the shared timeout helper. later PRs will connect it to locator methods & add public timeout options. # what changed - added `locatorOperation.ts` to track the time remaining for one call. `runLocatorOperation()` creates it once & all nested steps share it - passing `0` disables the timeout - added `run()` to check the deadline before starting a step & stop waiting when time runs out. the error names the operation & the step that was still waiting. - added `delay()` so pauses between steps use the same timeout. - added `cleanup()` to attempt cleanup after a timeout, with a one-second limit on waiting. cleanup errors do not replace the original error. - added an optional callback to release temporary resources that arrive too late to use. commands already sent to the browser may still finish # test plan added tests in `locatorOperation.test.ts` that control time & hold responses open to verify: - nested steps keep the original deadline after success or failure, & timing out one call does not stop another. - zero disables the timeout, changing the system clock does not change the time remaining, & invalid timeout or delay values are rejected. - an expired call cannot start another step. a late response or error cannot resume the action. - resources arriving after timeout are released once; resources returned in time remain available to the caller. - delays stop at the deadline. long timeouts & delays are not shortened by the underlying timer's size limit. - timers & listeners are removed after success, failure, or timeout. timeout errors identify a step that is still waiting. - cleanup failures preserve the original error, & stalled cleanup neither delays the timeout response nor waits longer than its one-second allowance <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a shared locator operation context so a single timeout spans all steps of a locator action (frame checks, element lookup, and the action itself), replacing separate per-step deadlines. - `runLocatorOperation()` creates the context once and nested steps share its remaining budget; passing `0` disables the timeout. - `run()` checks the deadline before each step, `delay()` pauses within the same budget, and cleanup of late resources is attempted for one second after expiry. - Expiry stops waiting and may release late-arriving resources, but the timeout error always wins, even if a late command rejects. <sup>Written for commit 5800073. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3013?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why resolving a the node/object ID that a `locator` points to can involve crossing iframes, waiting for browser helpers, & looking up the element. these steps need to share the caller's deadline so each frame or retry cannot restart the timeout. this pr connects that deadline to node/object ID resolution. the next PR in this stack will connect `locator` actions & reads to these helpers. public parameters for setting timeouts will come in a later PR. ### note: this PR also renames `LocatorOperation` to `Progress` for clarity # what changed - renamed `locatorOperation.ts` to `progress.ts`, `LocatorOperation` to `Progress`, & `runLocatorOperation()` to `runWithProgress()` because it will be used by callers beyond locators. - passed the same optional progress through frame traversal, element lookup, & browser helper readiness. callers without progress keep their existing behavior for now. - made readiness waits, retries, & browser commands use the remaining time. readiness can exceed the old fixed limits when the caller allows it. passing in `0` disables the deadline. - preserved timeout errors through retries, fallback setup, & cleanup. closed connection or session errors stop resolution, while frame movement & temporary browser context loss can still recover before expiry. - released temporary browser references after timeout, including late results. callers waiting for shared helper setup have independent deadlines. # test plan added tests in `locatorResolution.test.ts` using controlled time & browser responses to verify: - multiple frame hops share one budget, & polling stops when it expires. - readiness can finish beyond the old limits with a longer or disabled timeout. - short readiness attempts fit the remaining time & detect a frame's new session. - stalled commands time out; late responses cannot resume resolution & temporary references are released. listeners & timers are removed after expiry. - one caller timing out does not cancel shared helper setup for another caller. - errors or cleanup finishing after the deadline produce a timeout, even before the timeout timer fires. ordinary lookup failures retain their existing behavior before expiry. - closed connections & sessions surface their errors. recovery from a changed session or missing browser context works only while the call is still active. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a shared deadline to `locator` resolution so iframe hops, readiness waits, and element lookup all share the caller's timeout instead of each restarting it. Also fixes locator failures when entering still-loading iframes and correctly resolves XPaths that end at an iframe element. **What changed** - Renames `LocatorOperation` to `Progress` and `runLocatorOperation()` to `runWithProgress()`; callers beyond locators now use it, and a temporary `runLocatorStep()` adapter lets callers without `Progress` keep current behavior. - Threads an optional `Progress` through frame traversal and element lookup; `0` disables the deadline. - Readiness waits and browser commands use remaining time; timeout errors survive retries, fallback setup, and cleanup, while closed connection or session errors stop resolution immediately. - Releases temporary browser references after expiry, including late results and earlier element matches replaced by a later lookup. - Recovered contexts and frame restarts are honored only while the call is active. **Bug fixes** - Waits for the locator world when a deep XPath crosses a loading iframe instead of failing on a missing execution context. - Keeps a trailing `iframe[n]` in the parent frame as the target element instead of descending into the child document. <sup>Written for commit 0f263bc. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3023?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why pr #3023 made locator resolution respect the caller's deadline. the action or read that follows also needs to use the remaining time. otherwise, a stalled browser command can keep the call waiting after its timeout. # what changed - passed the same progress through direct, deep, & frame-scoped locator methods, from finding the target through executing the action/read. - bounded browser commands for `click()`, `hover()`, `selectOption()`, `scrollTo()`, `sendClickEvent()`, `centroid()`, `backendNodeId()`, counts, & element reads. - counts also pass progress through their separate selector helpers - preserved timeout & closed connection/session errors in catches that previously ignored errors or returned zero. ordinary lookup failures keep their existing handling. - used bounded cleanup for temporary browser references. cleanup failures cannot replace the action's error, & cleanup crossing the deadline cannot turn the call into success. - kept click events in their existing order, without waiting for each response before sending the next event. expiry prevents further dispatch. ### note: progress remains optional during migration. fill, typing, highlighting, & uploads come in a subsequent PR # test plan added tests in `locatorActions.test.ts` using shared setup, controlled time, & held browser responses to verify: - delegates, actions, reads, & counting helpers receive the same progress. - time spent resolving the target leaves only the remaining budget for execution. - stalled commands reject at the deadline; late responses cannot resume actions. an already-expired call sends no action commands. - click events retain their order & are sent before earlier responses arrive. dispatch stops if the deadline passes during the sequence. - timeout & closure errors propagate through scrolling & counting. valid empty reads still return false, zero, or an empty string. - cleanup failures preserve the action error, cleanup crossing the deadline reports a timeout, & stalled cleanup cannot hold the outer caller past expiry. - timing out one call leaves a concurrent unlimited call on the same locator free to finish. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Makes locator actions and reads respect the caller's timeout so a stalled browser command can no longer hold a call past its deadline. - Threads the same progress through direct, deep, and frame-scoped locator methods, from target resolution through execution. - Bounds browser commands for click, hover, selectOption, scrollTo, sendClickEvent, centroid, backendNodeId, count, and element reads; counts also pass progress through their selector helpers. - Preserves timeout and closed connection/session errors in catches that previously ignored them or returned zero. - Bounds cleanup of temporary browser references so cleanup failures can't replace the action's error, and cleanup crossing the deadline can't turn the call into success; cleanup is no longer awaited when an action is expiring. - Keeps click events in their existing order without waiting for each response; expiry stops further dispatch. - Progress remains optional during migration; fill, typing, highlighting, and uploads come in a later PR. <sup>Written for commit e4cef1d. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3024?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
) # why `fill()`, `type()`, `highlight()`, & `setInputFiles()` perform multiple steps within one call. those steps need to share the caller's deadline, including typing fallbacks, intentional delays, & file preparation. otherwise, they can continue sending browser commands after the call times out # what changed - passed the progress object downstream through `fill()`, `type()`, `highlight()`, `setInputFiles()`, & their existing delegates - made both fill fallbacks reuse the original deadline. timeout or closed connection/session errors prevent fallback to typing. each browser reference is released once, including when an early release stalls. - bounded text preparation & keyboard commands. typing delays use the remaining budget & stop on expiry. - bounded highlight setup, drawing, duration, & refresh waits. successful `durationMs: 0` calls still leave the highlight visible. timeout or failure triggers removal, including another removal attempt if a draw finishes late. - combined overlay removal & reference release into one bounded cleanup wait. cleanup failures cannot replace the action error. - included file normalization & encoding in the budget, with another check before injection. synchronous encoding can finish after expiry, but cannot trigger an upload afterward. clearing a file input follows the same path. # test plan extended `locatorActions.test.ts` using shared setup, controlled time, & held browser responses to verify: - delegates & nested calls receive the same progress; both fill fallbacks get only the remaining time & stop on expiry or closure. - prepared fill inserts text or clears the field correctly, & stalled early cleanup does not release the same reference twice. - typing stops during a delay or stalled keyboard command without sending more characters. unlimited typing can finish. - highlight duration consumes the budget; zero-duration highlights remain visible on success. ordinary refresh failures can recover, while closure stops refreshes. - late highlight draws are removed. stalled cleanup does not add sequential waits, & cleanup failures preserve the original error. - expiry during normalization or encoding prevents file injection. stalled normalization cannot resume the upload after timeout. - upload injection respects finite & unlimited budgets; file contents & metadata are preserved, & an empty file list still clears the input. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes `fill()`, `type()`, `highlight()`, and `setInputFiles()` so every step in a multi-step call shares the caller's deadline, preventing browser commands from being sent after the call has timed out. - Both `fill()` fallbacks reuse the original deadline; timeout or closed connection errors stop fallback to typing. - Typing delays use the remaining budget, and highlight refresh waits and duration consumption are bounded. - Zero-duration highlights stay visible on success; timeout or failure triggers removal, including a retry if a draw finishes late. - File normalization and encoding count against the budget, with a check before injection; clearing a file input follows the same path. - After a failed or timed-out action, cleanup runs without blocking the caller and cannot replace the original error, even when cleanup itself stalls. - Extended `locatorActions.test.ts` with controlled time and held browser responses to cover each deadline path. <sup>Written for commit 013a3f3. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3026?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why
this PR adds the `timeout` param to the protocol, & exposes it publicly
in ts. the default timeout is 20 seconds
# what changed
- added optional timeout settings to all 17 terminal locator methods,
including reads. typescript callers can use `click({ timeout: 5000 })`,
`fill("hello", { timeout: 5000 })`, or `count({ timeout: 0 })`.
- started one deadline before frame resolution & passed it through the
whole call. frame readiness, element lookup, typing delays, highlight
duration, & extension-side upload preparation all share that budget.
- aligned typescript response waits with the execution timeout plus
delivery grace. zero disables that response deadline too. long timeouts
avoid the JS timer limit, & timeout errors retain their name & message.
- made the compatibility facade pass its remaining budget to native
locator calls, including zero, instead of dropping timeout options
# test plan
- `locator-timeouts.test.ts` checks every registered locator method
accepts zero & positive timeouts, rejects invalid values, preserves
omission, & keeps existing options working. timeout settings stay
separate from locator identity.
- `runtime-locator-timeouts.test.ts` uses controlled time to verify
every entry point starts its deadline before resolution, applies the
default or override, rejects stalled work, & leaves zero unlimited.
- wrapper, rpc, & package tests cover option forwarding, the public
options type, response deadlines & delivery grace, long timers, &
timeout error details. facade tests check remaining-budget forwarding
for ordinary & frame locators.
- `iframeLocatorReadiness.test.ts` runs against real chrome with
same-process frames & frames in a separate process. it verifies nested
frame readiness & typing share one budget, explicit timeouts can exceed
the old readiness cap, zero waits successfully, & loading a frame after
expiry does not cause a late click.
- `locatorActions.test.ts` exercises highlight & upload cleanup through
the runtime: stalled cleanup preserves an earlier action error & does
not delay timeout rejection.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a `timeout` option to all terminal locator methods across the
protocol and the TypeScript, Python, and Go SDKs, and updates the v4
docs. The default is 20 seconds, and `{ timeout: 0 }` disables the
deadline.
**What changed**
- One deadline starts before frame resolution and covers frame
readiness, element lookup, typing delays, highlight duration, and upload
preparation; SDK file reading and request delivery happen before that
budget starts.
- Each SDK sets its RPC response deadline to the execution timeout plus
a delivery grace, with `0` disabling it; long timeouts work around
per-language timer limits.
- The Playwright compatibility facade forwards its remaining budget to
native locator calls, including zero.
- Go's `SetInputFiles` now takes a file-input slice, and Python rejects
non-finite timeout values.
- Timeout errors retain the `TimeoutError` name and message.
<sup>Written for commit 0d7d1ec.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3033?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
…#3081) # why `screenshot()` timeouts could stop the caller waiting while downstream functions (eg, preparation & mask lookup) continued without a shared deadline. `pdf()` also used separate timeout handling. this PR makes both `screenshot()` & `pdf()` use the `progress` tracker. # what changed - used shared progress for screenshots & pdfs, starting before queueing. nested calls reuse their parent's remaining time. - passed screenshot progress through preparation, mask lookup, tab activation, & capture. mask lookup & its paint delay consume the same budget. - the timeout/deadline are checked before starting further browser commands, including when the timeout timer has not fired yet. already-issued commands can still finish. - the page is kept unavailable until pending work & restoration finish. stalled preparation or cleanup does not block other tabs; activation & capture remain serialized across the browser. - registered restoration before setup starts & released all resolved mask nodes, including nodes skipped after expiry. cleanup cannot replace an earlier capture error. - preserved defaults: screenshots are unlimited, pdfs use 30 seconds, & zero disables either timeout # test plan - `screenshotUtils.test.ts` checks that queued requests cannot start after expiry, stalled browser commands cannot trigger later steps, & captures stay blocked until recovery finishes. it also checks that stalled page setup or cleanup leaves other tabs usable. - `pdf.test.ts` checks shared queue ordering, time spent queueing counting toward the deadline, inherited deadlines, defaults, & zero. late print or screenshot responses cannot release the page before pending work finishes. - added preparation tests in `pdf.test.ts` for mask lookup consuming the screenshot budget, late mask measurements being restored, skipped nodes being released, & cleanup preserving the original capture error. further tests prevent animation changes or style insertion after expiry, including before the timer fires. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Makes `screenshot()` and `pdf()` use the shared `progress` tracker so their deadline applies across every downstream step, nested calls inherit the parent's remaining budget, and a timed-out capture can no longer leave scheduled work running or free the page early. - The deadline is checked before each browser command, including before the timeout timer fires; commands already issued still finish. - Late CDP responses, stalled setup, and stalled cleanup keep the page lock held, blocking subsequent captures while leaving other tabs usable. - Mask lookup and its paint delay consume the same budget as the capture itself, and all resolved mask nodes are released even when skipped after expiry. - Cleanup cannot overwrite an earlier capture error. - Defaults preserved: screenshots are unlimited, pdfs use 30 seconds, and zero disables either timeout. <sup>Written for commit ad86581. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3081?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
## Summary - Move the observability documentation change out of #3045. - Document that omitting telemetry disables export and remove the placeholder-endpoint TODO. Stacked on #3045; this PR contains only the documentation change. Merge after #3045. ## Validation - git diff --check passes. - Verified #3045 no longer changes packages/docs. - Verified the combined branches reproduce the original tree exactly. - No runtime tests run for this docs-only split. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Documents opt-in telemetry behavior in the observability config docs: omitting the `telemetry` option now disables export, and the outdated placeholder-endpoint TODO comment is removed. <sup>Written for commit 13b02f1. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3054?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
…3067) See browserbase/stagehand-website#199 --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why `page.snapshot()` had no timeout param, nor did some of its internal helpers. the helpers that it calls are also called by other functions in the codebase that require timeout handling. this PR wires the `progress` object through the shared downstream helpers, and also exposes a user facing `timeout` param in `page.snapshot()` # what changed - added a snapshot timeout in milliseconds to typescript, python, & go. omission or `0` keeps snapshots unlimited. - made one deadline cover frame readiness, element lookup, document & accessibility tree reads, & frame traversal - allowed internal snapshot calls to reuse a caller's remaining time & timeout error instead of starting a new budget. - stopped retries, fallback reads, & further frame traversal after expiry. temporary element references are released, including those returned after timeout. already-issued browser commands can still finish. - updated sdk response waits to allow the requested timeout plus delivery grace, with no response deadline for unlimited snapshots # test plan - `capture.test.ts` checks public & inherited deadlines, unlimited snapshots, expiry preventing further reads or fallback, & cleanup of ignored elements. - `domTree.test.ts` & `a11yTree.test.ts` check that expired reads cannot retry or fall back, including when the deadline timer has not fired yet. - `focusSelectors.test.ts` checks that both selector lookup paths release element references returned after timeout. focused accessibility tests also check reference cleanup after successful reads. - protocol & sdk tests cover omitted, zero, positive, & invalid timeouts, option forwarding in all three sdks, & response waits. the typescript package test checks that the published snapshot options include the new field. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds an optional `timeout` param to `page.snapshot()` so callers can bound the entire snapshot operation. Omitted timeouts now default to 20 seconds instead of running unlimited. - Exposes `timeout` in the TypeScript, Python, and Go SDKs; passing `0` keeps snapshots unlimited. - Uses one deadline for frame readiness, element lookup, DOM/accessibility tree reads, and frame traversal, and lets snapshots reuse the caller's remaining time instead of starting a new budget. - Stops retries, fallback reads (including focus-scope and ignore-locator fallback), and further frame traversal after expiry, releasing temporary element references even when they return after the timeout. - SDK response waits now add delivery grace to the requested timeout and skip the deadline entirely for unlimited snapshots. <sup>Written for commit 4054cdb. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3083?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
Browse 0.10.0 uploaded successfully in [the Release workflow](https://github.com/browserbase/stagehand/actions/runs/35798682312/job/106985029323), but the following tag step saw a temporary npm 404 and returned `unpublished`. The job finished green without pushing the release tag. Push the validated local tag that Changesets creates after a successful upload without requiring immediate registry visibility. When no local tag exists, retain the registry check and original version-bump commit guard for recovery. Validation: reproduced the failure with a real HTTP server returning 404 and a bare Git remote, then verified the fix; all 67 release tests, tooling typecheck, targeted lint/format, and diff checks pass. The diff changes only the helper and its existing regression test. The current `browse@0.10.0` tag has been repaired separately to the exact commit verified in npm provenance. No npm upload or package version change is part of this PR. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes the release workflow so an existing local Browse tag is pushed without waiting for npm registry reads to converge. Previously a temporary 404 from npm during propagation made the tag step return `unpublished`, finishing green without creating the release tag. When no local tag exists, the registry check and the version-bump-commit guard still run as before. <sup>Written for commit 345a953. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3015?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
…2821) # why Eve agents need an installable Browserbase extension with persistent browser state and predictable cleanup. This adds the native Stagehand V4 integration as `@browserbasehq/eve` 0.2. # what changed - Add `browserbase__run`, `browserbase__snapshot`, and `browserbase__screenshot` through Eve's native extension API. - Share one Browserbase session across calls, recover unhealthy sessions, and release owned resources on explicit close. The next call can start a fresh session. - Bundle the shared browser facade, including the cleanup hook and sanitized errors used by Eve's session owner, and add package build, release, and Changeset configuration. - Support Eve 0.68.x, resolve environment credentials when the browser starts, and inherit Browserbase proxy defaults unless explicitly overridden. The [build script](https://github.com/browserbase/stagehand/blob/ab25295e96476ee3c13c19a8e936348491da0e04/packages/integrations/eve/scripts/stage-facade.mjs) copies four shared Core files byte-for-byte into Eve's generated, gitignored source directory. `runtime.ts`, `contract.ts`, and `redact.ts` are unchanged from the PR base. `tools.ts` adds the host cleanup hook and error handling; the Eve tool wrappers adapt the existing Stagehand example. The [previous implementation in browserbase/integrations](https://github.com/browserbase/integrations/tree/b7bc81c6fd4e089ab0c0df2b82529b200739e458/packages/eve-browserbase) already uses Stagehand V4. This PR keeps its npm package identity but changes the tool API and session lifecycle; none of the 17 tracked Eve package files is byte-identical to that implementation. The main implementation review areas are session ownership/recovery, the shared cleanup/error changes, and packaging/release wiring. Eve's built-in `web_search` and `web_fetch` remain available; [#2822](#2822) adds optional Browserbase replacements. The separate MCP lifecycle change is in [#3078](#3078); this native extension does not depend on it. Documentation is in [#3079](#3079). Merge that PR before publishing 0.2 so the npm package includes the updated README. # test plan Checked after the `main` update at [`ab25295e9`](ab25295). Refreshed against current `main`, preserving upstream dependencies and Eve’s named catalog. The URL-matching test now resolves Playwright Core through its declared Playwright dependency, so the new examples’ MCP dependency cannot change which version it tests. | Command / flow | Observed output | Coverage | | --- | --- | --- | | Shared facade build, typecheck and unit tests; Pi build/typecheck/tests | 136 facade tests and 3 Pi tests passed | Shared hook/error changes and existing native consumer | | `CHROME_PATH=<Chrome binary> pnpm --filter @browserbasehq/stagehand-integrations test:browser` | 6 tests passed | Browser compatibility against local fixtures | | Eve package typecheck and `test:unit` | Typecheck passed; 39 tests passed | Native session ownership, credentials and tool behavior | | Fresh tarball, strict `publint`, external Eve 0.68.0 consumer | All passed; `eve build` passed with `BROWSERBASE_API_KEY` unset | Installable package and credential-free builds | | Installed SDK and browser extension compared with fresh local build | Byte-identical; Eve resolves the same SDK | Smoke tests cover the SDK and browser extension from this branch | | Packed lifecycle probe and real `eve eval --strict --skip-report --timeout 300000` | 8/8 gates passed; persistent state, error recovery, snapshot-ID navigation, 193,444-byte PNG and close/reopen passed | Native tools with real Browserbase sessions on public Example Domain/IANA pages | | Independent session audit | All 5 sessions `COMPLETED`, including the preliminary harness run; no fallback release needed | Owned-session cleanup |
Adds [Amel Bajramovic](https://github.com/bosniankicks) to the contributors list in the README Acknowledgements section.
…2893) Bounds capture and RPC/batch waits. Two consecutive capture deadlines are recoverable; a third latches terminal session loss, while a successful tool call resets the counter. Late completion cannot overwrite newer snapshot IDs. Terminal loss rejects queued calls without dispatch. Actions are never automatically replayed. Regressions cover bounded timeout inputs, late completion, counter reset, screenshot transport and first-loss handling. `experimentalBatch` keeps its single `timeout` option (the callback deadline the browser-side executor enforces). The client bounds the whole round trip at `timeout` plus a 15-second batch grace (`CALLBACK_BATCH_CLIENT_GRACE_MS`), because the executor's timeout is cooperative and can be reported late. A batch that gets no response by then rejects with `StagehandBatchTimeoutError`; RPC response deadlines throw `RPCResponseTimeoutError`. Earlier revisions also exposed that local deadline as a `clientTimeoutMs` option. Nothing passed it, so it is removed; the default it produced is unchanged. The facade now calls `page.snapshot()` with `timeout: 0`. Snapshot gained a 20-second default on main, which fired before the facade's 120-second capture deadline, so a slow snapshot failed as an ordinary tool error and never counted toward terminal session loss. Preserves provider/session/age/timeout diagnostics through the host, checks screenshot byte limits before decoding, and isolates failures in diagnostic observers. The typed RPC timeout error lives in a focused public module, keeping internal RPC helpers outside the SDK public-field contract. Validation: 120 focused tests and 47 SDK AST/release guards, SDK/core/eval typechecks, SDK build/publint, and merged ownership/capture regression checks. At `b14e4ec95`: 345 SDK unit tests and 156 facade unit tests pass, with SDK and facade typechecks and the format check clean. Stack base: `main`. Review this PR relative to its immediate predecessor. Reviewer entry points: - [`packages/integrations/core/src/facade/tools.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/integrations/core/src/facade/tools.ts) - [`packages/sdk-ts/src/batch.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/sdk-ts/src/batch.ts) - [`packages/integrations/core/tests/facade-tools.test.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/integrations/core/tests/facade-tools.test.ts) The CLI startup fix is now included in the parent (#2892), so this PR focuses on capture/RPC deadlines and recovery. Current main is incorporated, preserving both the timeout exports and the runtime-compatibility exports. Readiness: CI is running on `b14e4ec95e`; it last passed on `65d9c911b7` ([run](https://github.com/browserbase/stagehand/actions/runs/36969426716)). The one cubic comment (snapshot timeout) is fixed and resolved. Human review status is unchanged. Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 → #2905 → #2906 → #2907.
# why the protocol now lets the worker ask an SDK to make an HTTP request. the TS SDK needs an implementation that can receive that request, send it over HTTP, & return the response while the original Stagehand call is still waiting this PR adds that transport using native `fetch` & the existing RPC connection # what changed - added a connection snapshot that resolves the bb key, session, & API endpoint using existing browser-factory precedence, regions, & URL overrides - added an executor for Gateway, cache read, & cache write requests. it adds the bb headers, sends the supplied body, & returns the complete response. - kept each execution to one HTTP attempt. HTTP errors & redirects are returned to the worker; retry decisions remain with the worker. - carried cancellation & the remaining timeout through response body buffering. - added RPC handler registration & disposal. cancellation targets one request, disconnects stop pending work, & disposal removes handlers without closing the shared RPC connection. # test plan - shared fixtures verify endpoint selection, connection precedence, & headers. - local HTTP tests cover request bodies, compressed & empty responses, redirects, HTTP/network failures, cancellation, & timeouts during body delivery. - RPC tests verify a reverse request completes while a Stagehand call is pending, equal request IDs on separate connections stay independent, & cleanup stops active HTTP work. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds an HTTP transport to the TS SDK so the worker can ask the SDK to make Browserbase Gateway and cache requests while the original Stagehand call is still pending. - Resolves the Browserbase connection from existing browser-factory precedence, region, and API URL overrides, and snapshots it per connection. - Executes `gateway.responses`, `cache.get`, and `cache.set` over native `fetch`, adds the Browserbase headers, and returns the response without retrying. - Carries cancellation and the remaining timeout through body buffering; the worker owns retry decisions. - Registers RPC request and cancel-notification handlers and aborts active HTTP on disposal without closing the shared RPC connection. <sup>Written for commit d05a8d5. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3205?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3205?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3205&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why the protocol now lets the worker ask an SDK to make an HTTP request. the python SDK needs an implementation that can receive that request, send it over HTTP, & return the response while the original Stagehand call is still waiting this PR adds the python implementation of #3205 using the SDK's existing `httpx` dependency & RPC connection # what changed - added a connection snapshot with the same browser-factory precedence, regional endpoints, & API URL override behavior as the TypeScript implementation - added one HTTP attempt per Gateway, cache read, or cache write request. the executor applies bb headers & returns the buffered status, headers, & body, including HTTP errors & redirects. - used the caller's remaining timeout through body buffering, without adding an `httpx` default timeout or a second retry loop - added request & cancellation handlers to the existing RPC connection. explicit request cancellation, task cancellation, disconnect, & disposal stop the corresponding HTTP work & release its resources # test plan - shared fixtures & connection tests cover endpoint selection, precedence, & snapshots remaining unchanged after caller inputs are mutated. - local HTTP tests cover header precedence, response decoding, redirects, network failures, & deadlines before headers and during body delivery. - RPC tests cover requests during a pending batch call, cancellation, duplicate IDs, independent connections, & handler disposal <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds the Python SDK implementation of the Browserbase HTTP transport, letting a worker ask the SDK to make HTTP requests over the RPC connection while the original Stagehand call is still pending. - Resolves a Browserbase connection snapshot (API key, API URL, session ID) with the same precedence, regional endpoints, and override behavior as the TypeScript SDK. - Executes one `httpx` request per Gateway, cache read, or cache write, returning the buffered status, headers, and body — including HTTP errors and redirects — with no retry loop or `httpx` default timeout. - Uses the caller's remaining timeout through body buffering, without adding a second deadline. - Adds request and cancellation handlers to the RPC connection; cancellation, task cancellation, disconnect, and disposal stop in-flight HTTP work and release resources. <sup>Written for commit 9997de8. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3206?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3206?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3206&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why the protocol now lets the worker ask an SDK to make an HTTP request. the golang SDK needs an implementation that can receive that request, send it over HTTP, & return the response while the original Stagehand call is still waiting this PR adds the python implementation of #3205 using Go's standard `net/http` package # what changed - added a connection snapshot that preserves browser-factory precedence, regional endpoints, & API URL overrides. - added an executor for Gateway, cache read, & cache write requests. it applies bb headers & returns the buffered HTTP response, including errors & redirects - prevented automatic replay of these POST requests so the worker continues to own retry decisions. - carried context cancellation & the remaining timeout through response body reads, & closed response bodies and idle connections during cleanup. - added RPC registration & cancellation by request ID. cancellation notifications are handled directly, so a busy log callback cannot delay them # test plan - shared fixtures & connection tests cover endpoint selection, header precedence, & independent connection snapshots. - local HTTP tests cover gzip/text decoding, empty bodies, redirects, network failures, & cancellation or timeout while reading a response. - transport tests verify a dropped connection does not replay a received POST & that response bodies are closed. - RPC tests cover concurrent requests, matching IDs on separate connections, disconnects, disposal, & cancellation while log delivery is blocked; race checks exercise the lifecycle paths. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds HTTP transport to the Go SDK so the Browserbase worker can request HTTP calls while the original Stagehand call is still waiting, matching the Python SDK implementation. **New Features** - Snapshots connection settings, including worker-claimed API key precedence, regional endpoints, and API URL overrides. - Handles Gateway responses plus cache get and set operations, returning buffered responses with headers, errors, and redirects preserved. - Prevents automatic replay of POST requests so the worker keeps retry decisions. - Propagates context cancellation and remaining timeouts through response body reads and closes bodies and idle connections on cleanup. - Registers RPC handlers per request ID, applies cancellation notifications directly without waiting on busy log callbacks, and drops responses issued during or after disposal and disconnect. <sup>Written for commit 880517f. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3207?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3207?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3207&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
…3208) # why this PR connects the worker's model gateway & cache clients to the new RPC transport. aisdk continues to build gateway requests, interpret responses, & decide when to retry # what changed - added a worker adapter that sends `browserbase.request` & reconstructs a native `Response` or the corresponding transport error for existing callers - added cancellable RPC sends using the existing request ID, including cleanup on abort, disconnect, & late replies - routed Gateway requests through the adapter when initialization selects client transport. automatic model selection, explicit headers, & AI SDK retry behavior remain in the worker - routed cache reads & writes through the same adapter. each cache request keeps one five-second budget across serialization, RPC, & HTTP response buffering - preserved direct-provider inference, custom LLM callbacks, batch overrides, & cache failure fallback # test plan - response-adapter tests cover HTTP status & headers, empty bodies, transport errors, cancellation ordering, disconnects, & late replies. - Gateway tests exercise both transports against the same header, response, retry, & backoff expectations. - cache tests cover hits, misses, read/write failures, & the shared timeout budget without adding retries - runtime tests cover ordinary & batch calls, custom callbacks, model overrides, close/drain behavior, & disconnects during inference <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Connects the worker's Browserbase Model Gateway and cache clients to the new RPC transport, so inference and cache HTTP requests are sent by the connected SDK instead of direct HTTP from the worker. - Adds a worker adapter that sends `browserbase.request` over RPC and reconstructs a native `Response` or the matching transport error for existing callers. - Makes RPC sends cancellable via the existing request ID, with cleanup on abort, disconnect, and late replies. - Routes Gateway requests through the adapter when initialization selects client transport; AI SDK retry and backoff behavior, explicit headers, and automatic model selection stay in the worker. - Routes cache reads and writes through the same adapter, keeping one shared five-second budget per request across serialization, RPC, and response buffering. - Preserves direct-provider inference, custom LLM callbacks, batch overrides, and cache failure fallback. - Rebuilds the extension assets bundle, removes duplicated gateway tests, and updates the client/server version compatibility tests. <sup>Written for commit 015eaf9. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3208?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3208?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3208&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why this PR wires the HTTP transport into sdk initialization, so that gateway & cache requests are sent by the connected TS, python, or Go client # what changed - registered bb request handlers before worker initialization in all three SDKs, so requests can run during initialization, ordinary calls, batch, & close - resolved bb connection settings in the SDK. worker initialization now sends transport availability & browser session metadata; public connection options remain accepted & validated by each SDK - preserved browser-factory precedence, regional endpoints, API URL overrides, direct-provider model configuration, & custom callback registration - kept handlers available while the worker finishes active calls, then disposed them on close or failed initialization ### note: the client transports return redirect responses to the worker instead of following them automatically. the previous worker transport followed redirects # test plan - SDK lifecycle tests exercise requests before initialization completes, during batch, & while close is pending, plus cleanup after initialization failure. - real Chromium tests in each SDK cover ordinary & batch Gateway calls, cache hits, custom callbacks, per-call model overrides, & cache failure fallback. - direct-provider configuration is covered alongside a cache hit that skips inference. - local HTTP fixtures verify operation counts, endpoint selection, & session settings without requiring live bb or model services. - compatibility tests cover rejecting a worker that predates this transport & the transitional worker continuing to accept older clients. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Routes Browserbase Model Gateway and cache HTTP requests through the connected TypeScript, Python, and Go SDK clients instead of the worker, so the client's connection is used during initialization, ordinary calls, batch, and close. **Behavior changes** - Each SDK now resolves and validates Browserbase connection settings; worker init receives transport availability and browser session metadata instead of the API key and URL. - Browser-factory key precedence, regional endpoints, API URL overrides, direct-provider model configuration, and custom callbacks are preserved. - Browserbase request handlers stay registered while the worker finishes active calls and are disposed on close or failed initialization. - Client transports return redirect responses to the worker instead of following them; the previous worker transport followed redirects. - API URLs must use an HTTP or HTTPS scheme, include no query string or fragment, and omit a trailing `/v1`. **Compatibility** - Clients now require protocol 2.2.0; older workers are rejected, while a 2.2.0 worker still accepts older clients. <sup>Written for commit fb4a78c. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3209?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3209?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3209&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why this PR makes the connected SDK the only HTTP transport # what changed - removed the worker's direct Gateway/cache HTTP execution & the endpoint helper used by that path - simplified Gateway & cache setup around the client request adapter, removing transport-selection branches & unused context fields - removed top-level `apiKey` & `apiUrl` from worker initialization. the public TypeScript, Python, & Go constructor options still accept them & resolve them in the SDK # test plan - schema & actual RPC initialization tests reject the removed fields while accepting client transport, direct-provider models, & custom model references. - Gateway/cache tests cover client routing, retries, cancellation, cache budgets, & unavailable or disconnected transport without falling back to worker HTTP. - SDK tests verify public connection options remain accepted & incompatible protocol majors are rejected. - cross-SDK Chromium tests exercise the final route with the regenerated extension; generated-model & bundled-asset checks verify the artifacts match. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Makes the connected SDK the only HTTP transport for Browserbase Model Gateway and cache requests by removing the worker's direct HTTP execution path. - Removes the worker's direct Gateway/cache HTTP execution and its endpoint helper, along with top-level `apiKey` and `apiUrl` from worker initialization. - Simplifies Gateway and cache setup around the client request adapter by removing transport-selection branches and unused context fields. Regenerates the Go SDK extension bundle and updates SDK parity checks. - Public TypeScript, Python, and Go constructor options still accept `apiKey` and `apiUrl` and resolve them in the SDK. **Breaking Changes** - Worker protocol now rejects `apiKey` and `apiUrl` init options and bumps to protocol 3.0.0, which incompatible clients and workers reject with `protocol-major-mismatch`. <sup>Written for commit ef3892a. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3210?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3210?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3210&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why to address comments on earlier PRs in this stack # what changed - aligned request-header handling across SDKs. HTTP clients supply host & transfer headers; SDKs supply the Browserbase key & Gateway session header. ordinary application headers remain supported. malformed headers fail before HTTP dispatch, so Go no longer reports them as retryable network failures. - preserved non-ASCII response header bytes in Python so the worker can reconstruct the response without rejecting its headers. - cancelled pending TypeScript Browserbase requests when the browser closes, including when the socket does not deliver another close event. - reused Python HTTP connections across requests on the same RPC connection, closing the pool after pending requests are cancelled during cleanup. - skipped cache request bodies larger than 25 MB (25,000,000 UTF-8 bytes) before sending them over RPC. normal execution continues. an oversized read reports `payload_too_large` & skips the later write; an independently oversized write is skipped without replacing the read's metadata. - reported cache read deadlines as `timeout`, keeping `read_failed` for other failures & preserving cancellation of the user's operation. # test plan - shared header fixtures & local HTTP tests cover filtering, malformed input, preserved application headers, & Python response header decoding. - lifecycle tests cover explicit browser close, cancellation, Python connection reuse, disconnects, & pool cleanup. - cache tests cover the exact size boundary, multibyte UTF-8, skipped reads/writes, normal execution after a skip, timeouts, & caller cancellation. - protocol & SDK tests cover valid initialization, missing browser metadata, removed init fields, & rejection before dispatch. generator checks verify the validation survives regeneration <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Aligns Browserbase HTTP transport behavior across the Go, Python, and TypeScript SDKs so header validation, connection handling, cancellation, and cache error semantics are consistent. Malformed request headers now fail before HTTP dispatch instead of surfacing as retryable network failures, and client Browserbase init params now require browser metadata and reject `api_key` and `api_url` since the browser handle's connection supplies those. **What changed** - SDKs validate request headers and strip host, content-length, hop-by-hop, and forwarding headers; they supply `x-bb-api-key`, and for `gateway.responses` also `x-bb-session-id` and a default `Authorization`. - Python preserves non-ASCII response header bytes as Latin-1 so the worker can reconstruct the response without rejecting its headers. - TypeScript cancels pending Browserbase requests when the browser or context closes, including when the socket never emits a close event; Python reuses one HTTP connection per RPC connection and closes the pool during cleanup. - Cache requests whose serialized body exceeds 25,000,000 UTF-8 bytes are skipped with `payload_too_large`; an independently oversized write is skipped without replacing the read metadata, and cache read timeouts are reported as `timeout` rather than `read_failed`. <sup>Written for commit 1900e78. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3229?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3229?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3229&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
## Why
Stagehand's extension opens its own CDP connection to the browser, and
it is handed the URL the Python client connected with. That only works
when the client and the browser can use the same address.
Sometimes they can't. Our case: the client runs in a server process and
reaches a sandboxed Chrome through an authenticated gateway,
`wss://<gateway>/.../cdp?api_key=...`. The extension, running inside
that Chrome, should dial the browser's local endpoint
(`ws://127.0.0.1:<port>/devtools/browser/<id>`). Using the gateway URL
would hand the gateway's credentials to the browser, which loads
arbitrary pages, and send every extension command out and back in
through the gateway. Today the only workaround is overriding the private
`Stagehand._worker_init_params`.
## What
```python
browser = await local_browser.connect(
cdp_url="wss://gateway/cdp?api_key=...",
extension_cdp_url="ws://127.0.0.1:9300/devtools/browser/<id>",
)
stagehand = await Stagehand.create(browser=browser)
```
- `local_browser.connect` takes an optional `extension_cdp_url`, which
must be a `ws://` or `wss://` URL with a host.
- It is carried on the claimed browser's worker metadata, and
`Stagehand.create` sends it as the init param `browser_cdp_url` in place
of the client's URL.
- When it is unset, behaviour is unchanged.
- Python SDK only, with a minor changeset. The TypeScript SDK has the
same assumption and could take the same option; happy to follow up.
## Tests
- New tests cover the init param, connect carrying the value through,
the default, and rejection of non-WebSocket URLs.
- `ruff format --check`, `ruff check`, `ty check` and `generate.py
--check` pass.
- `pytest`: 793 passed.
`test_official_api_routes_through_and_never_closes_a_caller_http_client`
fails with and without this change in my checkout, because it needs the
extension built in `packages/extension/dist`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an optional `extension_cdp_url` to `local_browser.connect` in the
Python SDK so Stagehand's extension can dial a different CDP WebSocket
than the client's, when the client reaches Chrome through a proxy or
gateway the extension cannot use.
- When set, `Stagehand.create` sends it as the init param
`browser_cdp_url` in place of the client's URL; when unset, behavior is
unchanged.
- The value must be a `ws://` or `wss://` URL with a host; invalid
schemes, ports (including 0), or missing hostnames raise a validation
error.
- Python SDK only, with a minor changeset; the TypeScript SDK could take
the same option in a follow-up.
- New tests cover the init param, metadata carrying the value through,
the default, and rejection of invalid URLs. `pytest` reports 793 passed;
`test_official_api_routes_through_and_never_closes_a_caller_http_client`
fails with and without this change because it needs the extension built
in `packages/extension/dist`.
<sup>Written for commit 48a3789.
Summary will update on new commits.</sup>
<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3252?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3252?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3252&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
---------
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydney@langchain.dev>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ect()` in TS (#3253) # why - this allows users to specify a CDP url that the extension will use for its loopback/in-browser connection # what changed - exposed `extensionCdpUrl` on `localBrowser.connect()` # test plan - added unit tests ensuring the URL gets correctly propagated through the protocol <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds an optional `extensionCdpUrl` param to `localBrowser.connect()` so callers can tell Stagehand's extension which CDP WebSocket to dial. Previously the extension always dialed the same URL the client connected with, which could hand gateway credentials to the browser and route extension traffic through the gateway. When unset, behavior is unchanged. The value must be a `ws://` or `wss://` URL with a host and a port between 1 and 65535; invalid values are rejected with a validation error before any connection is attempted. <sup>Written for commit 9bf9abf. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3253?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3253?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3253&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
#3254) # why - this allows users to specify a CDP url that the extension will use for its loopback/in-browser connection # what changed - exposed `ExtensionCDPURL` in `LocalBrowserConnectOptions` # test plan - added unit tests ensuring the URL gets correctly propagated through the protocol <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds an optional `ExtensionCDPURL` field to `LocalBrowserConnectOptions` in the Go SDK, letting users set the CDP WebSocket URL the extension uses for its in-browser connection independently of the client's CDP URL. When empty, the client's CDP URL is used as before. - Validates `ExtensionCDPURL` is a `ws://` or `wss://` URL with a valid host and port before connecting (including rejecting port `0`). - Propagates the URL to the extension init; falls back to the client's CDP URL when unset. - Includes unit tests for validation and propagation. <sup>Written for commit 32ce206. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3254?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3254?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3254&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why - before this, if a stagehand instance was closed, then recreated, and a CDP url was provided in `localBrowser.connect()`, the provided CDP url would not get used: the extension would keep using the old one # what changed - the extension now stores the CDP URL associated with the extension’s browser connection - the extension will replace the connection when initialization supplies a different URL - it will reuse reuse a connection when the URL matches or is omitted # test plan - added a test that initializes with URL A, closes the Stagehand instance, then initializes with URL B and verifies the old connection closes before the new one opens. - added a test that omits the URL on reinitialization and verifies the existing connection is reused. - added a test that makes connection replacement fail, verifies the runtime stays idle with no connection, then retries successfully. - updated the active-instance test to supply a different URL and verify reinitialization is still rejected <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes the extension keeping a stale browser connection when a Stagehand instance is closed and recreated with a different CDP URL in `localBrowser.connect()`. - The runtime now stores the CDP URL for the active browser connection and, on re-initialization, replaces the connection when the URL differs and reuses it when the URL matches or is omitted. - When replacement fails, the runtime stays idle so re-initialization can be retried. - Adds a changeset and updates the bundled extension assets. <sup>Written for commit 6fe991e. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3257?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3257?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3257&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# what changed - adds an extension cdp url example in browser configuration page <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Documents the `extensionCdpUrl` browser option in the configuration page with TypeScript, Python, and Go examples, showing how to give the extension its own CDP WebSocket URL when the client connects through a proxy or gateway. The examples use a token-based gateway URL, and the docs also cover validation rules and the fallback behavior when the option is omitted. <sup>Written for commit 60b0380. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3259?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3259?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3259&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
) changes pulled in from #3224 , thanks @sydney-runkle for the contrib! ## Why `local_browser.connect` takes only a URL. To reach a CDP endpoint behind an authenticated gateway, the credentials have to go in the query string. URLs leak easily: into exception messages, tracebacks and proxy logs. So callers end up redacting them by hand. Playwright solves this with `connect_over_cdp(..., headers=...)`. ## What ```python browser = await local_browser.connect( cdp_url="https://gateway/.../cdp", headers={"X-Api-Key": "..."}, ) ``` - `headers` are sent with the `/json/version` request and with the CDP WebSocket handshake (`websockets`' `additional_headers`). - They follow the advertised `webSocketDebuggerUrl` only when it's on the same host and port as `cdp_url`, so a gateway can't redirect credentials elsewhere. They're never passed to the extension. - Names must be RFC 9110 tokens, and values may only contain visible characters, spaces and tabs, so CR/LF injection is rejected. `LocalBrowserConnectOptions` sets `hide_input_in_errors` so a rejected credential isn't echoed in the `ValidationError`. - When `headers` is unset, nothing changes: `CDPClient.connect` isn't even passed the argument. - Python SDK only, with a minor changeset. Independent of #3223; the two compose. ## Tests - New tests cover headers on `/json/version`, resolve passing them through, the same-host rule (6 cases), connect forwarding them only when given, and rejection of unsafe names and values without echoing them. - The existing `test_cdp_client` fakes now accept the new keyword argument. - `ruff format --check`, `ruff check`, `ty check` and `generate.py --check` pass. - `pytest`: 798 passed. `test_official_api_routes_through_and_never_closes_a_caller_http_client` fails with and without this change, because it needs the built extension in `packages/extension/dist`. - **Live:** against a LangSmith browser sandbox's CDP gateway, `/json/version` with an `X-Api-Key` header returned a credential-free WebSocket URL, the header-authenticated WebSocket reached Chrome (`Browser.getVersion`), and the same WebSocket without the header was refused. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds optional `headers` to `local_browser.connect` in the Python SDK so callers can authenticate against CDP gateways without putting credentials in the URL. - Headers go to the `/json/version` request and the CDP WebSocket handshake, and only to endpoints on the same host and port as `cdp_url`; redirects off-host or to insecure endpoints are refused rather than followed. Headers are never passed to the extension. - Header names and values are validated against RFC 9110 rules, and validation errors never echo header values since they may be credentials. - Discovery that returns 401 or 403 now fails immediately with a message pointing at gateway credentials instead of retrying. - When `headers` is unset, nothing changes: the keyword argument isn't passed to `CDPClient.connect`, and redirect behavior is unchanged. <sup>Written for commit 564690c. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3260?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3260?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3260&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Sydney Runkle <sydney@langchain.dev> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## why port the Python support from #3260 to TypeScript so callers can authenticate against CDP gateways without putting credentials in the URL ## what ```typescript const browser = await localBrowser.connect({ cdpUrl: "https://gateway/.../cdp", headers: { "X-Api-Key": "..." }, }); ``` Headers are sent with HTTP discovery and the client’s CDP WebSocket handshake. They only reach endpoints on the same host and effective port, without downgrading TLS, and are never passed to the extension. Unsafe HTTP redirects are rejected; Node’s WebSocket transport already rejects redirects. Header validation rejects unsafe names, non-ASCII values, and leading or trailing whitespace without exposing credentials in errors. Discovery fails immediately on HTTP 401/403, and optional debug logging explains when headers are withheld. Includes a minor changeset. ## test plan - Network tests cover HTTP discovery and WebSocket header forwarding, allowed HTTP redirects, blocked redirects, and connections with omitted or empty headers. - Regression tests cover header validation and error redaction, host/port/TLS boundaries, safe diagnostics, immediate 401/403 failures, and retries for transient failures. - Browser factory tests verify headers stay out of extension initialization metadata. - All 159 targeted tests, TypeScript type checking, and lint checks pass. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a `headers` option to TypeScript `localBrowser.connect()`, porting the existing Python support so CDP gateways can be authenticated without putting credentials in the URL. **New Features** - Headers are sent with HTTP discovery and the CDP WebSocket handshake; they only reach endpoints on the same host and effective port, without downgrading transport security. - Unsafe HTTP and WebSocket redirects are rejected, and gateway responses with HTTP 401/403 fail fast with instructions to check credentials. - Header validation rejects invalid names, non-ASCII values, and leading/trailing whitespace. The map is snapshotted once before parsing, so throwing getters and proxy traps never leak header content into validation errors. - Headers are never passed to the extension initialization metadata. <sup>Written for commit 6359b7e. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3263?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3263?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3263&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
## why port the Python support from #3260 to Go so callers can authenticate against CDP gateways without putting credentials in the URL ## what ```go browser, err := stagehand.ConnectLocalBrowser(ctx, stagehand.LocalBrowserConnectOptions{ CDPURL: "https://gateway/.../cdp", Headers: map[string]string{"X-Api-Key": "..."}, }) ``` Headers are sent with HTTP discovery and the client’s CDP WebSocket handshake. They only reach endpoints on the same host and effective port, without downgrading TLS, and are never passed to the extension. Both HTTP and WebSocket redirects are guarded using a copy of the HTTP client, preserving the caller’s settings. Header validation rejects unsafe names, non-ASCII values, and leading or trailing whitespace without exposing credentials in errors. Discovery fails immediately on HTTP 401/403, and debug logging explains when headers are withheld. Includes a minor changeset. ## test plan - Network tests cover discovery and WebSocket header forwarding, allowed and blocked redirects, redirect limits, and connections with nil or empty headers. - Regression tests cover validation, error redaction, host/port/TLS boundaries, safe diagnostics, immediate 401/403 failures, and retries for transient HTTP failures. - Factory tests verify headers are copied from the caller’s map and kept out of extension initialization metadata. Redirect tests verify the caller’s HTTP client and redirect policy are preserved. - Targeted tests pass with the race detector, and `go vet .` passes. The broader `go test ./...` command hits duplicate declarations in the standalone examples directory. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds `Headers` to `LocalBrowserConnectOptions` so Go callers can authenticate against CDP gateways without putting credentials in the URL. - Ports the Python support from #3260 to Go, sending headers with HTTP discovery and the client's CDP WebSocket handshake. - Headers only reach endpoints on the same host and effective port, never downgrading TLS, and are not passed to the extension. - Redirects are guarded using a copy of the HTTP client, preserving caller settings, and URLs are re-validated even if the caller's redirect callback rewrites them; duplicate header names ignoring case are rejected. - 401/403 discovery failures fail immediately, and validation rejects unsafe names, non-ASCII values, and whitespace trim issues without exposing credentials in errors. <sup>Written for commit b1b9938. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3265?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3265?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3265&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# what changed - adds documentation for headers passed into `localBrowser.connect()` <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds documentation for passing authentication headers to `localBrowser.connect()` (TypeScript and Python) and `ConnectLocalBrowser` (Go). - Shows how to pass headers without putting credentials in the connection URL. - Documents that headers are sent with HTTP discovery and the WebSocket connection, only forwarded to the same host and port, and never passed to the extension. - Promotes the "Connecting over CDP" heading so the extension CDP URL anchor link resolves correctly. <sup>Written for commit 0a68a53. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3266?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3266?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3266&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# why Add browser-side function waiting without repeatedly evaluating over the SDK transport. This is PR1 of the `waitForFunction()` stack. Follow-up #3183 targets this branch to register the RPC and expose it in TypeScript, Python, and Go. # what changed - Poll an expression in the main world immediately, then on animation frames or a positive interval; await asynchronous predicates without overlapping calls. - Return a detached JSON value and surface predicate/serialization errors directly. - Reuse the selector-wait handle lifecycle through one shared browser-wait helper, including disposal and late-result cleanup. - Keep one Progress deadline across navigation retries. Timeout zero remains unlimited, but closed pages/transports stop retries. - Distinguish browser predicate exceptions from transient CDP errors so a matching error message never triggers accidental retries. - Refresh the required embedded extension ZIP. No protocol/RPC or public SDK API changes. Reviewed with the requested Thermo-Nuclear Code Quality Review skill: shared resource ownership replaces duplicated cleanup, and browser-side polling stays out of the transport and SDK layers. # test plan - 79 focused extension tests passed, including the existing selector-wait regressions. - Covers async predicates, errors, invalid polling, timeout/late cleanup, context/root-frame replacement, and closure during readiness/retry with timeout zero. - Extension build/typecheck, embedded ZIP regeneration, formatting, and `git diff --check` passed. - Public real-Chrome integration coverage is in the SDK follow-up. --------- Co-authored-by: miguel <miguelg71921@gmail.com>
# why Expose browser-side predicate waiting consistently across Stagehand SDKs, without transport polling. This is PR2 of 2, stacked directly on #3179 (`amel/wait-for-function-extension`). Polling, navigation recovery, and cleanup live in the parent; merge it first using the repository’s stacked-PR handoff rules. # what changed - Register `page.wait_for_function` and connect the extension controller/runtime to the internal implementation. - Add TypeScript `waitForFunction(expression, arg?, options?)`, Python `wait_for_function(expression, *, arg, polling, timeout)`, and Go `WaitForFunction`. As in Playwright, an expression that evaluates to a function is invoked on each poll and receives the optional JSON `arg`. - Preserve JSON result keys through opaque wire metadata, with roundtrip coverage for own `toString`, `constructor`, and `hasOwnProperty` keys in nested payloads. No browser-handle API is introduced. - Provide RAF/interval polling and no deadline by default in all three SDKs; pass `timeout` to bound a wait. An omitted or zero timeout also drops the client response deadline. - Derive internal wait options from the canonical protocol contract. Reuse the TypeScript argument serializer. Model Go’s string-or-number polling option through its existing typed-union generator extension point. - Regenerate protocol/models/final ZIP and include docs plus minor release entries for all five packages. Reviewed with the requested Thermo-Nuclear Code Quality Review skill, including an independent cross-review of SDK boundaries. No SDK polling loops, duplicated serializer, broad generator abstraction, or new 1,000-line file crossing. # test plan - 9 real-Chrome tests passed, including main-world access, async predicates, custom intervals, error propagation, navigation recovery, concurrent waits, and timeout-zero closure. - 79 extension/selector tests and 788 protocol/docs/SDK/architecture guards passed. - 184 Python tests plus Ruff/type checks passed; Go SDK package tests passed. - Follow-up review: 26 wire tests passed; canonical option types emit unchanged JavaScript, and the rebuilt extension ZIP remains identical. - Extension/SDK/protocol typechecks, dependency-ordered build, generated-model/ZIP checks, formatting, lint, and `git diff --check` passed. --------- Co-authored-by: miguel <miguelg71921@gmail.com>
# why - to give users a stable contract for getting the extension archive, instead of reaching into the internals of stagehand & relying on brittle file paths that may change across releases # what changed added an extension archive getter in all three SDKs: - TypeScript: await getExtensionArchive() → Uint8Array - Python: get_extension_archive() → bytes - Go: ExtensionArchive() → []byte # test plan - added tests covering archive contents, extraction, repeatability, and independent buffer <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a public getter for the bundled Stagehand extension archive across all three SDKs, so users no longer need to reach into internal file paths. - TypeScript: `getExtensionArchive()` returns a `Uint8Array`; Python: `get_extension_archive()` returns `bytes`; Go: `ExtensionArchive()` returns `[]byte`. - Tests verify the archive is a valid ZIP, extractable, repeatable, and that mutating a returned copy doesn't corrupt later calls. <sup>Written for commit 6769580. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3267?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3267?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3267&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
# what changed - adds docs for `getExtensionArchive()`, `get_extension_archive()`, `ExtensionArchive()` <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Documents the new extension ZIP export helpers and updates the deployment guide to use them instead of the hardcoded `node_modules` path. - Adds a new "Exporting the Stagehand extension" section covering `getExtensionArchive()`, `get_extension_archive()`, and `ExtensionArchive()`, including upload and local Chrome installation examples. - Updates the deployment guide to export `stagehand-extension.zip` via the SDK helper before uploading. <sup>Written for commit fd9b57b. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3268?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="View guided diff" src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3268?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3268&source=description" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img alt="Turn on auto-fix" src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @browserbasehq/stagehand@4.3.0 ### Minor Changes - [#3267](#3267) [`cb9a1d1`](cb9a1d1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add extension archive getter - [#3253](#3253) [`6bf4146`](6bf4146) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add optional `extensionCdpUrl` to `localBrowser.connect` to allow configuring the in-browser CDP url - [#3263](#3263) [`ecb2a6b`](ecb2a6b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add `headers` to `localBrowser.connect` so CDP gateways can be authenticated without credentials in the URL - [#3183](#3183) [`901eb27`](901eb27) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add `page.waitForFunction()` to wait until a predicate in the page returns a truthy value. ### Patch Changes - [#3229](#3229) [`c6b6f27`](c6b6f27) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip caching for request bodies larger than 25 MB. - [#3198](#3198) [`10418f9`](10418f9) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable WebMCP by default for local chromium versions newer than 157 - [#3210](#3210) [`1c40ba7`](1c40ba7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require client transport for Browserbase Model Gateway and cache requests. - [#3209](#3209) [`17de6ea`](17de6ea) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Route Browserbase Model Gateway and cache requests through the connected SDK. ## @browserbasehq/eve@0.2.2 ### Patch Changes - Updated dependencies [[`c6b6f27`](c6b6f27), [`cb9a1d1`](cb9a1d1), [`10418f9`](10418f9), [`1c40ba7`](1c40ba7), [`17de6ea`](17de6ea), [`6bf4146`](6bf4146), [`ecb2a6b`](ecb2a6b), [`901eb27`](901eb27)]: - @browserbasehq/stagehand@4.3.0 ## @browserbasehq/stagehand-protocol@3.0.0 ### Major Changes - [#3210](#3210) [`1c40ba7`](1c40ba7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require client transport for Browserbase Model Gateway and cache requests. ### Minor Changes - [#3208](#3208) [`4a7c637`](4a7c637) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Support routing Browserbase Model Gateway and cache requests through the connected SDK. - [#3183](#3183) [`901eb27`](901eb27) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add the `page.wait_for_function` method. ## @browserbasehq/stagehand-extension@1.2.0 ### Minor Changes - [#3208](#3208) [`4a7c637`](4a7c637) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Support routing Browserbase Model Gateway and cache requests through the connected SDK. - [#3183](#3183) [`901eb27`](901eb27) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add the `page.wait_for_function` method. ### Patch Changes - [#3229](#3229) [`c6b6f27`](c6b6f27) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip caching for request bodies larger than 25 MB. - [#3257](#3257) [`113ad81`](113ad81) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - honour a changed extension CDP WS URL when creating a new Stagehand instance after closing the previous one - [#3210](#3210) [`1c40ba7`](1c40ba7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require client transport for Browserbase Model Gateway and cache requests. ## @browserbasehq/stagehand-go@4.3.0 ### Minor Changes - [#3267](#3267) [`cb9a1d1`](cb9a1d1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add extension archive getter - [#3265](#3265) [`a31e2da`](a31e2da) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add `Headers` to `LocalBrowserConnectOptions` so CDP gateways can be authenticated without credentials in the URL - [#3254](#3254) [`9eac212`](9eac212) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add optional `ExtensionCDPURL` to `LocalBrowserConnectOptions` to allow configuring the in-browser CDP url. - [#3183](#3183) [`901eb27`](901eb27) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add `Page.WaitForFunction` to wait until a predicate in the page returns a truthy value. ### Patch Changes - [#3229](#3229) [`c6b6f27`](c6b6f27) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip caching for request bodies larger than 25 MB. - [#3198](#3198) [`10418f9`](10418f9) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable WebMCP by default for local chromium versions newer than 157 - [#3210](#3210) [`1c40ba7`](1c40ba7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require client transport for Browserbase Model Gateway and cache requests. - [#3209](#3209) [`17de6ea`](17de6ea) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Route Browserbase Model Gateway and cache requests through the connected SDK. ## @browserbasehq/stagehand-python@4.3.0 ### Minor Changes - [#3260](#3260) [`2859fd5`](2859fd5) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add `headers` to `local_browser.connect` so CDP gateways can be authenticated without credentials in the URL - [#3267](#3267) [`cb9a1d1`](cb9a1d1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add extension archive getter - [#3252](#3252) [`21e0363`](21e0363) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add `extension_cdp_url` to `local_browser.connect` for clients that reach Chrome through a proxy the extension cannot use - [#3183](#3183) [`901eb27`](901eb27) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add `page.wait_for_function()` to wait until a predicate in the page returns a truthy value. ### Patch Changes - [#3229](#3229) [`c6b6f27`](c6b6f27) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip caching for request bodies larger than 25 MB. - [#3198](#3198) [`10418f9`](10418f9) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable WebMCP by default for local chromium versions newer than 157 - [#3210](#3210) [`1c40ba7`](1c40ba7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require client transport for Browserbase Model Gateway and cache requests. - [#3209](#3209) [`17de6ea`](17de6ea) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Route Browserbase Model Gateway and cache requests through the connected SDK. ## @browserbasehq/stagehand-examples@0.0.3 ### Patch Changes - Updated dependencies [[`c6b6f27`](c6b6f27), [`cb9a1d1`](cb9a1d1), [`10418f9`](10418f9), [`1c40ba7`](1c40ba7), [`17de6ea`](17de6ea), [`6bf4146`](6bf4146), [`ecb2a6b`](ecb2a6b), [`901eb27`](901eb27)]: - @browserbasehq/stagehand@4.3.0 - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-example-claude-code-facade@4.0.6 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 - @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.5 ## @browserbasehq/stagehand-integrations-claude-cua-sdk@4.0.4 ### Patch Changes - Updated dependencies [[`c6b6f27`](c6b6f27), [`cb9a1d1`](cb9a1d1), [`10418f9`](10418f9), [`1c40ba7`](1c40ba7), [`17de6ea`](17de6ea), [`6bf4146`](6bf4146), [`ecb2a6b`](ecb2a6b), [`901eb27`](901eb27)]: - @browserbasehq/stagehand@4.3.0 - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-example-codex-facade@4.0.6 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 - @browserbasehq/stagehand-integrations-codex-sdk@4.0.5 ## @browserbasehq/stagehand-integrations-codex-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations@4.0.6 ### Patch Changes - Updated dependencies [[`c6b6f27`](c6b6f27), [`cb9a1d1`](cb9a1d1), [`10418f9`](10418f9), [`1c40ba7`](1c40ba7), [`17de6ea`](17de6ea), [`6bf4146`](6bf4146), [`ecb2a6b`](ecb2a6b), [`901eb27`](901eb27)]: - @browserbasehq/stagehand@4.3.0 ## @browserbasehq/stagehand-integrations-example-cursor-facade@4.0.4 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 - @browserbasehq/stagehand-integrations-cursor-sdk@4.0.5 ## @browserbasehq/stagehand-integrations-cursor-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-deepagents-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-eve-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-fx-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-gemini-cua-sdk@4.0.4 ### Patch Changes - Updated dependencies [[`c6b6f27`](c6b6f27), [`cb9a1d1`](cb9a1d1), [`10418f9`](10418f9), [`1c40ba7`](1c40ba7), [`17de6ea`](17de6ea), [`6bf4146`](6bf4146), [`ecb2a6b`](ecb2a6b), [`901eb27`](901eb27)]: - @browserbasehq/stagehand@4.3.0 - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-example-mastra-facade@4.0.6 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-mastra-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-example-pi-facade@4.0.6 ### Patch Changes - Updated dependencies [[`c6b6f27`](c6b6f27), [`cb9a1d1`](cb9a1d1), [`10418f9`](10418f9), [`1c40ba7`](1c40ba7), [`17de6ea`](17de6ea), [`6bf4146`](6bf4146), [`ecb2a6b`](ecb2a6b), [`901eb27`](901eb27)]: - @browserbasehq/stagehand@4.3.0 - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-pi-sdk@4.0.5 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 ## @browserbasehq/stagehand-integrations-example-vercel-ai-facade@4.0.6 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.6 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
miguelg719
approved these changes
Oct 20, 2026
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by cubic
Brings the production docs branch up to date with
mainahead of the v4.3.0 SDK release.page.waitForFunction(), thegetExtensionArchive()helpers, and theextensionCdpUrl/headersoptions onlocalBrowser.connect().browse cloud searchprovider and mode flags and the newwaitForFunction()migration entries.Written for commit c81d603. Summary will update on new commits.