Repository navigation
feat: expose browser-side function waits across Stagehand SDKs - #3183
Conversation
…nction # Conflicts: # packages/sdk-go/internal/extensionassets/stagehand-extension.zip
🦋 Changeset detectedLatest commit: b545864 The changes in this PR will be included in the next version bump. This PR includes changesets to release 25 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…nction # Conflicts: # packages/sdk-go/internal/extensionassets/stagehand-extension.zip
There was a problem hiding this comment.
1 issue found and verified against the latest diff
Confidence score: 3/5
models.pyrejects integer polling intervals even though the protocol accepts them, so valid requests can fail model validation. Accept strict integers as well as floats while retaining the bounds.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/sdk-python/src/stagehand/_generated/models.py">
<violation number="1" location="packages/sdk-python/src/stagehand/_generated/models.py:2093">
P2: Integer-valued polling intervals fail model validation because `StrictFloat` rejects integers, although the protocol accepts any positive number. Accept strict integers as well as floats while retaining the bounds.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
Invoke expressions that evaluate to a function on each poll, pass the optional JSON argument to function strings (TypeScript and a new Python arg keyword), and default TypeScript waits to no deadline as Playwright does. Python and Go keep Playwright's 30-second default.
There was a problem hiding this comment.
All reported issues were addressed across 12 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
View guided diff | Turn on auto-fix | Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 9 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
Invoke callbacks and bound function strings exactly once per poll, parenthesize bound expressions, keep own __proto__ keys in arguments, pass an explicit Python arg=None as JSON null, and make the navigation recipes cover same-URL reloads and flagged RegExp URLs.
There was a problem hiding this comment.
All reported issues were addressed across 8 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
…nction # Conflicts: # packages/sdk-go/internal/extensionassets/stagehand-extension.zip
…nction # Conflicts: # packages/sdk-go/internal/extensionassets/stagehand-extension.zip
An omitted timeout now means no deadline in the extension and in the TypeScript, Python, and Go clients, instead of 30 seconds outside TypeScript.
# 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>
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>
…nction page.waitForFunction (#3179, #3183) polls in the page and reinstalls its predicate after a navigation, so the quiet wait is one in-page wait per call instead of a page.evaluate round trip every 100 ms. The cap still runs on the host clock, a failed wait sleeps out the rest, and pages without waitForFunction fall back to the plain sleep.
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
page.wait_for_functionand connect the extension controller/runtime to the internal implementation.waitForFunction(expression, arg?, options?), Pythonwait_for_function(expression, *, arg, polling, timeout), and GoWaitForFunction. As in Playwright, an expression that evaluates to a function is invoked on each poll and receives the optional JSONarg.toString,constructor, andhasOwnPropertykeys in nested payloads. No browser-handle API is introduced.timeoutto bound a wait. An omitted or zero timeout also drops the client response deadline.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
git diff --checkpassed.