Migrate all Stagehand templates to V4 - #101
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub. |
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5f7ce32. Configure here.
| 3. Run `go mod download`. | ||
| 4. Run `go run .`. | ||
|
|
||
| The V4 Go SDK is temporarily pinned to an exact Stagehand source commit. Replace it with the published V4 Go module once that package is released. |
There was a problem hiding this comment.
Fast-follow: fix upstream Stagehand V4 Go release tagging
There was a problem hiding this comment.
Addressed in 8c89b3f — switched go.mod and imports to the published github.com/browserbase/stagehand/packages/sdk-go/v4 v4.0.2, refreshed go.sum, and removed the temporary README warning. go test ./... and the real Hacker News entrypoint both pass.
| input=upload_response, | ||
| instructions=instructions, | ||
| settings=settings, | ||
| response = await asyncio.to_thread( |
There was a problem hiding this comment.
Shouldn't this use stagehand.extract instead of a direct API call?
There was a problem hiding this comment.
Clarified in 8c89b3f by renaming this to reducto_client. This call is intentionally Reducto's PDF extraction API after the file has been downloaded; stagehand.extract extracts from the active browser page and would remove the template's Reducto workflow. The complete Browserbase download → PDF → Reducto result passed 3/3.
| ) -> int: | ||
| started = time.monotonic() | ||
| while time.monotonic() - started < retry_for_seconds: | ||
| response = await asyncio.to_thread(client.sessions.downloads.list, session_id) |
There was a problem hiding this comment.
Check if there is a more idiomatic way to interact with our downloads API
There was a problem hiding this comment.
Addressed in 8c89b3f — Python now uses AsyncBrowserbase with the typed await api.sessions.downloads.list(session_id) ZIP endpoint and await response.read(). No raw HTTP or explicit API URL is needed. The updated path passed 3/3 live runs with a real PDF in each ZIP.
|
|
||
| SERVER_NAME = "stagehand_browser" | ||
|
|
||
| STAGEHAND_DEEPAGENTS_SOURCE = ( |
There was a problem hiding this comment.
Fast follow: publish codemode MCP so that external integrations (like templates or eve external PR) can consume it without having to pin to a GitHub commit / repo
There was a problem hiding this comment.
Agreed as an upstream fast-follow. There is not yet a published codemode MCP package for this template to consume, so this PR retains the reviewed source dependency until that first-class package exists; no additional template-side workaround is warranted.
| tools=tools, | ||
| system_prompt=( | ||
| BROWSER_INSTRUCTIONS | ||
| + "\nUse no more than eight browser-tool calls. Once you find the exact record, " |
There was a problem hiding this comment.
Have we empirically checked that specifying the tool calls in-context is followed or actually affects the MCP run? Furthermore, does specifying to return the structured response immediately also have the same outcome? If not, we should remove both instructions
There was a problem hiding this comment.
Addressed in 78e6d02 — removed both the eight-tool-call limit and the “return immediately” clause. The simpler prompt passed 3/3 live runs, and an external validator matched every returned field against the current official SF Open Data record each time, so those instructions had no demonstrated correctness benefit.
|
|
||
| # Use Stagehand's natural language API to fill the field | ||
| if field.field_type == FieldType.RADIO: | ||
| matched_option = self._match_radio_option(answer, field.options or []) |
There was a problem hiding this comment.
Shouldn't stagehand.act be able to handle this without a heuristic? The _match_radio_option function seems like an unnecessary heuristic that we should abstract away via model inference through stagehand.act
There was a problem hiding this comment.
Addressed in 78e6d02 — removed _match_radio_option entirely. Radio answers now go through semantic stagehand.act; only if the direct action fails at the interaction layer do we use semantic observe → act. A scratch validator passed 3/3 across four conversational answers per run (including “Yes, I have no issues…” and “No, I haven’t…”), and the complete nine-field synthetic submission also passed with the real confirmation page.
| SERVER_NAME = "stagehand_browser" | ||
|
|
||
| STAGEHAND_DEEPAGENTS_SOURCE = ( | ||
| "git+https://github.com/browserbase/stagehand.git@2785d0d1fb9f254a51b9f223f1f1a250094c8e79" |
There was a problem hiding this comment.
This shouldn't need to be pinned to a specific commit hash - we can have it point to stagehand main
There was a problem hiding this comment.
Addressed in 78e6d02 — STAGEHAND_DEEPAGENTS_SOURCE now tracks stagehand@main, matching the other Python Deep Agents templates. A real Gemini CUA run built the integration from current main and completed the two-source eclipse workflow successfully.
| }, | ||
| }); | ||
| const stagehand = await Stagehand.create({ | ||
| browser: browser, | ||
| model: { modelName: "google/gemini-2.5-flash" }, |
There was a problem hiding this comment.
Let's omit model name so we can use Model Router
There was a problem hiding this comment.
Addressed in c87e1c0 — removed the explicit Gemini model so Stagehand uses Model Router. A fresh run forced the Fetch API’s 53-character response into the real browser fallback; routed extract completed and returned structured data. That run also exposed the existing close-socket cleanup race, so cleanup now follows the warning-only guards used by the other templates and the entrypoint exits successfully.
| }); | ||
| const stagehand = await Stagehand.create({ | ||
| browser, | ||
| model: { modelName: "google/gemini-2.5-pro" }, |
There was a problem hiding this comment.
Let's remove model name so we can use Model Router
There was a problem hiding this comment.
Addressed in c87e1c0 — removed the explicit Gemini model so Stagehand uses Model Router. With MAX_LINKS=1, the real homepage link discovery and destination verification completed 3 consecutive routed runs. One earlier routed extraction returned invalid URL values and is recorded in the PR flake section. The Fetch API redesign remains intentionally deferred to a fast follow.

Summary
Stagehand is the SDK for browser agents.
@browserbasehq/stagehand@4.0.0andstagehand==4.0.0for the core SDKsbrowserbase.launch()/localBrowser.launch(),Stagehand.create({ browser }),browser.context, V4{ data, metadata }envelopes,locator(), and explicit Stagehand-then-browser cleanupCompanion PR: browserbase/create-browser-app#40
Agent migration: 12 templates
Eight TypeScript templates use Vercel AI SDK
ToolLoopAgentwith Stagehand code mode's statefulcode_executetool:typescript/agent-with-human-in-looptypescript/browser-agent-demotypescript/business-lookuptypescript/company-address-findertypescript/dynamic-form-fillingtypescript/gemini-3-flashtypescript/gemini-cuatypescript/microsoft-cuaFour Python templates use Deep Agents with the Stagehand integration's stateful browser tools:
python/business-lookuppython/cerebras-docs-checkerpython/company-address-finderpython/gemini-cuaThe Exa TypeScript and Python templates use a smaller direct Stagehand workflow: focused Exa discovery, one role,
act/extract/observe, exact résumé upload mechanics, and a human-review result that never submits.The Go template's removed autonomous
Sessions.Executestep is now an explicit V4Observe→Act→ typedExtractworkflow. Its live output is judged only by the external E2E harness.Package state
@browserbasehq/stagehand@4.0.0stagehand==4.0.054302fc5f13be5ad8e717d8e1388502de22be2eduntil@browserbasehq/stagehand-codemodeis publishedbusiness-lookup,company-address-finder,cerebras-docs-checker, andgemini-cuatrackstagehand/main. Their server dependency is publishedstagehand==4.0.0github.com/browserbase/stagehand/packages/sdk-go/v4@v4.0.2The code-mode Git dependency needs two temporary measures until publication: the pnpm subdirectory selector must be
path:packages/integrations(no leading slash), and pnpm overrides must resolve the upstream monorepo'sworkspace:/catalog:dependencies. These are present in all eight code-mode manifests.Fresh out-of-band 79-entrypoint E2E re-audit — 2026-08-21
Important
This section supersedes every earlier E2E table. Runtime claims use only executions performed in this audit; no historical result is counted.
Review assessment
Ready for human review. The current result set covers all 79 entrypoints: 72 runnable entries pass, zero runnable entries fail, and seven are explicitly blocked by unavailable login credentials or Cerebras quota.
Published head: c87e1c0, tree 08fc487690981454330a636b9d659760a55f090d.
The harness installed and invoked every runnable entrypoint against real services and configured credentials. It ran the complete 79-entrypoint inventory, retained every result, then reran every entrypoint affected by a final min-cut fix. The final set is therefore complete for the published tree, while preserving the original full-run evidence and flake history.
Each entrypoint has a separate scratchpad validator outside the repository. Those validators inspect real output and, where applicable, deterministic external truth or artifacts: current Hacker News titles, ZIP/PDF/image contents, proxy IPs, response URLs, UI/SSE state, and form postconditions. None of this audit judging ships in template code.
Focused review follow-up — 2026-08-21
The inventory counts below remain one result per entrypoint. These additional repetitions specifically test the latest review-driven simplifications on the published head:
/dp/URLs, four-PDF ZIPs, image magic bytes, link reports, and Reducto PDF outputsessions.downloads.listreturned a fresh ZIP containing a PDF; Reducto returned the complete iPhone sales objectsdk-go/v4@v4.0.2go test ./...and the real observe → act → two typed extracts completedstagehand@mainextract; Website Link Tester completed 3 consecutive one-link runs after one initial invalid-URL structured-output missAll 12 “never return an accessibility-tree reference” prompt/schema caveats were removed only after the corresponding entrypoint reached 3/3 with the caveat absent. TypeScript and Python were evaluated independently; no result was inferred across SDKs.
Fresh TypeScript passes (38)
agent-with-human-in-loop, amazon-global-price-comparison, amazon-product-scraping, basic-caching, basic-recaptcha, browser-agent-demo, browserbase-reducto, business-lookup, company-address-finder, company-value-prop-generator, council-events, download-financial-statements, dynamic-form-filling, exa-browserbase, extend-browserbase, form-filling, gemini-3-flash, gemini-cua, getting-started-with-browserbase, gift-finder, google-trends, image-url-download, job-application, license-verification, mfa-handling, microsoft-cua, nurse-verification, playwright-mfa-handling, playwright/basic-recaptcha, playwright/quickstart-playwright, polymarket-research, proxies, proxies-weather, puppeteer/quickstart-puppeteer, sec-filing-research, selenium/quickstart-selenium, smart-fetch-scraper, website-link-tester.
Fresh Python passes (33)
amazon-global-price-comparison, amazon-product-scraping, basic-caching, basic-recaptcha, browserbase-reducto, business-lookup, cartesia-form-filling, company-address-finder, company-value-prop-generator, council-events, download-financial-statements, exa-browserbase, extend-browserbase, form-filling, gemini-cua, getting-started-with-browserbase, gift-finder, google-trends, image-url-download, job-application, license-verification, mfa-handling, nurse-verification, playwright-mfa-handling, playwright/basic-recaptcha, playwright/quickstart-playwright, polymarket-research, proxies, proxies-weather, sec-filing-research, selenium/quickstart-selenium, smart-fetch-scraper, website-link-tester.
Go hackernews: PASS.
Fresh blockers
Do not paste credentials into the PR. Configure them through managed Coder User Secrets if fresh coverage of those paths is required.
Approved policy audit
The published tree is 79/79 policy-aligned under the full review contract:
The per-entrypoint matrix also checks README/live-site task alignment: 70 entrypoints map to the current public catalog and nine are repository-only. Three public-copy caveats remain transparent: Exa's safe one-role review flow is narrower than “apply at scale”; Gemini CUA pages still use older CUA/V3 naming while these templates use V4 code mode; Image URL Download now uses the first-party Fetch API although the site still describes browser-session downloads.
Notable final outcomes
stagehand/main, matching the other Deep Agents templates.Fresh flake record
The complete run observed transient failures rather than hiding them: one empty TypeScript cache observe, one Python Amazon structured parse miss, one TypeScript proxy endpoint fetch failure, one Python link-extraction miss, and cleanup socket failures after successful Form Filling/Polymarket outcomes. Focused reruns also observed one Amazon page-readiness timeout before extraction, intermittent Cartesia direct-click CDP failures, and one routed Website Link Tester extraction containing invalid URLs; the replacement Amazon run passed, Cartesia uses semantic observe → act only after direct semantic act cannot complete the interaction, and Website Link Tester then passed 3 consecutive routed runs. Unchanged reruns or the minimum scoped fixes above passed. Gemini and the Next.js HITL flow showed substantial latency variability; they passed but should not be treated as deterministic-duration examples.
Repository proof
Comparison limitation
A literal fresh V3/V4 runtime A/B was not practical for all 79 entrypoints: some V3 APIs/models are superseded, six flows require unavailable login secrets, one credential is out of quota, and some tasks have consequential side effects. Task intent was compared against origin/dev and the live public catalog. Every runtime claim above comes only from fresh V4 executions in this audit.
Note
High Risk
Repo-wide SDK rewrite (TS/Python/Go) plus new BYO-agent orchestration, MCP/code-mode, and credential model (
AI_GATEWAY_API_KEY). Scope and API-surface change are large even though these are example templates.Overview
Migrates all Stagehand templates (TS, Python, Go) from V3 session APIs to Stagehand V4 (
@browserbasehq/stagehand@4.0.0,stagehand==4.0.0, Gosdk-go/v4@v4.0.2).Lifecycle: examples now
browserbase.launch()/Stagehand.create({ browser }), use{ data, metadata }results, and close Stagehand then the browser. Docs and the root template index point at V4; primitives use Browserbase Model Gateway (BROWSERBASE_API_KEYonly).Agents: V3
agent()/ CUA /Sessions.Executeare gone. Eight TS templates use Vercel AI SDKToolLoopAgent+ Stagehand code mode (code_execute, git-pinned@browserbasehq/stagehand-codemodeuntil publish). Four Python templates use LangChain Deep Agents over MCP (run/snapshot/screenshot) andAI_GATEWAY_API_KEY. Go Hacker News is an explicit Observe → Act → typed Extract flow.Non-agent examples are rewritten to the same V4 primitives (Amazon, caching, reCAPTCHA, Reducto downloads, Cartesia form fill, etc.), with Python requiring 3.11–3.13.
Reviewed by Cursor Bugbot for commit c87e1c0. Bugbot is set up for automated code reviews on this repo. Configure here.