Showing preview only (5,332K chars total). Download the full file or copy to clipboard to get everything.
Repository: browserbase/stagehand
Branch: main
Commit: 2e99c9d9814e
Files: 799
Total size: 4.9 MB
Directory structure:
gitextract_8uatdfoc/
├── .changeset/
│ ├── config.json
│ └── crazy-nights-prove.md
├── .cursorrules
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── actions/
│ │ ├── select-browserbase-region/
│ │ │ └── action.yml
│ │ ├── setup-node-pnpm-turbo/
│ │ │ └── action.yml
│ │ ├── upload-ctrf-report/
│ │ │ └── action.yml
│ │ ├── upload-v8-coverage/
│ │ │ └── action.yml
│ │ └── verify-chromium-launch/
│ │ └── action.yml
│ ├── pull_request_template
│ └── workflows/
│ ├── ci.yml
│ ├── claude.yml
│ ├── external-contributor-pr-approval-handoff.yml
│ ├── external-contributor-pr.yml
│ ├── feature-parity.yml
│ ├── release.yml
│ ├── stagehand-server-v3-release.yml
│ ├── stagehand-server-v3-sea-build.yml
│ ├── stagehand-server-v4-release.yml
│ ├── stagehand-server-v4-sea-build.yml
│ └── stainless.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode/
│ └── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── claude.md
├── eslint.config.mjs
├── package.json
├── packages/
│ ├── README.md
│ ├── cli/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── src/
│ │ │ └── index.ts
│ │ ├── tests/
│ │ │ ├── cli.test.ts
│ │ │ └── mode.test.ts
│ │ ├── tsconfig.json
│ │ ├── tsup.config.ts
│ │ └── vitest.config.ts
│ ├── core/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── examples/
│ │ │ ├── 2048.ts
│ │ │ ├── CHANGELOG.md
│ │ │ ├── actionable_observe_example.ts
│ │ │ ├── agent-custom-tools.ts
│ │ │ ├── agent_stream_example.ts
│ │ │ ├── cua-example.ts
│ │ │ ├── custom_client_aisdk.ts
│ │ │ ├── custom_client_langchain.ts
│ │ │ ├── custom_client_openai.ts
│ │ │ ├── example.ts
│ │ │ ├── external_clients/
│ │ │ │ ├── aisdk.ts
│ │ │ │ ├── customOpenAI.ts
│ │ │ │ └── langchain.ts
│ │ │ ├── form_filling_sensible.ts
│ │ │ ├── google_enter.ts
│ │ │ ├── instructions.ts
│ │ │ ├── integrations/
│ │ │ │ ├── exa.ts
│ │ │ │ └── supabase.ts
│ │ │ ├── mcp.ts
│ │ │ ├── operator-example.ts
│ │ │ ├── oss-cua-example.ts
│ │ │ ├── parameterizeApiKey.ts
│ │ │ ├── persist_logs_example.ts
│ │ │ ├── tsconfig.json
│ │ │ ├── v3/
│ │ │ │ ├── cuaReplay.ts
│ │ │ │ ├── deepLocator.ts
│ │ │ │ ├── dropdown.ts
│ │ │ │ ├── highlight.ts
│ │ │ │ ├── patchright.ts
│ │ │ │ ├── playwright.ts
│ │ │ │ ├── puppeteer.ts
│ │ │ │ ├── recordVideo.ts
│ │ │ │ ├── returnXpath.ts
│ │ │ │ ├── shadowRoot.ts
│ │ │ │ ├── targetedExtract.ts
│ │ │ │ └── v3_agent.ts
│ │ │ ├── v3_example.ts
│ │ │ └── wordle.ts
│ │ ├── lib/
│ │ │ ├── CHANGELOG.md
│ │ │ ├── inference.ts
│ │ │ ├── inferenceLogUtils.ts
│ │ │ ├── logger.ts
│ │ │ ├── modelUtils.ts
│ │ │ ├── prompt.ts
│ │ │ ├── utils.ts
│ │ │ ├── v3/
│ │ │ │ ├── agent/
│ │ │ │ │ ├── AgentClient.ts
│ │ │ │ │ ├── AgentProvider.ts
│ │ │ │ │ ├── AnthropicCUAClient.ts
│ │ │ │ │ ├── GoogleCUAClient.ts
│ │ │ │ │ ├── MicrosoftCUAClient.ts
│ │ │ │ │ ├── OpenAICUAClient.ts
│ │ │ │ │ ├── prompts/
│ │ │ │ │ │ └── agentSystemPrompt.ts
│ │ │ │ │ ├── tools/
│ │ │ │ │ │ ├── README.md
│ │ │ │ │ │ ├── act.ts
│ │ │ │ │ │ ├── ariaTree.ts
│ │ │ │ │ │ ├── braveSearch.ts
│ │ │ │ │ │ ├── browserbaseSearch.ts
│ │ │ │ │ │ ├── click.ts
│ │ │ │ │ │ ├── clickAndHold.ts
│ │ │ │ │ │ ├── dragAndDrop.ts
│ │ │ │ │ │ ├── extract.ts
│ │ │ │ │ │ ├── fillFormVision.ts
│ │ │ │ │ │ ├── fillform.ts
│ │ │ │ │ │ ├── goto.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── keys.ts
│ │ │ │ │ │ ├── navback.ts
│ │ │ │ │ │ ├── screenshot.ts
│ │ │ │ │ │ ├── scroll.ts
│ │ │ │ │ │ ├── think.ts
│ │ │ │ │ │ ├── type.ts
│ │ │ │ │ │ └── wait.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── actionMapping.ts
│ │ │ │ │ ├── captchaSolver.ts
│ │ │ │ │ ├── coordinateNormalization.ts
│ │ │ │ │ ├── cuaKeyMapping.ts
│ │ │ │ │ ├── googleCustomToolHandler.ts
│ │ │ │ │ ├── handleDoneToolCall.ts
│ │ │ │ │ ├── imageCompression.ts
│ │ │ │ │ ├── messageProcessing.ts
│ │ │ │ │ ├── screenshotHandler.ts
│ │ │ │ │ ├── validateExperimentalFeatures.ts
│ │ │ │ │ ├── variables.ts
│ │ │ │ │ └── xpath.ts
│ │ │ │ ├── api.ts
│ │ │ │ ├── cache/
│ │ │ │ │ ├── ActCache.ts
│ │ │ │ │ ├── AgentCache.ts
│ │ │ │ │ ├── CacheStorage.ts
│ │ │ │ │ ├── serverAgentCache.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── cli.js
│ │ │ │ ├── dom/
│ │ │ │ │ ├── a11yScripts/
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── genA11yScripts.ts
│ │ │ │ │ ├── genDomScripts.ts
│ │ │ │ │ ├── genLocatorScripts.ts
│ │ │ │ │ ├── genScreenshotScripts.ts
│ │ │ │ │ ├── global.d.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── locatorScripts/
│ │ │ │ │ │ ├── counts.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── scripts.ts
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── waitForSelector.ts
│ │ │ │ │ │ ├── xpathParser.ts
│ │ │ │ │ │ └── xpathResolver.ts
│ │ │ │ │ ├── piercer.entry.ts
│ │ │ │ │ ├── piercer.runtime.ts
│ │ │ │ │ ├── rerenderMissingShadows.entry.ts
│ │ │ │ │ ├── rerenderMissingShadows.runtime.ts
│ │ │ │ │ └── screenshotScripts/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── resolveMaskRect.ts
│ │ │ │ ├── external_clients/
│ │ │ │ │ ├── aisdk.ts
│ │ │ │ │ └── customOpenAI.ts
│ │ │ │ ├── flowlogger/
│ │ │ │ │ ├── EventEmitter.ts
│ │ │ │ │ ├── EventSink.ts
│ │ │ │ │ ├── EventStore.ts
│ │ │ │ │ ├── FlowLogger.ts
│ │ │ │ │ └── prettify.ts
│ │ │ │ ├── handlers/
│ │ │ │ │ ├── actHandler.ts
│ │ │ │ │ ├── extractHandler.ts
│ │ │ │ │ ├── handlerUtils/
│ │ │ │ │ │ ├── actHandlerUtils.ts
│ │ │ │ │ │ └── timeoutGuard.ts
│ │ │ │ │ ├── observeHandler.ts
│ │ │ │ │ ├── v3AgentHandler.ts
│ │ │ │ │ └── v3CuaAgentHandler.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── launch/
│ │ │ │ │ ├── browserbase.ts
│ │ │ │ │ └── local.ts
│ │ │ │ ├── llm/
│ │ │ │ │ ├── AnthropicClient.ts
│ │ │ │ │ ├── CerebrasClient.ts
│ │ │ │ │ ├── GoogleClient.ts
│ │ │ │ │ ├── GroqClient.ts
│ │ │ │ │ ├── LLMClient.ts
│ │ │ │ │ ├── LLMProvider.ts
│ │ │ │ │ ├── OpenAIClient.ts
│ │ │ │ │ └── aisdk.ts
│ │ │ │ ├── logger.ts
│ │ │ │ ├── mcp/
│ │ │ │ │ ├── connection.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── runtimePaths.ts
│ │ │ │ ├── shutdown/
│ │ │ │ │ ├── cleanupLocal.ts
│ │ │ │ │ ├── supervisor.ts
│ │ │ │ │ └── supervisorClient.ts
│ │ │ │ ├── timeoutConfig.ts
│ │ │ │ ├── types/
│ │ │ │ │ ├── private/
│ │ │ │ │ │ ├── agent.ts
│ │ │ │ │ │ ├── api.ts
│ │ │ │ │ │ ├── cache.ts
│ │ │ │ │ │ ├── evaluator.ts
│ │ │ │ │ │ ├── handlers.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── internal.ts
│ │ │ │ │ │ ├── locator.ts
│ │ │ │ │ │ ├── network.ts
│ │ │ │ │ │ ├── shutdown.ts
│ │ │ │ │ │ ├── shutdownErrors.ts
│ │ │ │ │ │ └── snapshot.ts
│ │ │ │ │ └── public/
│ │ │ │ │ ├── agent.ts
│ │ │ │ │ ├── api.ts
│ │ │ │ │ ├── apiErrors.ts
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── locator.ts
│ │ │ │ │ ├── logs.ts
│ │ │ │ │ ├── methods.ts
│ │ │ │ │ ├── metrics.ts
│ │ │ │ │ ├── model.ts
│ │ │ │ │ ├── options.ts
│ │ │ │ │ ├── page.ts
│ │ │ │ │ ├── screenshotTypes.ts
│ │ │ │ │ └── sdkErrors.ts
│ │ │ │ ├── understudy/
│ │ │ │ │ ├── a11y/
│ │ │ │ │ │ └── snapshot/
│ │ │ │ │ │ ├── a11yTree.ts
│ │ │ │ │ │ ├── activeElement.ts
│ │ │ │ │ │ ├── capture.ts
│ │ │ │ │ │ ├── coordinateResolver.ts
│ │ │ │ │ │ ├── domTree.ts
│ │ │ │ │ │ ├── focusSelectors.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── sessions.ts
│ │ │ │ │ │ ├── treeFormatUtils.ts
│ │ │ │ │ │ └── xpathUtils.ts
│ │ │ │ │ ├── a11yInvocation.ts
│ │ │ │ │ ├── cdp.ts
│ │ │ │ │ ├── consoleMessage.ts
│ │ │ │ │ ├── context.ts
│ │ │ │ │ ├── cookies.ts
│ │ │ │ │ ├── deepLocator.ts
│ │ │ │ │ ├── executionContextRegistry.ts
│ │ │ │ │ ├── fileUploadUtils.ts
│ │ │ │ │ ├── frame.ts
│ │ │ │ │ ├── frameLocator.ts
│ │ │ │ │ ├── frameRegistry.ts
│ │ │ │ │ ├── initScripts.ts
│ │ │ │ │ ├── lifecycleWatcher.ts
│ │ │ │ │ ├── locator.ts
│ │ │ │ │ ├── locatorInvocation.ts
│ │ │ │ │ ├── navigationResponseTracker.ts
│ │ │ │ │ ├── networkManager.ts
│ │ │ │ │ ├── page.ts
│ │ │ │ │ ├── piercer.ts
│ │ │ │ │ ├── response.ts
│ │ │ │ │ ├── screenshotUtils.ts
│ │ │ │ │ └── selectorResolver.ts
│ │ │ │ ├── v3.ts
│ │ │ │ └── zodCompat.ts
│ │ │ └── v3Evaluator.ts
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── build-cjs.ts
│ │ │ ├── build-esm.ts
│ │ │ ├── coverage.ts
│ │ │ ├── gen-version.ts
│ │ │ ├── normalize-v8-coverage.ts
│ │ │ ├── prepare.js
│ │ │ ├── test-core.ts
│ │ │ ├── test-e2e.ts
│ │ │ └── test-utils.ts
│ │ ├── tests/
│ │ │ ├── cache-variables.test.ts
│ │ │ ├── integration/
│ │ │ │ ├── agent-abort-signal.spec.ts
│ │ │ │ ├── agent-cache-self-heal.spec.ts
│ │ │ │ ├── agent-callbacks.spec.ts
│ │ │ │ ├── agent-captcha-autosolve.spec.ts
│ │ │ │ ├── agent-experimental-validation.spec.ts
│ │ │ │ ├── agent-hybrid-mode.spec.ts
│ │ │ │ ├── agent-message-continuation.spec.ts
│ │ │ │ ├── agent-streaming.spec.ts
│ │ │ │ ├── cdp-close-api-region.spec.ts
│ │ │ │ ├── cdp-connection-close.spec.ts
│ │ │ │ ├── cdp-session-detached.spec.ts
│ │ │ │ ├── click-count.spec.ts
│ │ │ │ ├── connect-to-existing-browser.spec.ts
│ │ │ │ ├── context-addInitScript.spec.ts
│ │ │ │ ├── context-extra-http-headers.spec.ts
│ │ │ │ ├── cookies.spec.ts
│ │ │ │ ├── default-page-tracking.spec.ts
│ │ │ │ ├── downloads.spec.ts
│ │ │ │ ├── flowLogger.spec.ts
│ │ │ │ ├── frame-get-location-and-click.spec.ts
│ │ │ │ ├── iframe-ctx-addInitScript-race.spec.ts
│ │ │ │ ├── iframe-ctx-addInitScript.spec.ts
│ │ │ │ ├── keep-alive.child.ts
│ │ │ │ ├── keep-alive.spec.ts
│ │ │ │ ├── keyboard.spec.ts
│ │ │ │ ├── locator-backend-node-id.spec.ts
│ │ │ │ ├── locator-content-methods.spec.ts
│ │ │ │ ├── locator-count-iframe.spec.ts
│ │ │ │ ├── locator-count.spec.ts
│ │ │ │ ├── locator-fill.spec.ts
│ │ │ │ ├── locator-input-methods.spec.ts
│ │ │ │ ├── locator-nth.spec.ts
│ │ │ │ ├── locator-select-option.spec.ts
│ │ │ │ ├── logger-initialization.spec.ts
│ │ │ │ ├── multi-instance-logger.spec.ts
│ │ │ │ ├── nested-div.spec.ts
│ │ │ │ ├── page-addInitScript.spec.ts
│ │ │ │ ├── page-console.spec.ts
│ │ │ │ ├── page-drag-and-drop.spec.ts
│ │ │ │ ├── page-extra-http-headers.spec.ts
│ │ │ │ ├── page-goto-response.spec.ts
│ │ │ │ ├── page-hover.spec.ts
│ │ │ │ ├── page-screenshot.spec.ts
│ │ │ │ ├── page-scroll.spec.ts
│ │ │ │ ├── page-send-cdp.spec.ts
│ │ │ │ ├── perform-understudy-method.spec.ts
│ │ │ │ ├── setinputfiles.spec.ts
│ │ │ │ ├── shadow-iframe-oopif.spec.ts
│ │ │ │ ├── shadow-iframe-spif.spec.ts
│ │ │ │ ├── testUtils.ts
│ │ │ │ ├── text-selector-innermost.spec.ts
│ │ │ │ ├── timeouts.spec.ts
│ │ │ │ ├── user-data-dir.spec.ts
│ │ │ │ ├── v3.config.ts
│ │ │ │ ├── v3.dynamic.config.ts
│ │ │ │ ├── v3.playwright.config.ts
│ │ │ │ ├── wait-for-selector.spec.ts
│ │ │ │ ├── wait-for-timeout.spec.ts
│ │ │ │ └── xpath-for-location-deep.spec.ts
│ │ │ └── unit/
│ │ │ ├── agent-captcha-hooks.test.ts
│ │ │ ├── agent-execution-model.test.ts
│ │ │ ├── api-multiregion.test.ts
│ │ │ ├── browserbase-session-accessors.test.ts
│ │ │ ├── cache-llm-resolution.test.ts
│ │ │ ├── captcha-solver.test.ts
│ │ │ ├── cdp-connection-close.test.ts
│ │ │ ├── context-extra-http-headers.test.ts
│ │ │ ├── cookies.test.ts
│ │ │ ├── flowlogger-capturing-cdp.test.ts
│ │ │ ├── flowlogger-capturing-llm.test.ts
│ │ │ ├── flowlogger-eventstore.test.ts
│ │ │ ├── helpers/
│ │ │ │ └── mockCDPSession.ts
│ │ │ ├── llm-provider.test.ts
│ │ │ ├── model-deprecation.test.ts
│ │ │ ├── model-utils.test.ts
│ │ │ ├── openai-cua-client.test.ts
│ │ │ ├── page-extra-http-headers.test.ts
│ │ │ ├── page-snapshot.test.ts
│ │ │ ├── public-api/
│ │ │ │ ├── export-surface.test.ts
│ │ │ │ ├── llm-and-agents.test.ts
│ │ │ │ ├── public-error-types.test.ts
│ │ │ │ ├── public-types.test.ts
│ │ │ │ ├── runtime-utils.test.ts
│ │ │ │ ├── schema-utils.test.ts
│ │ │ │ ├── timeout-error-types.test.ts
│ │ │ │ ├── tool-type-export.test.ts
│ │ │ │ └── v3-core.test.ts
│ │ │ ├── safety-confirmation.test.ts
│ │ │ ├── snapshot-a11y-resolvers.test.ts
│ │ │ ├── snapshot-a11y-tree-utils.test.ts
│ │ │ ├── snapshot-capture-orchestration.test.ts
│ │ │ ├── snapshot-cbor.test.ts
│ │ │ ├── snapshot-dom-session-builders.test.ts
│ │ │ ├── snapshot-dom-tree-utils.test.ts
│ │ │ ├── snapshot-focus-selectors-utils.test.ts
│ │ │ ├── snapshot-frame-merge.test.ts
│ │ │ ├── snapshot-tree-format-utils.test.ts
│ │ │ ├── snapshot-xpath-utils.test.ts
│ │ │ ├── timeout-handlers.test.ts
│ │ │ ├── understudy-command-exception.test.ts
│ │ │ ├── xpath-parser.test.ts
│ │ │ ├── xpath-resolver.test.ts
│ │ │ └── zod-enum-compatibility.test.ts
│ │ ├── tsconfig.json
│ │ ├── vitest.cjs.config.mjs
│ │ ├── vitest.config.ts
│ │ └── vitest.esm.config.mjs
│ ├── docs/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── docs.json
│ │ ├── language-selector.js
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── runtimePaths.js
│ │ │ └── sync-sdk-docs.js
│ │ ├── snippets/
│ │ │ ├── excalidraw.mdx
│ │ │ └── v3-banner.mdx
│ │ ├── v2/
│ │ │ ├── basics/
│ │ │ │ ├── act.mdx
│ │ │ │ ├── agent.mdx
│ │ │ │ ├── extract.mdx
│ │ │ │ └── observe.mdx
│ │ │ ├── best-practices/
│ │ │ │ ├── agent-fallbacks.mdx
│ │ │ │ ├── build-agent.mdx
│ │ │ │ ├── caching.mdx
│ │ │ │ ├── computer-use.mdx
│ │ │ │ ├── contributing.mdx
│ │ │ │ ├── cost-optimization.mdx
│ │ │ │ ├── deployments.mdx
│ │ │ │ ├── mcp-integrations.mdx
│ │ │ │ ├── playwright-interop.mdx
│ │ │ │ ├── prompting-best-practices.mdx
│ │ │ │ ├── speed-optimization.mdx
│ │ │ │ ├── usecase-observe.mdx
│ │ │ │ ├── user-data.mdx
│ │ │ │ ├── using-multiple-tabs.mdx
│ │ │ │ └── working-with-iframes.mdx
│ │ │ ├── configuration/
│ │ │ │ ├── browser.mdx
│ │ │ │ ├── evals.mdx
│ │ │ │ ├── logging.mdx
│ │ │ │ ├── models.mdx
│ │ │ │ └── observability.mdx
│ │ │ ├── first-steps/
│ │ │ │ ├── ai-rules.mdx
│ │ │ │ ├── installation.mdx
│ │ │ │ ├── introduction.mdx
│ │ │ │ └── quickstart.mdx
│ │ │ ├── integrations/
│ │ │ │ ├── crew-ai/
│ │ │ │ │ ├── configuration.mdx
│ │ │ │ │ └── introduction.mdx
│ │ │ │ ├── langchain/
│ │ │ │ │ ├── configuration.mdx
│ │ │ │ │ └── introduction.mdx
│ │ │ │ ├── mcp/
│ │ │ │ │ ├── configuration.mdx
│ │ │ │ │ ├── introduction.mdx
│ │ │ │ │ ├── setup.mdx
│ │ │ │ │ └── tools.mdx
│ │ │ │ └── vercel/
│ │ │ │ ├── configuration.mdx
│ │ │ │ └── introduction.mdx
│ │ │ └── references/
│ │ │ ├── act.mdx
│ │ │ ├── agent.mdx
│ │ │ ├── extract.mdx
│ │ │ ├── observe.mdx
│ │ │ └── stagehand.mdx
│ │ └── v3/
│ │ ├── basics/
│ │ │ ├── act.mdx
│ │ │ ├── agent.mdx
│ │ │ ├── evals.mdx
│ │ │ ├── extract.mdx
│ │ │ └── observe.mdx
│ │ ├── best-practices/
│ │ │ ├── agent-fallbacks.mdx
│ │ │ ├── caching.mdx
│ │ │ ├── computer-use.mdx
│ │ │ ├── cost-optimization.mdx
│ │ │ ├── deployments.mdx
│ │ │ ├── deterministic-agent.mdx
│ │ │ ├── history.mdx
│ │ │ ├── mcp-integrations.mdx
│ │ │ ├── prompting-best-practices.mdx
│ │ │ ├── speed-optimization.mdx
│ │ │ ├── usecase-observe.mdx
│ │ │ ├── user-data.mdx
│ │ │ └── using-multiple-tabs.mdx
│ │ ├── configuration/
│ │ │ ├── browser.mdx
│ │ │ ├── logging.mdx
│ │ │ ├── models.mdx
│ │ │ └── observability.mdx
│ │ ├── first-steps/
│ │ │ ├── ai-rules.mdx
│ │ │ ├── installation.mdx
│ │ │ ├── introduction.mdx
│ │ │ └── quickstart.mdx
│ │ ├── integrations/
│ │ │ ├── convex/
│ │ │ │ ├── configuration.mdx
│ │ │ │ └── introduction.mdx
│ │ │ ├── crew-ai/
│ │ │ │ ├── configuration.mdx
│ │ │ │ └── introduction.mdx
│ │ │ ├── langchain/
│ │ │ │ ├── configuration.mdx
│ │ │ │ └── introduction.mdx
│ │ │ ├── mcp/
│ │ │ │ ├── configuration.mdx
│ │ │ │ ├── introduction.mdx
│ │ │ │ ├── setup.mdx
│ │ │ │ └── tools.mdx
│ │ │ ├── playwright.mdx
│ │ │ ├── puppeteer.mdx
│ │ │ ├── selenium.mdx
│ │ │ └── vercel/
│ │ │ ├── configuration.mdx
│ │ │ └── introduction.mdx
│ │ ├── migrations/
│ │ │ ├── python.mdx
│ │ │ └── v2.mdx
│ │ ├── references/
│ │ │ ├── act.mdx
│ │ │ ├── agent.mdx
│ │ │ ├── context.mdx
│ │ │ ├── deeplocator.mdx
│ │ │ ├── extract.mdx
│ │ │ ├── locator.mdx
│ │ │ ├── observe.mdx
│ │ │ ├── page.mdx
│ │ │ ├── response.mdx
│ │ │ └── stagehand.mdx
│ │ └── sdk/
│ │ ├── go.mdx
│ │ ├── java.mdx
│ │ ├── python.mdx
│ │ └── ruby.mdx
│ ├── evals/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── args.ts
│ │ ├── assets/
│ │ │ ├── cart.html
│ │ │ └── peeler.html
│ │ ├── browserbaseCleanup.ts
│ │ ├── cli.ts
│ │ ├── datasets/
│ │ │ ├── gaia/
│ │ │ │ └── GAIA_web.jsonl
│ │ │ ├── onlineMind2Web/
│ │ │ │ └── onlineMind2Web.jsonl
│ │ │ ├── webtailbench/
│ │ │ │ └── WebTailBench_data.jsonl
│ │ │ └── webvoyager/
│ │ │ └── WebVoyager_data.jsonl
│ │ ├── env.ts
│ │ ├── evals.config.json
│ │ ├── index.eval.ts
│ │ ├── initV3.ts
│ │ ├── lib/
│ │ │ └── AISdkClientWrapped.ts
│ │ ├── llm_clients/
│ │ │ ├── hn_aisdk.ts
│ │ │ ├── hn_customOpenAI.ts
│ │ │ └── hn_langchain.ts
│ │ ├── logger.ts
│ │ ├── package.json
│ │ ├── run.ts
│ │ ├── runtimePaths.ts
│ │ ├── scoring.ts
│ │ ├── scripts/
│ │ │ ├── build-cli.ts
│ │ │ ├── build-esm.ts
│ │ │ └── test-evals.ts
│ │ ├── suites/
│ │ │ ├── gaia.ts
│ │ │ ├── onlineMind2Web.ts
│ │ │ ├── webtailbench.ts
│ │ │ └── webvoyager.ts
│ │ ├── summary.ts
│ │ ├── taskConfig.ts
│ │ ├── tasks/
│ │ │ ├── agent/
│ │ │ │ ├── alibaba_supplier_search.ts
│ │ │ │ ├── all_recipes.ts
│ │ │ │ ├── amazon_shoes_cart.ts
│ │ │ │ ├── apple_trade_in.ts
│ │ │ │ ├── apple_tv.ts
│ │ │ │ ├── arxiv_gpt_report.ts
│ │ │ │ ├── columbia_tuition.ts
│ │ │ │ ├── flipkart_laptops.ts
│ │ │ │ ├── gaia.ts
│ │ │ │ ├── github.ts
│ │ │ │ ├── github_react_version.ts
│ │ │ │ ├── google_flights.ts
│ │ │ │ ├── google_maps.ts
│ │ │ │ ├── google_maps_2.ts
│ │ │ │ ├── google_maps_3.ts
│ │ │ │ ├── google_shopping.ts
│ │ │ │ ├── hotel_booking.ts
│ │ │ │ ├── hotels_paris_amenities.ts
│ │ │ │ ├── hugging_face.ts
│ │ │ │ ├── iframe_form.ts
│ │ │ │ ├── iframe_form_multiple.ts
│ │ │ │ ├── instacart_organic_bananas.ts
│ │ │ │ ├── kayak.ts
│ │ │ │ ├── kfc_tenders_combo.ts
│ │ │ │ ├── kith.ts
│ │ │ │ ├── made_in_china_supplier.ts
│ │ │ │ ├── nba_trades.ts
│ │ │ │ ├── nvidia_hgx_driver.ts
│ │ │ │ ├── oed_word_search.ts
│ │ │ │ ├── onlineMind2Web.ts
│ │ │ │ ├── radiotimes_tv_schedule.ts
│ │ │ │ ├── redfin_apartment_rental.ts
│ │ │ │ ├── sf_library_card.ts
│ │ │ │ ├── sf_library_card_multiple.ts
│ │ │ │ ├── sign_in.ts
│ │ │ │ ├── steam_games.ts
│ │ │ │ ├── thegamer_opinion_article.ts
│ │ │ │ ├── trailhead_superbadge.ts
│ │ │ │ ├── trivago.ts
│ │ │ │ ├── trustpilot_hr_companies.ts
│ │ │ │ ├── ubereats.ts
│ │ │ │ ├── uniqlo_mens_blazers.ts
│ │ │ │ ├── webmd_audiologist_search.ts
│ │ │ │ ├── webmd_ovulation_calculator.ts
│ │ │ │ ├── webtailbench.ts
│ │ │ │ └── webvoyager.ts
│ │ │ ├── allrecipes.ts
│ │ │ ├── amazon_add_to_cart.ts
│ │ │ ├── apple.ts
│ │ │ ├── arxiv.ts
│ │ │ ├── bidnet.ts
│ │ │ ├── checkboxes.ts
│ │ │ ├── combination_sauce.ts
│ │ │ ├── costar.ts
│ │ │ ├── csr_in_oopif.ts
│ │ │ ├── csr_in_spif.ts
│ │ │ ├── custom_dropdown.ts
│ │ │ ├── dropdown.ts
│ │ │ ├── extract_aigrant_companies.ts
│ │ │ ├── extract_aigrant_targeted.ts
│ │ │ ├── extract_aigrant_targeted_2.ts
│ │ │ ├── extract_apartments.ts
│ │ │ ├── extract_area_codes.ts
│ │ │ ├── extract_baptist_health.ts
│ │ │ ├── extract_capacitor_info.ts
│ │ │ ├── extract_collaborators.ts
│ │ │ ├── extract_csa.ts
│ │ │ ├── extract_geniusee.ts
│ │ │ ├── extract_geniusee_2.ts
│ │ │ ├── extract_github_commits.ts
│ │ │ ├── extract_github_stars.ts
│ │ │ ├── extract_hamilton_weather.ts
│ │ │ ├── extract_jfk_links.ts
│ │ │ ├── extract_jstor_news.ts
│ │ │ ├── extract_memorial_healthcare.ts
│ │ │ ├── extract_nhl_stats.ts
│ │ │ ├── extract_partners.ts
│ │ │ ├── extract_press_releases.ts
│ │ │ ├── extract_professional_info.ts
│ │ │ ├── extract_public_notices.ts
│ │ │ ├── extract_recipe.ts
│ │ │ ├── extract_regulations_table.ts
│ │ │ ├── extract_repo_name.ts
│ │ │ ├── extract_resistor_info.ts
│ │ │ ├── extract_rockauto.ts
│ │ │ ├── extract_single_link.ts
│ │ │ ├── extract_snowshoeing_destinations.ts
│ │ │ ├── extract_staff_members.ts
│ │ │ ├── extract_zillow.ts
│ │ │ ├── google_flights.ts
│ │ │ ├── heal_custom_dropdown.ts
│ │ │ ├── heal_scroll_50.ts
│ │ │ ├── heal_simple_google_search.ts
│ │ │ ├── hidden_input_dropdown.ts
│ │ │ ├── history.ts
│ │ │ ├── homedepot.ts
│ │ │ ├── iframe_form_filling.ts
│ │ │ ├── iframe_hn.ts
│ │ │ ├── iframe_same_proc.ts
│ │ │ ├── iframe_scroll.ts
│ │ │ ├── iframes_nested.ts
│ │ │ ├── imdb_movie_details.ts
│ │ │ ├── instructions.ts
│ │ │ ├── ionwave.ts
│ │ │ ├── ionwave_observe.ts
│ │ │ ├── login.ts
│ │ │ ├── multi_tab.ts
│ │ │ ├── namespace_xpath.ts
│ │ │ ├── nested_iframes_2.ts
│ │ │ ├── next_chunk.ts
│ │ │ ├── no_js_click.ts
│ │ │ ├── nonsense_action.ts
│ │ │ ├── observe_amazon_add_to_cart.ts
│ │ │ ├── observe_github.ts
│ │ │ ├── observe_iframes1.ts
│ │ │ ├── observe_iframes2.ts
│ │ │ ├── observe_simple_google_search.ts
│ │ │ ├── observe_taxes.ts
│ │ │ ├── observe_vantechjournal.ts
│ │ │ ├── observe_yc_startup.ts
│ │ │ ├── oopif_in_csr.ts
│ │ │ ├── oopif_in_osr.ts
│ │ │ ├── os_dropdown.ts
│ │ │ ├── osr_in_oopif.ts
│ │ │ ├── osr_in_spif.ts
│ │ │ ├── panamcs.ts
│ │ │ ├── peeler_complex.ts
│ │ │ ├── prev_chunk.ts
│ │ │ ├── radio_btn.ts
│ │ │ ├── rakuten_jp.ts
│ │ │ ├── sciquest.ts
│ │ │ ├── scroll_50.ts
│ │ │ ├── scroll_75.ts
│ │ │ ├── shadow_dom.ts
│ │ │ ├── simple_google_search.ts
│ │ │ ├── spif_in_csr.ts
│ │ │ ├── spif_in_osr.ts
│ │ │ ├── stock_x.ts
│ │ │ ├── tab_handling.ts
│ │ │ ├── ted_talk.ts
│ │ │ ├── vanta_h.ts
│ │ │ ├── vantechjournal.ts
│ │ │ ├── wichita.ts
│ │ │ └── wikipedia.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── evals.ts
│ │ │ └── screenshotCollector.ts
│ │ ├── utils/
│ │ │ ├── ScreenshotCollector.ts
│ │ │ └── imageResize.ts
│ │ └── utils.ts
│ ├── server-v3/
│ │ ├── CHANGELOG.md
│ │ ├── README.md
│ │ ├── SDK_RELEASE_WORKFLOW.md
│ │ ├── openapi.v3.yaml
│ │ ├── package.json
│ │ ├── scripts/
│ │ │ ├── build-sea.ts
│ │ │ ├── gen-openapi.ts
│ │ │ ├── runtimePaths.ts
│ │ │ └── test-server.ts
│ │ ├── src/
│ │ │ ├── lib/
│ │ │ │ ├── InMemorySessionStore.ts
│ │ │ │ ├── SessionStore.ts
│ │ │ │ ├── auth.ts
│ │ │ │ ├── env.ts
│ │ │ │ ├── errorHandler.ts
│ │ │ │ ├── header.ts
│ │ │ │ ├── logging/
│ │ │ │ │ └── index.ts
│ │ │ │ ├── response.ts
│ │ │ │ ├── sessionStoreManager.ts
│ │ │ │ ├── stream.ts
│ │ │ │ └── utils.ts
│ │ │ ├── routes/
│ │ │ │ ├── healthcheck.ts
│ │ │ │ ├── readiness.ts
│ │ │ │ └── v1/
│ │ │ │ └── sessions/
│ │ │ │ ├── _id/
│ │ │ │ │ ├── act.ts
│ │ │ │ │ ├── agentExecute.ts
│ │ │ │ │ ├── end.ts
│ │ │ │ │ ├── extract.ts
│ │ │ │ │ ├── navigate.ts
│ │ │ │ │ ├── observe.ts
│ │ │ │ │ └── replay.ts
│ │ │ │ └── start.ts
│ │ │ ├── sea-entry.ts
│ │ │ ├── server.ts
│ │ │ └── types/
│ │ │ ├── error.ts
│ │ │ ├── fastify.d.ts
│ │ │ ├── model.ts
│ │ │ └── rrweb.ts
│ │ ├── test/
│ │ │ └── integration/
│ │ │ ├── api-server-cache.test.ts
│ │ │ ├── utils.ts
│ │ │ └── v3/
│ │ │ ├── act.test.ts
│ │ │ ├── agentExecute.test.ts
│ │ │ ├── end.test.ts
│ │ │ ├── extract.test.ts
│ │ │ ├── multiRegion.test.ts
│ │ │ ├── navigate.test.ts
│ │ │ ├── observe.test.ts
│ │ │ ├── replay.test.ts
│ │ │ └── start.test.ts
│ │ ├── tsconfig.json
│ │ ├── tsconfig.tests.json
│ │ └── vitest.config.ts
│ └── server-v4/
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── openapi.v4.yaml
│ ├── package.json
│ ├── scripts/
│ │ ├── build-sea.ts
│ │ ├── gen-openapi.ts
│ │ ├── runtimePaths.ts
│ │ └── test-server.ts
│ ├── src/
│ │ ├── routes/
│ │ │ ├── healthcheck.ts
│ │ │ ├── readiness.ts
│ │ │ └── v4/
│ │ │ ├── browsersession/
│ │ │ │ ├── _id/
│ │ │ │ │ ├── end.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── action/
│ │ │ │ │ ├── _actionId.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── activePage.ts
│ │ │ │ ├── addCookies.ts
│ │ │ │ ├── addInitScript.ts
│ │ │ │ ├── awaitActivePage.ts
│ │ │ │ ├── browserbaseDebugURL.ts
│ │ │ │ ├── browserbaseSessionID.ts
│ │ │ │ ├── browserbaseSessionURL.ts
│ │ │ │ ├── clearCookies.ts
│ │ │ │ ├── configuredViewport.ts
│ │ │ │ ├── connectURL.ts
│ │ │ │ ├── cookies.ts
│ │ │ │ ├── getFullFrameTreeByMainFrameId.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── newPage.ts
│ │ │ │ ├── pages.ts
│ │ │ │ ├── resolvePageByMainFrameId.ts
│ │ │ │ ├── routes.ts
│ │ │ │ ├── setExtraHTTPHeaders.ts
│ │ │ │ └── shared.ts
│ │ │ ├── page/
│ │ │ │ ├── action/
│ │ │ │ │ ├── _actionId.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── addInitScript.ts
│ │ │ │ ├── asProtocolFrameTree.ts
│ │ │ │ ├── click.ts
│ │ │ │ ├── close.ts
│ │ │ │ ├── dragAndDrop.ts
│ │ │ │ ├── enableCursorOverlay.ts
│ │ │ │ ├── evaluate.ts
│ │ │ │ ├── frames.ts
│ │ │ │ ├── getFullFrameTree.ts
│ │ │ │ ├── getOrdinal.ts
│ │ │ │ ├── goBack.ts
│ │ │ │ ├── goForward.ts
│ │ │ │ ├── goto.ts
│ │ │ │ ├── hover.ts
│ │ │ │ ├── keyPress.ts
│ │ │ │ ├── listAllFrameIds.ts
│ │ │ │ ├── mainFrame.ts
│ │ │ │ ├── mainFrameId.ts
│ │ │ │ ├── reload.ts
│ │ │ │ ├── routes.ts
│ │ │ │ ├── screenshot.ts
│ │ │ │ ├── scroll.ts
│ │ │ │ ├── sendCDP.ts
│ │ │ │ ├── setExtraHTTPHeaders.ts
│ │ │ │ ├── setViewportSize.ts
│ │ │ │ ├── shared.ts
│ │ │ │ ├── snapshot.ts
│ │ │ │ ├── targetId.ts
│ │ │ │ ├── title.ts
│ │ │ │ ├── type.ts
│ │ │ │ ├── url.ts
│ │ │ │ ├── waitForLoadState.ts
│ │ │ │ ├── waitForMainLoadState.ts
│ │ │ │ ├── waitForSelector.ts
│ │ │ │ └── waitForTimeout.ts
│ │ │ └── pluginUtils.ts
│ │ ├── schemas/
│ │ │ └── v4/
│ │ │ ├── browserSession.ts
│ │ │ └── page.ts
│ │ ├── sea-entry.ts
│ │ ├── server.ts
│ │ └── types/
│ │ ├── error.ts
│ │ ├── fastify.d.ts
│ │ ├── model.ts
│ │ └── rrweb.ts
│ ├── test/
│ │ └── integration/
│ │ ├── utils.ts
│ │ └── v4/
│ │ ├── browsersession.test.ts
│ │ └── page.test.ts
│ ├── tsconfig.json
│ ├── tsconfig.tests.json
│ └── vitest.config.ts
├── pnpm-workspace.yaml
├── stainless.yml
├── tsconfig.base.json
├── tsconfig.json
└── turbo.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@2.1.1/schema.json",
"commit": false,
"fixed": [],
"linked": [],
"baseBranch": "main",
"updateInternalDependencies": "patch",
"access": "public",
"changelog": [
"@changesets/changelog-github",
{
"repo": "browserbase/stagehand"
}
],
"snapshot": {
"useCalculatedVersion": true,
"prereleaseTemplate": "alpha-{commit}",
"tag": "alpha"
}
}
================================================
FILE: .changeset/crazy-nights-prove.md
================================================
---
"@browserbasehq/stagehand": patch
---
apply user defined toolTimeout to all agent tools (other than wait & think tools)
================================================
FILE: .cursorrules
================================================
# Stagehand Project
This is a project that uses Stagehand V3, a browser automation framework with AI-powered `act`, `extract`, `observe`, and `agent` methods.
The main class can be imported as `Stagehand` from `@browserbasehq/stagehand`.
**Key Classes:**
- `Stagehand`: Main orchestrator class providing `act`, `extract`, `observe`, and `agent` methods
- `context`: A `V3Context` object that manages browser contexts and pages
- `page`: Individual page objects accessed via `stagehand.context.pages()[i]` or created with `stagehand.context.newPage()`
## Initialize
```typescript
import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({
env: "LOCAL", // or "BROWSERBASE"
verbose: 2, // 0, 1, or 2
model: "openai/gpt-4.1-mini", // or any supported model
});
await stagehand.init();
// Access the browser context and pages
const page = stagehand.context.pages()[0];
const context = stagehand.context;
// Create new pages if needed
const page2 = await stagehand.context.newPage();
```
## Act
Actions are called on the `stagehand` instance (not the page). Use atomic, specific instructions:
```typescript
// Act on the current active page
await stagehand.act("click the sign in button");
// Act on a specific page (when you need to target a page that isn't currently active)
await stagehand.act("click the sign in button", { page: page2 });
```
**Important:** Act instructions should be atomic and specific:
- ✅ Good: "Click the sign in button" or "Type 'hello' into the search input"
- ❌ Bad: "Order me pizza" or "Type in the search bar and hit enter" (multi-step)
### Observe + Act Pattern (Recommended)
Cache the results of `observe` to avoid unexpected DOM changes:
```typescript
const instruction = "Click the sign in button";
// Get candidate actions
const actions = await stagehand.observe(instruction);
// Execute the first action
await stagehand.act(actions[0]);
```
To target a specific page:
```typescript
const actions = await stagehand.observe("select blue as the favorite color", {
page: page2,
});
await stagehand.act(actions[0], { page: page2 });
```
## Extract
Extract data from pages using natural language instructions. The `extract` method is called on the `stagehand` instance.
### Basic Extraction (with schema)
```typescript
import { z } from "zod";
// Extract with explicit schema
const data = await stagehand.extract(
"extract all apartment listings with prices and addresses",
z.object({
listings: z.array(
z.object({
price: z.string(),
address: z.string(),
}),
),
}),
);
console.log(data.listings);
```
### Simple Extraction (without schema)
```typescript
// Extract returns a default object with 'extraction' field
const result = await stagehand.extract("extract the sign in button text");
console.log(result);
// Output: { extraction: "Sign in" }
// Or destructure directly
const { extraction } = await stagehand.extract(
"extract the sign in button text",
);
console.log(extraction); // "Sign in"
```
### Targeted Extraction
Extract data from a specific element using a selector:
```typescript
const reason = await stagehand.extract(
"extract the reason why script injection fails",
z.string(),
{ selector: "/html/body/div[2]/div[3]/iframe/html/body/p[2]" },
);
```
### URL Extraction
When extracting links or URLs, use `z.string().url()`:
```typescript
const { links } = await stagehand.extract(
"extract all navigation links",
z.object({
links: z.array(z.string().url()),
}),
);
```
### Extracting from a Specific Page
```typescript
// Extract from a specific page (when you need to target a page that isn't currently active)
const data = await stagehand.extract(
"extract the placeholder text on the name field",
{ page: page2 },
);
```
## Observe
Plan actions before executing them. Returns an array of candidate actions:
```typescript
// Get candidate actions on the current active page
const [action] = await stagehand.observe("Click the sign in button");
// Execute the action
await stagehand.act(action);
```
Observing on a specific page:
```typescript
// Target a specific page (when you need to target a page that isn't currently active)
const actions = await stagehand.observe("find the next page button", {
page: page2,
});
await stagehand.act(actions[0], { page: page2 });
```
## Agent
Use the `agent` method to autonomously execute complex, multi-step tasks.
### Basic Agent Usage
```typescript
const page = stagehand.context.pages()[0];
await page.goto("https://www.google.com");
const agent = stagehand.agent({
model: "google/gemini-2.0-flash",
executionModel: "google/gemini-2.0-flash",
});
const result = await agent.execute({
instruction: "Search for the stock price of NVDA",
maxSteps: 20,
});
console.log(result.message);
```
### Computer Use Agent (CUA)
For more advanced scenarios using computer-use models:
```typescript
const agent = stagehand.agent({
mode: "cua", // Enable Computer Use Agent mode
model: "anthropic/claude-sonnet-4-20250514",
// or "google/gemini-2.5-computer-use-preview-10-2025"
systemPrompt: `You are a helpful assistant that can use a web browser.
Do not ask follow up questions, the user will trust your judgement.`,
});
await agent.execute({
instruction: "Apply for a library card at the San Francisco Public Library",
maxSteps: 30,
});
```
### Agent with Custom Model Configuration
```typescript
const agent = stagehand.agent({
model: {
modelName: "google/gemini-2.5-computer-use-preview-10-2025",
apiKey: process.env.GEMINI_API_KEY,
},
systemPrompt: `You are a helpful assistant.`,
});
```
### Agent with Integrations (MCP/External Tools)
```typescript
const agent = stagehand.agent({
integrations: [`https://mcp.exa.ai/mcp?exaApiKey=${process.env.EXA_API_KEY}`],
systemPrompt: `You have access to the Exa search tool.`,
});
```
## Advanced Features
### DeepLocator (XPath Targeting)
Target specific elements across shadow DOM and iframes:
```typescript
await page
.deepLocator("/html/body/div[2]/div[3]/iframe/html/body/p")
.highlight({
durationMs: 5000,
contentColor: { r: 255, g: 0, b: 0 },
});
```
### Multi-Page Workflows
```typescript
const page1 = stagehand.context.pages()[0];
await page1.goto("https://example.com");
const page2 = await stagehand.context.newPage();
await page2.goto("https://example2.com");
// Act/extract/observe operate on the current active page by default
// Pass { page } option to target a specific page
await stagehand.act("click button", { page: page1 });
await stagehand.extract("get title", { page: page2 });
```
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Detailed descriptions help us resolve faster
title: ''
labels: ''
assignees: ''
---
**Before submitting an issue, please:**
- [ ] Check the [documentation](https://docs.stagehand.dev/) for relevant information
- [ ] Search existing [issues](https://github.com/browserbase/stagehand/issues) to avoid duplicates
## Environment Information
Please provide the following information to help us reproduce and resolve your issue:
**Stagehand:**
- Language/SDK: [TypeScript, Python, MCP…]
- Stagehand version: [e.g., 1.0.0]
**AI Provider:**
- Provider: [e.g., OpenAI, Anthropic, Azure OpenAI]
- Model: [e.g., gpt-4o, claude-sonnet-4-6]
## Issue Description
```
[Describe the current behavior here]
```
### Steps to Reproduce
1.
2.
3.
### Minimal Reproduction Code
```tsx
// Your minimal reproduction code here
import { Stagehand } from '@browserbase/stagehand';
const stagehand = new Stagehand({
// IMPORTANT: include your stagehand config
});
// Steps that reproduce the issue
```
### Error Messages / Log trace
```
[Paste error messages/logs here]
```
### Screenshots / Videos
```
[Attach screenshots or videos here]
```
### Related Issues
Are there any related issues or PRs?
- Related to: #[issue number]
- Duplicate of: #[issue number]
- Blocks: #[issue number]
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Are you willing to contribute to implementing this feature or fix?**
- [ ] Yes, I can submit a PR
- [ ] Yes, but I need guidance
- [ ] No, I cannot contribute at this time
================================================
FILE: .github/actions/select-browserbase-region/action.yml
================================================
name: Select Browserbase region
description: Select a Browserbase region based on a weighted distribution.
inputs:
distribution:
description: Comma-separated region=weight list (e.g. us-west-2=40,us-east-1=20).
required: true
outputs:
region:
description: Selected region.
value: ${{ steps.select.outputs.region }}
runs:
using: composite
steps:
- id: select
shell: bash
run: |
dist="${{ inputs.distribution }}"
if [ -z "$dist" ]; then
echo "BROWSERBASE_REGION_DISTRIBUTION is empty"
exit 1
fi
IFS=',' read -r -a entries <<< "$dist"
total=0
regions=()
weights=()
for entry in "${entries[@]}"; do
region="${entry%%=*}"
weight="${entry#*=}"
region="$(printf '%s' "$region" | tr -d '[:space:]')"
weight="$(printf '%s' "$weight" | tr -d '[:space:]')"
if [ -z "$region" ] || [ -z "$weight" ]; then
echo "Invalid region distribution entry: $entry"
exit 1
fi
if ! [[ "$region" =~ ^[A-Za-z0-9-]+$ ]]; then
echo "Invalid region value: $region"
exit 1
fi
if ! [[ "$weight" =~ ^[0-9]+$ ]]; then
echo "Invalid weight for region $region: $weight"
exit 1
fi
regions+=("$region")
weights+=("$weight")
total=$((total + weight))
done
if [ "$total" -le 0 ]; then
echo "Invalid total weight: $total"
exit 1
fi
roll=$((RANDOM % total))
cumulative=0
chosen=""
for i in "${!regions[@]}"; do
cumulative=$((cumulative + weights[i]))
if [ "$roll" -lt "$cumulative" ]; then
chosen="${regions[i]}"
break
fi
done
if [ -z "$chosen" ]; then
echo "Failed to choose Browserbase region"
exit 1
fi
echo "Selected Browserbase region: $chosen"
echo "region=$chosen" >> "$GITHUB_OUTPUT"
echo "BROWSERBASE_REGION=$chosen" >> "$GITHUB_ENV"
================================================
FILE: .github/actions/setup-node-pnpm-turbo/action.yml
================================================
name: Setup Node, pnpm, and Turbo cache
description: Configure pnpm and Node.js with caching, restore Turbo cache, and install dependencies.
inputs:
node-version:
description: Node.js version to use.
required: false
default: "20.x"
use-prebuilt-artifacts:
description: Whether to download pre-built package from build artifacts.
required: false
default: "true"
restore-turbo-cache:
description: Whether to restore the local .turbo cache.
required: false
default: "true"
runs:
using: composite
steps:
- uses: pnpm/action-setup@v4
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
cache: 'pnpm'
cache-dependency-path: '**/pnpm-lock.yaml'
- name: Restore Turbo cache
if: ${{ inputs.restore-turbo-cache == 'true' }}
uses: actions/cache/restore@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json', 'turbo.json') }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json', 'turbo.json') }}-
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile --prefer-offline
- name: Download build artifacts
if: ${{ inputs.use-prebuilt-artifacts == 'true' }}
uses: actions/download-artifact@v4
with:
name: build-artifacts
path: .
merge-multiple: true
- name: Prepare test output directories
shell: bash
run: |
mkdir -p "${GITHUB_WORKSPACE}/ctrf"
if [ -n "${NODE_V8_COVERAGE:-}" ]; then
mkdir -p "$NODE_V8_COVERAGE"
fi
================================================
FILE: .github/actions/upload-ctrf-report/action.yml
================================================
name: Upload CTRF report
description: Upload CTRF report artifact.
inputs:
name:
description: Report path (used as artifact name when sanitized).
required: true
path:
description: Optional explicit path (defaults to name).
required: false
default: ""
runs:
using: composite
steps:
- name: Normalize inputs
id: normalize
shell: bash
run: |
name="${{ inputs.name }}"
echo "name=${name//\//-}" >> "$GITHUB_OUTPUT"
if [ -n "${{ inputs.path }}" ]; then
echo "path=${{ inputs.path }}" >> "$GITHUB_OUTPUT"
else
echo "path=${{ inputs.name }}" >> "$GITHUB_OUTPUT"
fi
- name: Upload CTRF report artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.normalize.outputs.name }}
# package.json anchors uploaded paths to the repository root.
path: |
package.json
${{ steps.normalize.outputs.path }}
================================================
FILE: .github/actions/upload-v8-coverage/action.yml
================================================
name: Upload V8 coverage
description: Upload V8 coverage artifacts.
inputs:
name:
description: Artifact name.
required: true
path:
description: Coverage path to upload (defaults to name).
required: false
default: ""
runs:
using: composite
steps:
- name: Normalize artifact name
id: normalize
shell: bash
run: |
name="${{ inputs.name }}"
echo "name=${name//\//-}" >> "$GITHUB_OUTPUT"
if [ -n "${{ inputs.path }}" ]; then
echo "path=${{ inputs.path }}" >> "$GITHUB_OUTPUT"
else
echo "path=${{ inputs.name }}" >> "$GITHUB_OUTPUT"
fi
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.normalize.outputs.name }}
# package.json anchors uploaded paths to the repository root.
path: |
package.json
${{ steps.normalize.outputs.path }}
================================================
FILE: .github/actions/verify-chromium-launch/action.yml
================================================
name: Verify Chromium launch
description: Validate that Chromium can start, connect to CDP, and read the page title.
inputs:
chrome-path:
description: Path to Chromium/Chrome binary.
required: false
default: "/usr/bin/chromium"
max-attempts:
description: Number of launch attempts before failing.
required: false
default: "3"
timeout-ms:
description: Milliseconds to wait for DevTools and CDP per attempt.
required: false
default: "30000"
runs:
using: composite
steps:
- shell: bash
run: |
set -euo pipefail
max_attempts="${{ inputs.max-attempts }}"
attempt=1
while [ "$attempt" -le "$max_attempts" ]; do
if [ -n "${{ inputs.chrome-path }}" ]; then
pkill -f "${{ inputs.chrome-path }}" >/dev/null 2>&1 || true
fi
if node - <<'NODE'
const { spawn } = require("node:child_process");
const workspace = process.env.GITHUB_WORKSPACE;
if (workspace) {
process.chdir(workspace);
}
const chrome = "${{ inputs.chrome-path }}";
const timeoutMs = Number("${{ inputs.timeout-ms }}");
const wsPrefix = "DevTools listening on ";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let proc;
let wsUrl;
const waitForWsUrl = async () => {
const deadline = Date.now() + timeoutMs;
while (!wsUrl) {
if (Date.now() > deadline) {
throw new Error(
`❌ Chromium did not expose CDP WS URL within timeout (${timeoutMs}ms)`,
);
}
await sleep(250);
}
return wsUrl;
};
const cleanup = () => {
if (proc && !proc.killed) {
proc.kill("SIGKILL");
}
};
(async () => {
try {
const startTime = Date.now();
const args = [
'--ash-no-nudges',
'--block-new-web-contents',
'--deny-permission-prompts',
'--disable-breakpad',
'--disable-client-side-phishing-detection',
'--disable-component-update',
'--disable-components=AcceptCHFrame,OptimizationHints,ProcessPerSiteUpToMainFrameThreshold,InterestFeedContentSuggestions,CalculateNativeWinOcclusion,BackForwardCache,HeavyAdPrivacyMitigations,LazyFrameLoading,ImprovedCookieControls,PrivacySandboxSettings4,AutofillServerCommunication,CertificateTransparencyComponentUpdater,DestroyProfileOnBrowserClose,CrashReporting,OverscrollHistoryNavigation,InfiniteSessionRestore',
'--disable-datasaver-prompt',
'--disable-default-apps',
'--disable-desktop-notifications',
'--disable-domain-reliability',
'--disable-external-intent-requests',
'--disable-hang-monitor',
'--disable-infobars',
'--disable-notifications',
'--disable-popup-blocking',
'--disable-print-preview',
'--disable-prompt-on-repost',
'--disable-search-engine-choice-screen',
'--disable-session-crashed-bubble',
'--disable-speech-api',
'--disable-speech-synthesis-api',
'--hide-crash-restore-bubble',
'--metrics-recording-only',
'--no-default-browser-check',
'--no-first-run',
'--no-pings',
'--noerrdialogs',
'--safebrowsing-disable-auto-update',
'--silent-debugger-extension-api',
'--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"',
'--suppress-message-center-popups',
"--disable-background-networking",
"--disable-default-apps",
"--disable-dev-shm-usage",
"--disable-extensions",
"--disable-notifications",
"--disable-setuid-sandbox",
"--disable-site-isolation-trials",
"--disable-sync",
"--disable-web-security",
"--headless=new",
"--no-default-browser-check",
"--no-first-run",
"--no-sandbox",
"--no-zygote",
"--password-store=basic",
"--remote-debugging-port=0",
"--test-type=gpu",
"--use-mock-keychain",
"about:blank",
];
proc = spawn(chrome, args, { stdio: ["ignore", "pipe", "pipe"] });
const lineBuffers = { stdout: "", stderr: "" };
const onData = (stream) => (data) => {
const text = data.toString();
if (stream === "stderr") {
process.stderr.write(text);
} else {
process.stdout.write(text);
}
lineBuffers[stream] += text;
const lines = lineBuffers[stream].split(/\r?\n/);
lineBuffers[stream] = lines.pop() ?? "";
for (const line of lines) {
const idx = line.indexOf(wsPrefix);
if (idx === -1) continue;
const rest = line.slice(idx + wsPrefix.length).trim();
const candidate = rest.split(/\s+/)[0];
if (
candidate.startsWith("ws://") ||
candidate.startsWith("wss://")
) {
wsUrl = candidate;
}
}
};
proc.stdout.on("data", onData("stdout"));
proc.stderr.on("data", onData("stderr"));
const url = await waitForWsUrl();
const wsFoundMs = Date.now() - startTime;
const wsFoundSec = (wsFoundMs / 1000).toFixed(2);
const connectStart = Date.now();
const path = require("node:path");
const workspaceRoot = process.env.GITHUB_WORKSPACE || process.cwd();
const playwrightPath = path.join(
workspaceRoot,
"packages/core/node_modules/playwright",
);
console.log(
`✅ CDP Url found after ${wsFoundSec}s, connecting with playwright...`,
);
const { chromium } = require(playwrightPath);
const browser = await chromium.connectOverCDP(url, {
timeout: timeoutMs,
});
const context = browser.contexts()[0];
if (!context) {
throw new Error("❌ No browser context available after CDP connect");
}
const page = context.pages()[0];
if (!page) {
throw new Error("❌ No page available after CDP connect");
}
const remainingMs = timeoutMs - (Date.now() - connectStart);
if (remainingMs <= 0) {
throw new Error(
`❌ CDP connect + verify timed out after ${timeoutMs}ms`,
);
}
const sum = await Promise.race([
page.evaluate("1 + 1"),
new Promise((_, reject) =>
setTimeout(
() =>
reject(
new Error(
`❌ CDP connect + verify timed out after ${timeoutMs}ms`,
),
),
remainingMs,
),
),
]);
if (sum !== 2) {
throw new Error(`❌ Unexpected eval result: ${sum}`);
}
const totalMs = Date.now() - startTime;
const connectMs = Date.now() - connectStart;
const totalSec = (totalMs / 1000).toFixed(2);
const connectSec = (connectMs / 1000).toFixed(2);
console.log(
`✅ Chromium launched in ${wsFoundSec}s and CDP connected in ${connectSec}s (total: ${totalSec}s)`,
);
await browser.close();
cleanup();
process.exit(0);
} catch (err) {
cleanup();
console.error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
})();
NODE
then
if [ "$attempt" -gt 1 ]; then
echo "⚠️ Chromium launch succeeded after ${attempt} attempts; GitHub Actions runner may be constrained."
fi
exit 0
fi
echo "⚠️ Chromium launch attempt ${attempt} failed."
attempt=$((attempt + 1))
sleep 2
done
echo "❌ Failed to launch Chromium before running Stagehand; GitHub Actions runner is likely overloaded."
exit 1
================================================
FILE: .github/pull_request_template
================================================
# why
# what changed
# test plan
================================================
FILE: .github/workflows/ci.yml
================================================
name: Tests
on:
pull_request:
types:
- opened
- synchronize
- labeled
- unlabeled
paths-ignore:
- "packages/docs/**"
permissions:
contents: read
actions: write
env:
BROWSERBASE_FLOW_LOGS: "1"
LLM_MAX_MS: "15000"
EVAL_MODELS: "openai/gpt-4.1,google/gemini-2.0-flash,anthropic/claude-haiku-4-5"
EVAL_AGENT_MODELS: "computer-use-preview-2025-03-11,claude-sonnet-4-6"
EVAL_CATEGORIES: "observe,act,combination,extract,targeted_extract,agent"
EVAL_MAX_CONCURRENCY: 25
EVAL_TRIAL_COUNT: 3
LOCAL_SESSION_LIMIT_PER_E2E_TEST: 2
BROWSERBASE_SESSION_LIMIT_PER_E2E_TEST: 3
BROWSERBASE_REGION_DISTRIBUTION: "us-west-2=30,us-east-1=30,eu-central-1=20,ap-southeast-1=20" # percentage of load for each region when running e2e tests against prod
CHROME_PATH: /usr/bin/chromium # GitHub Actions runners ship with stable Chromium by default
BROWSERBASE_CDP_CONNECT_MAX_MS: "10000"
BROWSERBASE_SESSION_CREATE_MAX_MS: "60000"
PUPPETEER_SKIP_DOWNLOAD: "1"
PLAYWRIGHT_SKIP_DOWNLOAD: "1"
TURBO_TELEMETRY_DISABLED: "1"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
determine-changes:
runs-on: ubuntu-latest
outputs:
core: ${{ steps.filter.outputs.core }}
cli: ${{ steps.filter.outputs.cli }}
evals: ${{ steps.filter.outputs.evals }}
server: ${{ steps.filter.outputs.server }}
docs-only: ${{ steps.filter.outputs.docs-only }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Log GitHub API rate limit
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
headers_file=$(mktemp)
body_file=$(mktemp)
curl -sSL \
-D "$headers_file" \
-o "$body_file" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/rate_limit
cat "$headers_file"
echo ""
cat "$body_file"
remaining=$(jq -r '.rate.remaining' "$body_file")
if [ "$remaining" -eq 0 ]; then
reset_epoch=$(jq -r '.rate.reset' "$body_file")
reset_utc=$(date -u -d "@$reset_epoch" +"%Y-%m-%d %H:%M:%S")
reset_pacific=$(TZ=America/Los_Angeles date -d "@$reset_epoch" +"%Y-%m-%d %H:%M:%S %Z")
echo "Github API rate limited until: ${reset_pacific} (${reset_utc} UTC)" >> "$GITHUB_STEP_SUMMARY"
echo "GitHub API rate limit exhausted."
exit 1
fi
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
core:
- '.github/workflows/ci.yml'
- 'packages/core/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'turbo.json'
cli:
- 'packages/cli/**'
- 'packages/core/**'
- 'package.json'
- 'pnpm-lock.yaml'
evals:
- 'packages/evals/**'
- 'package.json'
- 'pnpm-lock.yaml'
server:
- 'packages/server-v3/**'
- 'packages/server-v4/**'
- 'packages/core/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
- '.github/workflows/ci.yml'
docs-only:
- '**/*.md'
- 'examples/**'
- '!packages/**/*.md'
determine-evals:
needs: [determine-changes]
runs-on: ubuntu-latest
outputs:
skip-all-evals: ${{ steps.check-labels.outputs.skip-all-evals }}
eval-categories: ${{ steps.check-labels.outputs.eval-categories }}
steps:
- id: check-labels
run: |
categories=()
declare -A seen
add_category() {
local category="$1"
if [[ -z "${seen[$category]:-}" ]]; then
categories+=("$category")
seen["$category"]=1
fi
}
emit_categories() {
local json="["
for category in "${categories[@]}"; do
json+="\"${category}\","
done
json="${json%,}"
json+="]"
echo "eval-categories=$json" >> $GITHUB_OUTPUT
}
# Check if skip-evals label is present
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'skip-evals') }}" == "true" ]]; then
echo "skip-evals label found - skipping all evals"
echo "skip-all-evals=true" >> $GITHUB_OUTPUT
emit_categories
exit 0
fi
# Skip evals if only docs/examples changed
if [[ "${{ needs.determine-changes.outputs.docs-only }}" == "true" && "${{ needs.determine-changes.outputs.core }}" == "false" && "${{ needs.determine-changes.outputs.evals }}" == "false" ]]; then
echo "Only docs/examples changed - skipping evals"
echo "skip-all-evals=true" >> $GITHUB_OUTPUT
emit_categories
exit 0
fi
# Check for skip-regression-evals label
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'skip-regression-evals') }}" == "true" ]]; then
echo "skip-regression-evals label found - regression evals will be skipped"
else
echo "Regression evals will run by default"
add_category "regression"
fi
# Check for specific labels
echo "skip-all-evals=false" >> $GITHUB_OUTPUT
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'combination') }}" == "true" ]]; then
add_category "combination"
fi
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'extract') }}" == "true" ]]; then
add_category "extract"
fi
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'act') }}" == "true" ]]; then
add_category "act"
fi
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'observe') }}" == "true" ]]; then
add_category "observe"
fi
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'targeted-extract') }}" == "true" ]]; then
add_category "targeted_extract"
fi
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'agent') }}" == "true" ]]; then
add_category "agent"
fi
emit_categories
run-lint:
name: Lint
runs-on: ubuntu-latest
needs: [run-build]
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
node-version: 20.x
- name: Run Lint
run: pnpm exec turbo run lint
cancel-after-lint-failure:
name: Cancel after lint failure
runs-on: ubuntu-latest
needs: [run-lint]
if: ${{ always() && needs.run-lint.result == 'failure' }}
continue-on-error: true
steps:
- name: Cancel workflow run
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
curl -sSfL -X POST \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/cancel"
run-build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "false"
node-version: 20.x
- name: Run Build
run: pnpm exec turbo run build
- name: Save Turbo cache
if: always()
uses: actions/cache/save@v4
with:
path: .turbo
key: ${{ runner.os }}-turbo-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json', 'turbo.json') }}-${{ github.sha }}
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-artifacts
include-hidden-files: true
# package.json is included to anchor artifact paths at repo root.
path: |
package.json
packages/core/dist/**
packages/core/lib/version.ts
packages/core/lib/dom/build/**
packages/core/lib/v3/dom/build/**
packages/cli/dist/**
packages/evals/dist/**
packages/server-v3/dist/**
packages/server-v3/openapi.v3.yaml
packages/server-v4/dist/**
packages/server-v4/openapi.v4.yaml
retention-days: 1
run-cli-tests:
name: CLI Tests
runs-on: ubuntu-latest
needs: [run-build, determine-changes]
if: needs.determine-changes.outputs.cli == 'true'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- name: Run CLI Tests
run: pnpm exec turbo run test:cli --filter=@browserbasehq/browse-cli
discover-core-tests:
runs-on: ubuntu-latest
needs: [determine-changes]
if: needs.determine-changes.outputs.core == 'true'
outputs:
core-tests: ${{ steps.set-matrix.outputs.core-tests }}
has-core-tests: ${{ steps.set-matrix.outputs.has-core-tests }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "false"
restore-turbo-cache: "false"
- name: Discover core test files
id: set-matrix
run: |
core_json=$(pnpm --filter @browserbasehq/stagehand --silent run test:core -- --list)
echo "core-tests=$core_json" >> $GITHUB_OUTPUT
if [ "$core_json" = "[]" ]; then
echo "has-core-tests=false" >> $GITHUB_OUTPUT
else
echo "has-core-tests=true" >> $GITHUB_OUTPUT
fi
echo "Found core tests: $core_json"
core-unit-tests:
name: core/${{ matrix.test.name }}
runs-on: ubuntu-latest
needs: [run-build, discover-core-tests]
if: needs.discover-core-tests.outputs.has-core-tests == 'true'
env:
STAGEHAND_BROWSER_TARGET: local
STAGEHAND_SERVER_TARGET: local
strategy:
fail-fast: false
max-parallel: 100
matrix:
test: ${{ fromJson(needs.discover-core-tests.outputs.core-tests) }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- name: Run Vitest - ${{ matrix.test.name }}
run: |
pnpm exec turbo run test:core --only --filter=@browserbasehq/stagehand -- "${{ matrix.test.path }}"
- uses: ./.github/actions/upload-ctrf-report
if: always()
with:
name: ctrf/core-unit/${{ matrix.test.name }}.json
- uses: ./.github/actions/upload-v8-coverage
if: always()
with:
name: coverage/core-unit/${{ matrix.test.name }}
discover-server-tests:
runs-on: ubuntu-latest
needs: [determine-changes]
if: needs.determine-changes.outputs.server == 'true'
outputs:
integration-tests: ${{ steps.set-matrix.outputs.integration-tests }}
has-integration-tests: ${{ steps.set-matrix.outputs.has-integration-tests }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "false"
restore-turbo-cache: "false"
- name: Discover server test files
id: set-matrix
run: |
int_json=$(pnpm --filter @browserbasehq/stagehand-server-v3 --silent run test:server -- --list integration)
echo "integration-tests=$int_json" >> $GITHUB_OUTPUT
if [ "$int_json" = "[]" ]; then
echo "has-integration-tests=false" >> $GITHUB_OUTPUT
else
echo "has-integration-tests=true" >> $GITHUB_OUTPUT
fi
echo "Found server integration tests: $int_json"
build-server-sea:
name: Build SEA binary (tests, v3)
uses: ./.github/workflows/stagehand-server-v3-sea-build.yml
needs: [run-build]
with:
matrix: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v3-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v3-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v3-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v3-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v3-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v3-win32-arm64.exe","include_sourcemaps":false},
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v3-linux-x64-sourcemap","include_sourcemaps":true}
]
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
node-version: "20.x"
upload-only-binary: stagehand-server-v3-linux-x64-sourcemap
server-integration-tests:
name: server/v3/integration/${{ matrix.test.name }}
runs-on: ubuntu-latest
needs: [build-server-sea, discover-server-tests, run-build]
if: needs.discover-server-tests.outputs.has-integration-tests == 'true'
strategy:
fail-fast: false
matrix:
test: ${{ fromJson(needs.discover-server-tests.outputs.integration-tests) }}
env:
BB_ENV: local
STAGEHAND_BASE_URL: http://stagehand-api.localhost:3106
STAGEHAND_BROWSER_TARGET: local
STAGEHAND_SERVER_TARGET: sea
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
# Used only for testing /start with env: BROWSERBASE remote browser
BROWSERBASE_API_KEY: ${{ secrets.BROWSERBASE_API_KEY }}
BROWSERBASE_PROJECT_ID: ${{ secrets.BROWSERBASE_PROJECT_ID }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- name: Download SEA binary
uses: actions/download-artifact@v4
with:
name: stagehand-server-v3-linux-x64-sourcemap
path: .
- name: Ensure SEA binary is present and executable
shell: bash
run: |
set -euo pipefail
test -f packages/server-v3/dist/sea/stagehand-server-v3-linux-x64-sourcemap
chmod +x packages/server-v3/dist/sea/stagehand-server-v3-linux-x64-sourcemap
- name: Run server integration test - ${{ matrix.test.name }}
env:
SEA_BINARY_NAME: stagehand-server-v3-linux-x64-sourcemap
run: |
pnpm exec turbo run test:server --only --filter=@browserbasehq/stagehand-server-v3 -- "${{ matrix.test.path }}"
- uses: ./.github/actions/upload-ctrf-report
if: always()
with:
name: ctrf/server-v3-integration/${{ matrix.test.name }}.json
- uses: ./.github/actions/upload-v8-coverage
if: always()
with:
name: coverage/server-v3-integration/${{ matrix.test.name }}
discover-e2e-tests:
runs-on: ubuntu-latest
needs: [determine-changes]
if: needs.determine-changes.outputs.core == 'true'
outputs:
e2e-tests: ${{ steps.set-matrix.outputs.e2e-tests }}
has-e2e-tests: ${{ steps.set-matrix.outputs.has-e2e-tests }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "false"
restore-turbo-cache: "false"
- name: Discover e2e test files
id: set-matrix
run: |
e2e_json=$(pnpm --filter @browserbasehq/stagehand --silent run test:e2e -- --list)
echo "e2e-tests=$e2e_json" >> $GITHUB_OUTPUT
if [ "$e2e_json" = "[]" ]; then
echo "has-e2e-tests=false" >> $GITHUB_OUTPUT
else
echo "has-e2e-tests=true" >> $GITHUB_OUTPUT
fi
echo "Found e2e tests: $e2e_json"
run-e2e-local-tests:
name: e2e/local/${{ matrix.test.name }}
needs: [run-build, discover-e2e-tests]
runs-on: ubuntu-latest
timeout-minutes: 50
if: >
needs.discover-e2e-tests.outputs.has-e2e-tests == 'true' &&
github.event.pull_request.head.repo.full_name == github.repository
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
BROWSERBASE_API_KEY: ${{ secrets.BROWSERBASE_API_KEY }}
BROWSERBASE_PROJECT_ID: ${{ secrets.BROWSERBASE_PROJECT_ID }}
HEADLESS: true
STAGEHAND_BROWSER_TARGET: local
STAGEHAND_SERVER_TARGET: local
strategy:
fail-fast: false
max-parallel: 20
matrix:
test: ${{ fromJson(needs.discover-e2e-tests.outputs.e2e-tests) }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- uses: ./.github/actions/verify-chromium-launch
- name: Run local E2E Tests - ${{ matrix.test.name }}
run: |
pnpm exec turbo run test:e2e --only --filter=@browserbasehq/stagehand -- "${{ matrix.test.path }}"
- uses: ./.github/actions/upload-ctrf-report
if: always()
with:
name: ctrf/e2e-local/${{ matrix.test.name }}.json
- uses: ./.github/actions/upload-v8-coverage
if: always()
with:
name: coverage/e2e-local/${{ matrix.test.name }}
run-e2e-bb-tests:
name: e2e/bb/${{ matrix.test.name }}
needs: [run-build, discover-e2e-tests]
runs-on: ubuntu-latest
timeout-minutes: 50
if: >
needs.discover-e2e-tests.outputs.has-e2e-tests == 'true' &&
github.event.pull_request.head.repo.full_name == github.repository
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
BROWSERBASE_API_KEY: ${{ secrets.BROWSERBASE_API_KEY }}
BROWSERBASE_PROJECT_ID: ${{ secrets.BROWSERBASE_PROJECT_ID }}
HEADLESS: true
STAGEHAND_BROWSER_TARGET: browserbase
STAGEHAND_SERVER_TARGET: local
strategy:
fail-fast: false
max-parallel: 100
matrix:
test: ${{ fromJson(needs.discover-e2e-tests.outputs.e2e-tests) }}
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- name: Select Browserbase region
uses: ./.github/actions/select-browserbase-region
with:
distribution: ${{ env.BROWSERBASE_REGION_DISTRIBUTION }}
- name: Run E2E Tests (browserbase) - ${{ matrix.test.name }}
run: |
pnpm exec turbo run test:e2e --only --filter=@browserbasehq/stagehand -- "${{ matrix.test.path }}"
- uses: ./.github/actions/upload-ctrf-report
if: always()
with:
name: ctrf/e2e-bb/${{ matrix.test.name }}.json
- uses: ./.github/actions/upload-v8-coverage
if: always()
with:
name: coverage/e2e-bb/${{ matrix.test.name }}
run-evals:
name: evals/${{ matrix.category }}
needs: [run-build, determine-evals, run-e2e-bb-tests]
if: >-
${{
always() &&
needs.run-build.result == 'success' &&
needs.determine-evals.result == 'success' &&
needs.run-e2e-bb-tests.result != 'failure' &&
needs.run-e2e-bb-tests.result != 'cancelled' &&
needs.determine-evals.outputs.skip-all-evals != 'true' &&
needs.determine-evals.outputs.eval-categories != '[]'
}}
runs-on: ubuntu-latest
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
category: ${{ fromJson(needs.determine-evals.outputs.eval-categories) }}
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_GENERATIVE_AI_API_KEY: ${{ secrets.GOOGLE_GENERATIVE_AI_API_KEY }}
BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }}
BROWSERBASE_API_KEY: ${{ secrets.BROWSERBASE_API_KEY }}
BROWSERBASE_PROJECT_ID: ${{ secrets.BROWSERBASE_PROJECT_ID }}
STAGEHAND_BROWSER_TARGET: browserbase
STAGEHAND_SERVER_TARGET: local
steps:
- name: Check out repository code
uses: actions/checkout@v4
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- name: Select Browserbase region
uses: ./.github/actions/select-browserbase-region
with:
distribution: ${{ env.BROWSERBASE_REGION_DISTRIBUTION }}
- name: Run Evals - ${{ matrix.category }}
id: run-evals
env:
NODE_V8_COVERAGE: coverage/evals/${{ matrix.category }}
run: |
log_file="$(mktemp)"
set +e
pnpm exec turbo run test:evals --only --filter=@browserbasehq/stagehand-evals -- "${{ matrix.category }}" -t "${EVAL_TRIAL_COUNT}" -c "${EVAL_MAX_CONCURRENCY}" 2>&1 | tee "$log_file"
eval_status=${PIPESTATUS[0]}
set -e
summary_block="$(
awk '
/^=========================SUMMARY=========================$/ { capture=1 }
capture { print }
/^Evaluation summary written to / { capture=0 }
' "$log_file"
)"
if [ -n "$summary_block" ]; then
{
echo "summary_text<<EOF"
echo "$summary_block"
echo "EOF"
} >> "$GITHUB_OUTPUT"
fi
exit "$eval_status"
- name: Log Evals Performance - ${{ matrix.category }}
env:
EVAL_STDOUT_SUMMARY: ${{ steps.run-evals.outputs.summary_text }}
run: |
if [ -n "${EVAL_STDOUT_SUMMARY:-}" ]; then
echo "### Evals Summary (${{ matrix.category }})" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
printf '%s\n' "$EVAL_STDOUT_SUMMARY" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
fi
experimentName=$(jq -r '.experimentName' eval-summary.json)
echo "View results at https://www.braintrust.dev/app/Browserbase/p/stagehand/experiments/${experimentName}"
if [ -f eval-summary.json ]; then
category_score=$(jq ".categories[\"${{ matrix.category }}\"]" eval-summary.json)
echo "${{ matrix.category }} category score: $category_score%"
if (( $(echo "$category_score < 80" | bc -l) )); then
echo "${{ matrix.category }} category score is below 80%. Failing CI."
exit 1
fi
else
echo "Eval summary not found for ${{ matrix.category }} category. Failing CI."
exit 1
fi
- uses: ./.github/actions/upload-ctrf-report
if: always()
with:
name: ctrf/evals/${{ matrix.category }}.json
- uses: ./.github/actions/upload-v8-coverage
if: always()
with:
name: coverage/evals/${{ matrix.category }}
merge-coverage:
name: Code Coverage Report
runs-on: ubuntu-latest
needs:
- core-unit-tests
- run-e2e-local-tests
- run-e2e-bb-tests
- run-evals
- server-integration-tests
# if: always()
if: false
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "true"
restore-turbo-cache: "false"
- name: Download V8 coverage artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
pattern: coverage-*
path: .
merge-multiple: true
- name: Download CTRF artifacts
uses: actions/download-artifact@v4
continue-on-error: true
with:
pattern: ctrf-*
path: .
merge-multiple: true
- name: Generate merged coverage report
run: |
pnpm run coverage:merge
- name: Upload merged coverage report
if: always()
id: upload-coverage-artifact
uses: actions/upload-artifact@v4
with:
name: coverage-merged
# package.json is included to anchor artifact paths at repo root.
path: |
package.json
coverage/merged
- name: Add coverage summary to job summary
if: always()
shell: bash
run: |
echo "### Code Coverage" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
if [ -f coverage/merged/coverage-summary.txt ]; then
echo '```' >> "$GITHUB_STEP_SUMMARY"
cat coverage/merged/coverage-summary.txt >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
else
echo "Coverage summary not available." >> "$GITHUB_STEP_SUMMARY"
fi
if [ -n "${{ steps.upload-coverage-artifact.outputs.artifact-url }}" ]; then
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "[Download full HTML coverage report](${{ steps.upload-coverage-artifact.outputs.artifact-url }})" >> "$GITHUB_STEP_SUMMARY"
fi
- name: Publish merged CTRF report
if: always()
uses: ctrf-io/github-test-reporter@v1
with:
report-path: './ctrf/**/*.json'
summary: true
summary-report: false
summary-delta-report: true
test-report: false
failed-report: false
insights-report: true
flaky-rate-report: true
fail-rate-report: true
slowest-report: true
previous-results-report: true
fetch-previous-results: true
baseline: 1
previous-results-max: 1
max-workflow-runs-to-check: 5
max-previous-runs-to-fetch: 1
upload-artifact: true
artifact-name: ctrf-report-merged
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Compute coverage status metrics
if: always()
id: coverage-status
shell: bash
run: |
set -euo pipefail
shopt -s globstar nullglob
tests_failed=0
ctrf_files=(ctrf/**/*.json)
if [ "${#ctrf_files[@]}" -gt 0 ]; then
tests_failed=$(jq -s '[.[].results.summary.failed // 0] | add' "${ctrf_files[@]}")
fi
total_coverage=0
if [ -f coverage/merged/coverage-summary.txt ]; then
total_coverage=$(awk '/^Lines/ {gsub(/%/,"",$3); print $3}' coverage/merged/coverage-summary.txt)
fi
echo "tests_failed=${tests_failed}" >> "$GITHUB_OUTPUT"
echo "total_coverage=${total_coverage}" >> "$GITHUB_OUTPUT"
- name: Set coverage status
if: always()
continue-on-error: true
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RUN_ID: ${{ github.run_id }}
PULL_NUMBER: ${{ github.event.pull_request.number }}
TESTS_FAILED: ${{ steps.coverage-status.outputs.tests_failed }}
TOTAL_COVERAGE: ${{ steps.coverage-status.outputs.total_coverage }}
run: |
set -euo pipefail
repo="${GITHUB_REPOSITORY}"
sha="${GITHUB_SHA}"
tests_failed="${TESTS_FAILED:-0}"
total_coverage="${TOTAL_COVERAGE:-0}"
state="success"
if [ -n "${PULL_NUMBER:-}" ]; then
target_url="https://github.com/${repo}/pull/${PULL_NUMBER}/checks?check_run_id=${RUN_ID}"
else
target_url="https://github.com/${repo}/actions/runs/${RUN_ID}"
fi
description="non-blocking report: ${tests_failed} tests failed. ${total_coverage}% coverage"
payload=$(jq -n \
--arg state "$state" \
--arg target_url "$target_url" \
--arg description "$description" \
--arg context "Measured coverage" \
'{state: $state, target_url: $target_url, description: $description, context: $context}')
curl -sSfL -X POST \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${repo}/statuses/${sha}" \
-d "$payload"
================================================
FILE: .github/workflows/claude.yml
================================================
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
env:
BROWSERBASE_FLOW_LOGS: "1"
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: write # Required for Claude to read CI results on PRs / rerun actions that failed
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "false"
restore-turbo-cache: "false"
node-version: 20.x
- name: Run Build
run: |
pnpm exec turbo run build
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read
track_progress: true
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
prompt: 'Make sure "turbo run lint" and "turbo run build" pass before pushing and make sure to check present CI status for the branch and fix any easy failures. Prefer using the Github MCP tools over bash for Github operations, fall back to Bash(gh) for anything not supported by the MCP tools.'
branch_prefix: 'claude-'
# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
claude_args: |
--allowed-tools mcp__github_inline_comment__create_inline_comment,Bash,View,Glob,GlobTool,GrepTool,Grep,BatchTool,WebSearch,LS,Edit,MultiEdit,Write,Read
# consider adding in the future:
# - https://github.com/anthropics/claude-code-action/blob/main/examples/test-failure-analysis.yml
# - https://github.com/anthropics/claude-code-action/blob/main/examples/ci-failure-auto-fix.yml
# - https://github.com/anthropics/claude-code-action/blob/main/examples/issue-deduplication.yml
================================================
FILE: .github/workflows/external-contributor-pr-approval-handoff.yml
================================================
name: External Contributor PR Approval Handoff
on:
pull_request_review:
types:
- submitted
permissions:
contents: read
pull-requests: read
jobs:
capture-approved-review:
runs-on: ubuntu-latest
steps:
- name: Write approval handoff payload
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const pr = context.payload.pull_request;
const review = context.payload.review;
const shouldClaim =
review.state === 'approved' &&
pr.head.repo.full_name !== context.payload.repository.full_name;
const payload = {
shouldClaim,
prNumber: pr.number,
reviewer: review.user?.login || '',
reviewId: review.id,
approvedSha: review.commit_id || pr.head.sha,
};
fs.writeFileSync('approval-handoff.json', JSON.stringify(payload));
- name: Upload approval handoff artifact
uses: actions/upload-artifact@v4
with:
name: approved-review
path: approval-handoff.json
retention-days: 1
================================================
FILE: .github/workflows/external-contributor-pr.yml
================================================
name: External Contributor PR
on:
pull_request_target:
types:
- opened
- reopened
- synchronize
- closed
workflow_run:
workflows:
- External Contributor PR Approval Handoff
types:
- completed
permissions:
actions: read
contents: write
pull-requests: write
issues: write
env:
ECPR_LIB: |
(() => {
const LABELS = [
{ name: 'external-contributor', color: '8b949e', description: 'Tracks PRs mirrored from external contributor forks.' },
{ name: 'external-contributor:awaiting-approval', color: 'd29922', description: 'Waiting for a stagehand team member to approve the latest external commit.' },
{ name: 'external-contributor:mirrored', color: '1f6feb', description: 'An internal mirrored PR currently exists for this external contributor PR.' },
{ name: 'external-contributor:stale', color: 'db6d28', description: 'The mirrored PR is stale and waiting for a fresh approval to refresh.' },
{ name: 'external-contributor:completed', color: '2da44e', description: 'The mirrored PR has been merged and the external contributor flow is complete.' },
];
const MANAGED_LABELS = new Set(LABELS.map((label) => label.name));
const MANAGED_COMMENT_AUTHOR = 'github-actions[bot]';
const CLAIM_RE = /<!-- external-contributor-pr:claim owned-pr=(\d+) source-sha=([0-9a-f]{40}) claimer=([A-Za-z0-9-]+) branch=([^ ]+) -->/;
const OWNED_RE = /<!-- external-contributor-pr:owned source-pr=(\d+) source-sha=([0-9a-f]{40}) claimer=([A-Za-z0-9-]+) -->/;
const NOTICE_MARKER = '<!-- external-contributor-pr:notice -->';
const NOTICE_LINES = [
'This PR is from an external contributor and must be approved by a stagehand team member with write access before CI can run.',
'Approving the latest commit mirrors it into an internal PR owned by the approver.',
'If new commits are pushed later, the internal PR stays open but is marked stale until someone approves the latest external commit and refreshes it.',
];
async function ensureLabels(github, context) {
for (const label of LABELS) {
try {
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label.name });
} catch (error) {
if (error.status !== 404) throw error;
try {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label.name,
color: label.color,
description: label.description,
});
} catch (createError) {
if (createError.status !== 422) throw createError;
}
}
}
}
async function listComments(github, context, issueNumber) {
return github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
per_page: 100,
});
}
function isManagedComment(comment) {
return comment.user?.login === MANAGED_COMMENT_AUTHOR;
}
function defaultManagedBranch(prNumber) {
return `external-contributor-pr-${prNumber}`;
}
function sanitizeManagedBranch(prNumber, branch) {
const fallback = defaultManagedBranch(prNumber);
if (!branch) return fallback;
const allowed = new RegExp(`^external-contributor-pr-${prNumber}(?:-[A-Za-z0-9._-]+)?$`);
return allowed.test(branch) ? branch : fallback;
}
async function upsertComment(github, context, issueNumber, marker, lines) {
const comments = await listComments(github, context, issueNumber);
const body = [marker, ...lines].join('\n');
const existing = comments.find((comment) => isManagedComment(comment) && comment.body?.includes(marker));
if (!existing) {
await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issueNumber, body });
return;
}
if (existing.body !== body) {
await github.rest.issues.updateComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: existing.id, body });
}
}
async function syncLabels(github, context, issueNumber, desiredLabels) {
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const existingNames = issue.labels.map((label) => typeof label === 'string' ? label : label.name).filter(Boolean);
const preserved = existingNames.filter((label) => !MANAGED_LABELS.has(label));
await github.rest.issues.setLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: [...preserved, ...desiredLabels],
});
}
async function findLatestClaim(github, context, issueNumber) {
const comments = await listComments(github, context, issueNumber);
return [...comments]
.reverse()
.map((comment) => {
if (!isManagedComment(comment)) return null;
const match = comment.body?.match(CLAIM_RE);
if (!match) return null;
const sourcePrNumber = issueNumber;
return {
ownedPrNumber: Number(match[1]),
sourceSha: match[2],
claimer: match[3],
branch: sanitizeManagedBranch(sourcePrNumber, match[4]),
};
})
.find(Boolean);
}
async function externalLifecycle({ github, context }) {
const pr = context.payload.pull_request;
await ensureLabels(github, context);
if (context.payload.action === 'opened' || context.payload.action === 'reopened') {
await upsertComment(github, context, pr.number, NOTICE_MARKER, NOTICE_LINES);
const latestClaim = await findLatestClaim(github, context, pr.number);
if (context.payload.action === 'reopened' && latestClaim && latestClaim.sourceSha === pr.head.sha) {
const { data: ownedPr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: latestClaim.ownedPrNumber,
});
if (ownedPr.state === 'open') {
await syncLabels(github, context, pr.number, ['external-contributor', 'external-contributor:mirrored']);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: `This external contributor PR is already mirrored to ${ownedPr.html_url}. Closing it again so discussion stays on the internal PR until fresh commits require another approval.`,
});
await github.rest.pulls.update({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number, state: 'closed' });
return;
}
}
await syncLabels(github, context, pr.number, ['external-contributor', 'external-contributor:awaiting-approval']);
return;
}
const latestClaim = await findLatestClaim(github, context, pr.number);
if (!latestClaim || latestClaim.sourceSha === pr.head.sha) return;
const { data: ownedPr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: latestClaim.ownedPrNumber,
});
if (ownedPr.state !== 'open') return;
await syncLabels(github, context, pr.number, ['external-contributor', 'external-contributor:awaiting-approval']);
await syncLabels(github, context, ownedPr.number, ['external-contributor', 'external-contributor:stale']);
await upsertComment(github, context, ownedPr.number, '<!-- external-contributor-pr:owned-status -->', [
`This mirrored PR is stale because the original external contributor PR #${pr.number} received new commits (\`${latestClaim.sourceSha}\` -> \`${pr.head.sha}\`).`,
`Original PR: ${pr.html_url}`,
'',
'Approve the latest external commit to refresh this same internal PR in place.',
]);
if (pr.state === 'closed') {
await github.rest.pulls.update({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.number, state: 'open' });
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ownedPr.number,
body: `New commits landed on external contributor PR #${pr.number} (\`${latestClaim.sourceSha}\` -> \`${pr.head.sha}\`). This mirrored PR stays open but is now stale until the latest external commit is approved and copied over.`,
});
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: `New commits were pushed to this external contributor PR (\`${latestClaim.sourceSha}\` -> \`${pr.head.sha}\`). The mirrored PR ${ownedPr.html_url} remains open but is marked stale. A stagehand team member with write access must approve the latest commit to refresh that internal PR.`,
});
}
async function prepareClaim({ github, context, core, artifactPath }) {
const fs = require('fs');
const handoff = JSON.parse(fs.readFileSync(artifactPath, 'utf8'));
core.setOutput('should-claim', 'false');
if (!handoff.shouldClaim || !handoff.prNumber || !handoff.reviewer || !handoff.approvedSha) return;
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: Number(handoff.prNumber),
});
if (pr.head.repo.full_name === context.payload.repository.full_name || pr.state !== 'open') return;
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: handoff.reviewer,
});
if (!new Set(['admin', 'maintain', 'write']).has(permission.permission)) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: `@${handoff.reviewer} submitted an approving review, but only stagehand team members with write access can claim external contributor PRs. A maintainer with write access must approve the latest commit to proceed.`,
});
return;
}
if (pr.head.sha !== handoff.approvedSha) return;
const latestClaim = await findLatestClaim(github, context, pr.number);
const branch = sanitizeManagedBranch(pr.number, latestClaim?.branch);
const title = `[Claimed #${pr.number}] ${pr.title}`;
const body = [
`Mirrored from external contributor PR #${pr.number} after approval by @${handoff.reviewer}.`,
'',
`Original author: @${pr.user.login}`,
`Original PR: ${pr.html_url}`,
`Approved source head SHA: \`${pr.head.sha}\``,
'',
`@${pr.user.login}, 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',
pr.body?.trim() || '_No description provided._',
'',
`<!-- external-contributor-pr:owned source-pr=${pr.number} source-sha=${pr.head.sha} claimer=${handoff.reviewer} -->`,
].join('\n');
const { data: ownedPrs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
head: `${context.repo.owner}:${branch}`,
base: 'main',
per_page: 100,
});
core.setOutput('should-claim', 'true');
core.setOutput('claimer', handoff.reviewer);
core.setOutput('pr-number', String(pr.number));
core.setOutput('source-sha', pr.head.sha);
core.setOutput('previous-source-sha', latestClaim?.sourceSha || '');
core.setOutput('branch', branch);
core.setOutput('title', title);
core.setOutput('body', body);
core.setOutput('owned-pr-number', ownedPrs[0] ? String(ownedPrs[0].number) : '');
core.setOutput('owned-pr-merged', ownedPrs[0]?.merged_at ? 'true' : 'false');
}
async function finalizeClaim({ github, context, input }) {
await ensureLabels(github, context);
const {
prNumber,
sourceSha,
branch,
claimer,
title,
body,
existingNumber,
existingMerged,
refreshStatus,
refreshReason,
} = input;
if (refreshStatus !== 'updated') {
if (existingNumber) {
await syncLabels(github, context, Number(existingNumber), ['external-contributor', 'external-contributor:stale']);
await upsertComment(github, context, Number(existingNumber), '<!-- external-contributor-pr:owned-status -->', [
`This mirrored PR could not be refreshed automatically after approval by @${claimer}.`,
'',
`Refresh reason: \`${refreshReason || 'unknown'}\``,
'Resolve the branch manually, then keep using this same mirrored PR.',
]);
}
await syncLabels(github, context, prNumber, ['external-contributor', 'external-contributor:awaiting-approval']);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `The latest approval by @${claimer} could not refresh the mirrored PR automatically (${refreshReason || 'unknown reason'}). The external PR stays open, and the mirrored PR should be updated manually before work continues.`,
});
return;
}
let ownedPr;
if (existingNumber && !existingMerged) {
const { data } = await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: Number(existingNumber),
title,
body,
base: 'main',
state: 'open',
});
ownedPr = data;
} else {
const { data } = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
head: branch,
base: 'main',
});
ownedPr = data;
}
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ownedPr.number,
assignees: [claimer],
});
await syncLabels(github, context, prNumber, ['external-contributor', 'external-contributor:mirrored']);
await syncLabels(github, context, ownedPr.number, ['external-contributor', 'external-contributor:mirrored']);
await upsertComment(github, context, ownedPr.number, '<!-- external-contributor-pr:owned-status -->', [
`This mirrored PR tracks external contributor PR #${prNumber} at source SHA \`${sourceSha}\`, approved by @${claimer}.`,
`Original PR: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/pull/${prNumber}`,
'',
'When the external PR gets new commits, this same internal PR will be refreshed in place after the latest external commit is approved.',
]);
const marker = `<!-- external-contributor-pr:claim owned-pr=${ownedPr.number} source-sha=${sourceSha} claimer=${claimer} branch=${branch} -->`;
const comments = await listComments(github, context, prNumber);
if (!comments.some((comment) => comment.body?.includes(marker))) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: [marker, `This PR was approved by @${claimer} and mirrored to ${ownedPr.html_url}. All further discussion should happen on that PR.`].join('\n'),
});
}
const { data: externalPr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
if (externalPr.state !== 'closed') {
await github.rest.pulls.update({ owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber, state: 'closed' });
}
}
async function syncOwnedPr({ github, context }) {
const pr = context.payload.pull_request;
const match = pr.body?.match(OWNED_RE);
if (!match) return;
const sourcePrNumber = Number(match[1]);
const sourceSha = match[2];
await ensureLabels(github, context);
const { data: externalPr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: sourcePrNumber,
});
if (context.payload.action === 'reopened') {
await syncLabels(github, context, pr.number, ['external-contributor', 'external-contributor:mirrored']);
await syncLabels(github, context, sourcePrNumber, ['external-contributor', 'external-contributor:mirrored']);
if (externalPr.state !== 'closed') {
await github.rest.pulls.update({ owner: context.repo.owner, repo: context.repo.repo, pull_number: sourcePrNumber, state: 'closed' });
}
return;
}
if (pr.merged) {
await syncLabels(github, context, pr.number, ['external-contributor', 'external-contributor:completed']);
await syncLabels(github, context, sourcePrNumber, ['external-contributor', 'external-contributor:completed']);
await upsertComment(github, context, pr.number, '<!-- external-contributor-pr:owned-status -->', [
`This mirrored PR has been merged into \`main\`. The original external PR ${externalPr.html_url} is now completed.`,
]);
await upsertComment(github, context, sourcePrNumber, `<!-- external-contributor-pr:completed owned-pr=${pr.number} -->`, [
`The mirrored PR ${pr.html_url} has been merged into \`main\`. This original external contributor PR will stay closed as completed.`,
]);
return;
}
await syncLabels(github, context, pr.number, ['external-contributor', 'external-contributor:stale']);
await syncLabels(github, context, sourcePrNumber, ['external-contributor', 'external-contributor:awaiting-approval']);
if (externalPr.head.sha !== sourceSha) {
await upsertComment(github, context, pr.number, '<!-- external-contributor-pr:owned-status -->', [
`This mirrored PR is stale because the original external PR ${externalPr.html_url} now points at a different source SHA.`,
'Approve the latest external commit to refresh this same internal PR.',
]);
return;
}
if (externalPr.state === 'closed') {
await github.rest.pulls.update({ owner: context.repo.owner, repo: context.repo.repo, pull_number: sourcePrNumber, state: 'open' });
}
await upsertComment(github, context, sourcePrNumber, `<!-- external-contributor-pr:owned-closed owned-pr=${pr.number} -->`, [
`The mirrored PR ${pr.html_url} was closed without merge. This original PR has been reopened and is awaiting a fresh approving review from a stagehand team member with write access.`,
]);
await upsertComment(github, context, pr.number, '<!-- external-contributor-pr:owned-status -->', [
`This mirrored PR was closed without merge. The original external PR ${externalPr.html_url} has been reopened and relabeled as awaiting approval.`,
]);
}
return { externalLifecycle, prepareClaim, finalizeClaim, syncOwnedPr };
})()
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.workflow_run.id }}
cancel-in-progress: false
jobs:
manage-external-pr:
if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository
runs-on: ubuntu-latest
steps:
- name: Sync external PR lifecycle
if: github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const lib = eval(process.env.ECPR_LIB);
await lib.externalLifecycle({ github, context });
claim-approved-pr:
if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Download approval handoff artifact
uses: actions/download-artifact@v4
with:
name: approved-review
path: approval-handoff
github-token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
run-id: ${{ github.event.workflow_run.id }}
- name: Prepare approved claim
id: prepare-claim
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const lib = eval(process.env.ECPR_LIB);
await lib.prepareClaim({ github, context, core, artifactPath: 'approval-handoff/approval-handoff.json' });
- name: Checkout repository for branch operations
if: steps.prepare-claim.outputs.should-claim == 'true'
uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: true
- name: Refresh internal branch
if: steps.prepare-claim.outputs.should-claim == 'true'
id: refresh-branch
continue-on-error: true
env:
INTERNAL_BRANCH: ${{ steps.prepare-claim.outputs.branch }}
PR_NUMBER: ${{ steps.prepare-claim.outputs.pr-number }}
PREVIOUS_SOURCE_SHA: ${{ steps.prepare-claim.outputs.previous-source-sha }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -uo pipefail
refresh_status="conflict"
refresh_reason="unknown"
write_outputs() {
echo "refresh-status=${refresh_status}" >> "$GITHUB_OUTPUT"
if [ -n "${refresh_reason}" ]; then
echo "reason=${refresh_reason}" >> "$GITHUB_OUTPUT"
fi
}
trap write_outputs EXIT
if ! git config user.name "github-actions[bot]"; then
refresh_reason="git-config-failed"
exit 0
fi
if ! git config user.email "41898282+github-actions[bot]@users.noreply.github.com"; then
refresh_reason="git-config-failed"
exit 0
fi
if ! git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"; then
refresh_reason="remote-auth-failed"
exit 0
fi
if ! git fetch origin "pull/${PR_NUMBER}/head:refs/remotes/origin/external-pr-head-${PR_NUMBER}"; then
refresh_reason="fetch-external-failed"
exit 0
fi
external_ref="refs/remotes/origin/external-pr-head-${PR_NUMBER}"
branch_exists=false
if git ls-remote --exit-code --heads origin "${INTERNAL_BRANCH}" >/dev/null 2>&1; then
branch_exists=true
if ! git fetch origin "${INTERNAL_BRANCH}:refs/remotes/origin/${INTERNAL_BRANCH}"; then
refresh_reason="fetch-internal-failed"
exit 0
fi
fi
if [ "${branch_exists}" = false ]; then
if ! git checkout -B "${INTERNAL_BRANCH}" "${external_ref}"; then
refresh_reason="checkout-failed"
exit 0
fi
if ! git push --force-with-lease origin "HEAD:refs/heads/${INTERNAL_BRANCH}"; then
refresh_reason="push-failed"
exit 0
fi
refresh_status="updated"
refresh_reason=""
exit 0
fi
if ! git checkout -B "${INTERNAL_BRANCH}" "refs/remotes/origin/${INTERNAL_BRANCH}"; then
refresh_reason="checkout-failed"
exit 0
fi
if [ -z "${PREVIOUS_SOURCE_SHA}" ]; then
refresh_reason="missing-previous-source"
exit 0
fi
if git rebase --onto "${external_ref}" "${PREVIOUS_SOURCE_SHA}" "${INTERNAL_BRANCH}"; then
if ! git push --force-with-lease origin "HEAD:refs/heads/${INTERNAL_BRANCH}"; then
refresh_reason="push-failed"
exit 0
fi
refresh_status="updated"
refresh_reason=""
exit 0
fi
git rebase --abort || true
refresh_reason="rebase-conflict"
- name: Finalize approved claim
if: always() && steps.prepare-claim.outputs.should-claim == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const lib = eval(process.env.ECPR_LIB);
await lib.finalizeClaim({
github,
context,
input: {
prNumber: Number('${{ steps.prepare-claim.outputs.pr-number }}'),
sourceSha: ${{ toJson(steps.prepare-claim.outputs.source-sha) }},
branch: ${{ toJson(steps.prepare-claim.outputs.branch) }},
claimer: ${{ toJson(steps.prepare-claim.outputs.claimer) }},
title: ${{ toJson(steps.prepare-claim.outputs.title) }},
body: ${{ toJson(steps.prepare-claim.outputs.body) }},
existingNumber: ${{ toJson(steps.prepare-claim.outputs.owned-pr-number) }},
existingMerged: '${{ steps.prepare-claim.outputs.owned-pr-merged }}' === 'true',
refreshStatus: ${{ toJson(steps.refresh-branch.outputs.refresh-status) }},
refreshReason: ${{ toJson(steps.refresh-branch.outputs.reason) }},
},
});
sync-owned-pr:
if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository && (github.event.action == 'closed' || github.event.action == 'reopened')
runs-on: ubuntu-latest
steps:
- name: Sync mirrored PR lifecycle
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const lib = eval(process.env.ECPR_LIB);
await lib.syncOwnedPr({ github, context });
================================================
FILE: .github/workflows/feature-parity.yml
================================================
name: Feature Parity
on:
pull_request:
types:
- opened
- synchronize
- labeled
- unlabeled
paths-ignore:
- "packages/docs/**"
jobs:
check-parity-label:
runs-on: ubuntu-latest
if: github.event.action == 'labeled' && github.event.label.name == 'parity'
permissions:
contents: read
pull-requests: write
issues: write
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Check user permissions
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.actor
});
const hasWriteAccess = ['admin', 'write'].includes(permission.permission);
if (!hasWriteAccess) {
// Remove the parity label if user doesn't have write access
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'parity'
});
// Add a comment explaining why the label was removed
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `❌ **Parity Label Removed**\n\n@${context.actor}, you do not have sufficient permissions to add the 'parity' label. Only users with write access can trigger feature parity issues.\n\nIf you believe this feature should be implemented in the Python SDK, please ask a maintainer to add the label.`
});
throw new Error(`User ${context.actor} does not have write access to add parity label`);
}
console.log(`User ${context.actor} has ${permission.permission} access - proceeding with parity workflow`);
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.PARITY_APP_ID }}
private-key: ${{ secrets.PARITY_APP_PRIVATE_KEY }}
owner: browserbase
repositories: stagehand
- name: Create issue in Python SDK repository
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
// Get PR comments for additional context
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
// Format comments for the issue description
let commentsSection = '';
if (comments.length > 0) {
commentsSection = '\n\n## Recent Comments\n\n';
comments.slice(-3).forEach(comment => {
commentsSection += `**@${comment.user.login}** commented:\n`;
commentsSection += `${comment.body.substring(0, 500)}${comment.body.length > 500 ? '...' : ''}\n\n`;
});
}
// Get list of changed files for context
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
const changedFiles = files.map(file => `- \`${file.filename}\``).join('\n');
const issueTitle = `[Feature Parity] ${pullRequest.title}`;
const issueBody = `## Feature Parity Request
This issue was automatically created from a pull request in the TypeScript Stagehand repository that was labeled with 'parity'.
### Original PR Details
- **PR**: #${context.issue.number} - ${pullRequest.title}
- **Author**: @${pullRequest.user.login}
- **Link**: ${pullRequest.html_url}
### Description
${pullRequest.body || 'No description provided.'}
### Changed Files
${changedFiles}
${commentsSection}
### Action Required
Please review the changes in the original PR and implement equivalent functionality in the Python SDK if applicable.
---
*This issue was automatically generated by the Feature Parity workflow.*`;
// Create the issue in the Python repository
const { data: issue } = await github.rest.issues.create({
owner: 'browserbase',
repo: 'stagehand-python',
title: issueTitle,
body: issueBody,
labels: ['parity']
});
console.log(`Created issue: ${issue.html_url}`);
// Add a comment to the original PR confirming the issue was created
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `🔄 **Feature Parity Issue Created**\n\nAn issue has been automatically created in the Python SDK repository to track parity implementation:\n${issue.html_url}`
});
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches:
- main
permissions:
contents: write
pull-requests: write
id-token: write
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: ./.github/actions/setup-node-pnpm-turbo
with:
use-prebuilt-artifacts: "false"
- name: Configure npm registry for Trusted Publishing
uses: actions/setup-node@v6
with:
node-version: 20.x
registry-url: "https://registry.npmjs.org"
- name: Update npm for Trusted Publishing
run: npm install -g npm@latest
- name: Run Lint & Build
run: pnpm exec turbo run lint && pnpm exec turbo run build
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
publish: pnpm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish Canary
if: github.ref == 'refs/heads/main'
run: |
git checkout main
pnpm run release-canary
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .github/workflows/stagehand-server-v3-release.yml
================================================
name: Release stagehand/server-v3
on:
push:
branches:
- main
paths:
- .changeset/**
workflow_dispatch:
permissions:
contents: write
concurrency: ${{ github.workflow }}-${{ github.ref }}
env:
OAS_PATH: packages/server-v3/openapi.v3.yaml
jobs:
detect:
name: Detect server-v3 release (changesets)
runs-on: ubuntu-latest
outputs:
release: ${{ steps.meta.outputs.release }}
version: ${{ steps.meta.outputs.version }}
tag: ${{ steps.meta.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
fetch-tags: true
- uses: ./.github/actions/setup-node-pnpm-turbo
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
with:
use-prebuilt-artifacts: "false"
- name: Determine release metadata
id: meta
shell: bash
run: |
set -euo pipefail
latest_tag="$(git tag -l 'stagehand-server-v3/v*' --sort=-v:refname | head -n 1 || true)"
rm -f changeset-status.json
if [ -n "${latest_tag}" ]; then
pnpm changeset status --since "${latest_tag}" --output changeset-status.json
else
pnpm changeset status --output changeset-status.json
fi
node <<'NODE'
const fs = require('fs');
const status = JSON.parse(fs.readFileSync('changeset-status.json', 'utf8'));
const changesets = Array.isArray(status.changesets) ? status.changesets : [];
const releases = Array.isArray(status.releases) ? status.releases : [];
const shouldRelease = changesets.some((cs) =>
(cs.releases || []).some((r) => r?.name === '@browserbasehq/stagehand-server-v3')
);
const serverRelease = releases.find((r) => r?.name === '@browserbasehq/stagehand-server-v3');
if (shouldRelease && !serverRelease?.newVersion) {
throw new Error(
'Expected @browserbasehq/stagehand-server-v3 to have a computed newVersion in changeset-status.json.'
);
}
const release = shouldRelease ? 'true' : 'false';
const version = shouldRelease ? serverRelease.newVersion : '';
const tag = `stagehand-server-v3/v${version}`;
const out = process.env.GITHUB_OUTPUT;
fs.appendFileSync(out, `release=${release}\n`);
fs.appendFileSync(out, `version=${version}\n`);
fs.appendFileSync(out, `tag=${tag}\n`);
NODE
- name: Create stagehand/server-v3 tag
if: steps.meta.outputs.release == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
TARGET_SHA="${{ github.sha }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Try to fetch the tag if it exists on remote; ignore failure for new tags
git fetch --force origin "refs/tags/${TAG}:refs/tags/${TAG}" 2>/dev/null || true
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
echo "Tag already exists: ${TAG}"
exit 0
fi
git tag -a "${TAG}" "${TARGET_SHA}" -m "stagehand/server-v3 v${VERSION}"
git push origin "${TAG}"
build_binaries:
name: Build SEA binaries
needs: detect
if: needs.detect.outputs.release == 'true'
uses: ./.github/workflows/stagehand-server-v3-sea-build.yml
with:
matrix: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v3-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v3-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v3-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v3-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v3-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v3-win32-arm64.exe","include_sourcemaps":false}
]
release:
name: Publish GitHub Release
needs: [detect, build_binaries]
if: needs.detect.outputs.release == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
fetch-tags: false
- name: Prepare release assets directory
run: mkdir -p release-assets
- name: Prepare stagehand/server-v3 release assets
run: |
set -euo pipefail
cp "${{ env.OAS_PATH }}" "release-assets/openapi.v3.stagehand-server-v3-${{ needs.detect.outputs.version }}.yaml"
- name: Download SEA binary artifacts
uses: actions/download-artifact@v4
with:
pattern: stagehand-server-v3-*
path: .
merge-multiple: true
- name: Collect SEA binaries
shell: bash
run: |
set -euo pipefail
shopt -s nullglob
for f in packages/server-v3/dist/sea/stagehand-server-v3-*; do
cp "$f" release-assets/
done
- name: Create checksums
shell: bash
run: |
set -euo pipefail
cd release-assets
# Only checksum binaries (exclude openapi yaml). Avoid failing if no matches.
shopt -s nullglob
files=(stagehand-server-v3-*)
bins=()
for f in "${files[@]}"; do
[[ "$f" == *openapi* ]] && continue
[[ -f "$f" ]] && bins+=("$f")
done
: > checksums.sha256
if [ "${#bins[@]}" -gt 0 ]; then
shasum -a 256 "${bins[@]}" > checksums.sha256
fi
- name: Publish stagehand/server-v3 GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.detect.outputs.tag }}
name: stagehand/server-v3 v${{ needs.detect.outputs.version }}
generate_release_notes: true
files: |
release-assets/openapi.v3.stagehand-server-v3-${{ needs.detect.outputs.version }}.yaml
release-assets/stagehand-server-v3-*
release-assets/checksums.sha256
================================================
FILE: .github/workflows/stagehand-server-v3-sea-build.yml
================================================
name: Stagehand Server v3 SEA Build
on:
workflow_call:
inputs:
matrix:
description: "JSON matrix include list for SEA binaries."
required: false
type: string
default: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v3-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v3-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v3-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v3-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v3-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v3-win32-arm64.exe","include_sourcemaps":false}
]
use-prebuilt-artifacts:
description: "Whether to download pre-built package artifacts."
required: false
type: string
default: "false"
restore-turbo-cache:
description: "Whether to restore local .turbo cache."
required: false
type: string
default: "true"
node-version:
description: "Node.js version for setup."
required: false
type: string
default: "20.x"
upload-only-binary:
description: "Upload only this binary (empty => upload all)."
required: false
type: string
default: ""
workflow_dispatch:
inputs:
matrix:
description: "JSON matrix include list for SEA binaries."
required: false
default: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v3-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v3-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v3-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v3-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v3-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v3-win32-arm64.exe","include_sourcemaps":false}
]
use-prebuilt-artifacts:
description: "Whether to download pre-built package artifacts."
required: false
type: string
default: "false"
restore-turbo-cache:
description: "Whether to restore local .turbo cache."
required: false
type: string
default: "true"
node-version:
description: "Node.js version for setup."
required: false
type: string
default: "20.x"
upload-only-binary:
description: "Upload only this binary (empty => upload all)."
required: false
type: string
default: ""
jobs:
build_binaries:
name: Build SEA binaries (${{ matrix.binary_name }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(inputs.matrix) }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-tags: false
- uses: ./.github/actions/setup-node-pnpm-turbo
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
PLAYWRIGHT_SKIP_DOWNLOAD: "1"
PUPPETEER_SKIP_DOWNLOAD: "1"
with:
use-prebuilt-artifacts: ${{ inputs.use-prebuilt-artifacts }}
restore-turbo-cache: ${{ inputs.restore-turbo-cache }}
node-version: ${{ inputs.node-version }}
- name: Build SEA binary (ESM)
env:
SEA_TARGET_PLATFORM: ${{ matrix.platform }}
SEA_TARGET_ARCH: ${{ matrix.arch }}
SEA_BINARY_NAME: ${{ matrix.binary_name }}
SEA_INCLUDE_SOURCEMAPS: ${{ matrix.include_sourcemaps && '1' || '0' }}
run: pnpm exec turbo run build:sea:esm --filter=@browserbasehq/stagehand-server-v3
- name: Verify SEA binary exists
shell: bash
run: |
test -f "packages/server-v3/dist/sea/${{ matrix.binary_name }}"
- name: Verify SEA binary launches cleanly
shell: bash
env:
RUNNER_ARCH: ${{ runner.arch }}
run: |
set -euo pipefail
binary="packages/server-v3/dist/sea/${{ matrix.binary_name }}"
matrix_arch="${{ matrix.arch }}"
runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
if [[ "${matrix_arch}" != "${runner_arch}" ]]; then
echo "Runner arch (${runner_arch}) does not match matrix arch (${matrix_arch})."
echo "Launch verification must run on same-arch runners."
exit 1
fi
if [[ "${{ matrix.platform }}" != "win32" ]]; then
chmod +x "${binary}"
fi
port="$((30000 + RANDOM % 10000))"
log_file="$(mktemp)"
launched="false"
cleanup() {
if [[ -n "${pid:-}" ]] && kill -0 "${pid}" 2>/dev/null; then
kill "${pid}" 2>/dev/null || true
wait "${pid}" 2>/dev/null || true
fi
}
trap cleanup EXIT
PORT="${port}" "${binary}" >"${log_file}" 2>&1 &
pid=$!
for _ in {1..30}; do
if ! kill -0 "${pid}" 2>/dev/null; then
wait "${pid}" 2>/dev/null || true
echo "SEA binary exited before becoming healthy."
cat "${log_file}"
exit 1
fi
if curl --silent --show-error --fail "http://127.0.0.1:${port}/healthz" >/dev/null; then
launched="true"
break
fi
sleep 1
done
if [[ "${launched}" != "true" ]]; then
echo "SEA binary did not become healthy within 30 seconds."
cat "${log_file}"
exit 1
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
if: ${{ inputs.upload-only-binary == '' || matrix.binary_name == inputs.upload-only-binary }}
with:
name: ${{ matrix.binary_name }}
# package.json is included to anchor artifact paths at repo root.
path: |
package.json
packages/server-v3/dist/sea/${{ matrix.binary_name }}
retention-days: 7
================================================
FILE: .github/workflows/stagehand-server-v4-release.yml
================================================
name: Release stagehand/server-v4
on:
push:
branches:
- main
paths:
- .changeset/**
workflow_dispatch:
permissions:
contents: write
concurrency: ${{ github.workflow }}-${{ github.ref }}
env:
OAS_PATH: packages/server-v4/openapi.v4.yaml
jobs:
detect:
name: Detect server-v4 release (changesets)
runs-on: ubuntu-latest
outputs:
release: ${{ steps.meta.outputs.release }}
version: ${{ steps.meta.outputs.version }}
tag: ${{ steps.meta.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
fetch-tags: true
- uses: ./.github/actions/setup-node-pnpm-turbo
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
with:
use-prebuilt-artifacts: "false"
- name: Determine release metadata
id: meta
shell: bash
run: |
set -euo pipefail
latest_tag="$(git tag -l 'stagehand-server-v4/v*' --sort=-v:refname | head -n 1 || true)"
rm -f changeset-status.json
if [ -n "${latest_tag}" ]; then
pnpm changeset status --since "${latest_tag}" --output changeset-status.json
else
pnpm changeset status --output changeset-status.json
fi
node <<'NODE'
const fs = require('fs');
const status = JSON.parse(fs.readFileSync('changeset-status.json', 'utf8'));
const changesets = Array.isArray(status.changesets) ? status.changesets : [];
const releases = Array.isArray(status.releases) ? status.releases : [];
const shouldRelease = changesets.some((cs) =>
(cs.releases || []).some((r) => r?.name === '@browserbasehq/stagehand-server-v4')
);
const serverRelease = releases.find((r) => r?.name === '@browserbasehq/stagehand-server-v4');
if (shouldRelease && !serverRelease?.newVersion) {
throw new Error(
'Expected @browserbasehq/stagehand-server-v4 to have a computed newVersion in changeset-status.json.'
);
}
const release = shouldRelease ? 'true' : 'false';
const version = shouldRelease ? serverRelease.newVersion : '';
const tag = `stagehand-server-v4/v${version}`;
const out = process.env.GITHUB_OUTPUT;
fs.appendFileSync(out, `release=${release}\n`);
fs.appendFileSync(out, `version=${version}\n`);
fs.appendFileSync(out, `tag=${tag}\n`);
NODE
- name: Create stagehand/server-v4 tag
if: steps.meta.outputs.release == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
set -euo pipefail
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
TARGET_SHA="${{ github.sha }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Try to fetch the tag if it exists on remote; ignore failure for new tags
git fetch --force origin "refs/tags/${TAG}:refs/tags/${TAG}" 2>/dev/null || true
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
echo "Tag already exists: ${TAG}"
exit 0
fi
git tag -a "${TAG}" "${TARGET_SHA}" -m "stagehand/server-v4 v${VERSION}"
git push origin "${TAG}"
build_binaries:
name: Build SEA binaries
needs: detect
if: needs.detect.outputs.release == 'true'
uses: ./.github/workflows/stagehand-server-v4-sea-build.yml
with:
matrix: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v4-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v4-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v4-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v4-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v4-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v4-win32-arm64.exe","include_sourcemaps":false}
]
release:
name: Publish GitHub Release
needs: [detect, build_binaries]
if: needs.detect.outputs.release == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
fetch-tags: false
- name: Prepare release assets directory
run: mkdir -p release-assets
- name: Prepare stagehand/server-v4 release assets
run: |
set -euo pipefail
cp "${{ env.OAS_PATH }}" "release-assets/openapi.v4.stagehand-server-v4-${{ needs.detect.outputs.version }}.yaml"
- name: Download SEA binary artifacts
uses: actions/download-artifact@v4
with:
pattern: stagehand-server-v4-*
path: .
merge-multiple: true
- name: Collect SEA binaries
shell: bash
run: |
set -euo pipefail
shopt -s nullglob
for f in packages/server-v4/dist/sea/stagehand-server-v4-*; do
cp "$f" release-assets/
done
- name: Create checksums
shell: bash
run: |
set -euo pipefail
cd release-assets
# Only checksum binaries (exclude openapi yaml). Avoid failing if no matches.
shopt -s nullglob
files=(stagehand-server-v4-*)
bins=()
for f in "${files[@]}"; do
[[ "$f" == *openapi* ]] && continue
[[ -f "$f" ]] && bins+=("$f")
done
: > checksums.sha256
if [ "${#bins[@]}" -gt 0 ]; then
shasum -a 256 "${bins[@]}" > checksums.sha256
fi
- name: Publish stagehand/server-v4 GitHub release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.detect.outputs.tag }}
name: stagehand/server-v4 v${{ needs.detect.outputs.version }}
generate_release_notes: true
files: |
release-assets/openapi.v4.stagehand-server-v4-${{ needs.detect.outputs.version }}.yaml
release-assets/stagehand-server-v4-*
release-assets/checksums.sha256
================================================
FILE: .github/workflows/stagehand-server-v4-sea-build.yml
================================================
name: Stagehand Server v4 SEA Build
on:
workflow_call:
inputs:
matrix:
description: "JSON matrix include list for SEA binaries."
required: false
type: string
default: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v4-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v4-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v4-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v4-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v4-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v4-win32-arm64.exe","include_sourcemaps":false}
]
use-prebuilt-artifacts:
description: "Whether to download pre-built package artifacts."
required: false
type: string
default: "false"
restore-turbo-cache:
description: "Whether to restore local .turbo cache."
required: false
type: string
default: "true"
node-version:
description: "Node.js version for setup."
required: false
type: string
default: "20.x"
upload-only-binary:
description: "Upload only this binary (empty => upload all)."
required: false
type: string
default: ""
workflow_dispatch:
inputs:
matrix:
description: "JSON matrix include list for SEA binaries."
required: false
default: |
[
{"os":"ubuntu-latest","platform":"linux","arch":"x64","binary_name":"stagehand-server-v4-linux-x64","include_sourcemaps":false},
{"os":"ubuntu-24.04-arm","platform":"linux","arch":"arm64","binary_name":"stagehand-server-v4-linux-arm64","include_sourcemaps":false},
{"os":"macos-15","platform":"darwin","arch":"arm64","binary_name":"stagehand-server-v4-darwin-arm64","include_sourcemaps":false},
{"os":"macos-15-intel","platform":"darwin","arch":"x64","binary_name":"stagehand-server-v4-darwin-x64","include_sourcemaps":false},
{"os":"windows-latest","platform":"win32","arch":"x64","binary_name":"stagehand-server-v4-win32-x64.exe","include_sourcemaps":false},
{"os":"windows-11-arm","platform":"win32","arch":"arm64","binary_name":"stagehand-server-v4-win32-arm64.exe","include_sourcemaps":false}
]
use-prebuilt-artifacts:
description: "Whether to download pre-built package artifacts."
required: false
type: string
default: "false"
restore-turbo-cache:
description: "Whether to restore local .turbo cache."
required: false
type: string
default: "true"
node-version:
description: "Node.js version for setup."
required: false
type: string
default: "20.x"
upload-only-binary:
description: "Upload only this binary (empty => upload all)."
required: false
type: string
default: ""
jobs:
build_binaries:
name: Build SEA binaries (${{ matrix.binary_name }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(inputs.matrix) }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-tags: false
- uses: ./.github/actions/setup-node-pnpm-turbo
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
PLAYWRIGHT_SKIP_DOWNLOAD: "1"
PUPPETEER_SKIP_DOWNLOAD: "1"
with:
use-prebuilt-artifacts: ${{ inputs.use-prebuilt-artifacts }}
restore-turbo-cache: ${{ inputs.restore-turbo-cache }}
node-version: ${{ inputs.node-version }}
- name: Build SEA binary (ESM)
env:
SEA_TARGET_PLATFORM: ${{ matrix.platform }}
SEA_TARGET_ARCH: ${{ matrix.arch }}
SEA_BINARY_NAME: ${{ matrix.binary_name }}
SEA_INCLUDE_SOURCEMAPS: ${{ matrix.include_sourcemaps && '1' || '0' }}
run: pnpm exec turbo run build:sea:esm --filter=@browserbasehq/stagehand-server-v4
- name: Verify SEA binary exists
shell: bash
run: |
test -f "packages/server-v4/dist/sea/${{ matrix.binary_name }}"
- name: Verify SEA binary launches cleanly
shell: bash
env:
RUNNER_ARCH: ${{ runner.arch }}
run: |
set -euo pipefail
binary="packages/server-v4/dist/sea/${{ matrix.binary_name }}"
matrix_arch="${{ matrix.arch }}"
runner_arch="$(echo "${RUNNER_ARCH}" | tr '[:upper:]' '[:lower:]')"
if [[ "${matrix_arch}" != "${runner_arch}" ]]; then
echo "Runner arch (${runner_arch}) does not match matrix arch (${matrix_arch})."
echo "Launch verification must run on same-arch runners."
exit 1
fi
if [[ "${{ matrix.platform }}" != "win32" ]]; then
chmod +x "${binary}"
fi
port="$((30000 + RANDOM % 10000))"
log_file="$(mktemp)"
launched="false"
cleanup() {
if [[ -n "${pid:-}" ]] && kill -0 "${pid}" 2>/dev/null; then
kill "${pid}" 2>/dev/null || true
wait "${pid}" 2>/dev/null || true
fi
}
trap cleanup EXIT
PORT="${port}" "${binary}" >"${log_file}" 2>&1 &
pid=$!
for _ in {1..30}; do
if ! kill -0 "${pid}" 2>/dev/null; then
wait "${pid}" 2>/dev/null || true
echo "SEA binary exited before becoming healthy."
cat "${log_file}"
exit 1
fi
if curl --silent --show-error --fail "http://127.0.0.1:${port}/healthz" >/dev/null; then
launched="true"
break
fi
sleep 1
done
if [[ "${launched}" != "true" ]]; then
echo "SEA binary did not become healthy within 30 seconds."
cat "${log_file}"
exit 1
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
if: ${{ inputs.upload-only-binary == '' || matrix.binary_name == inputs.upload-only-binary }}
with:
name: ${{ matrix.binary_name }}
# package.json is included to anchor artifact paths at repo root.
path: |
package.json
packages/server-v4/dist/sea/${{ matrix.binary_name }}
retention-days: 7
================================================
FILE: .github/workflows/stainless.yml
================================================
name: Build SDKs for pull request
on:
pull_request:
types:
- opened
- synchronize
- reopened
- closed
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
STAINLESS_ORG: ${{ vars.STAINLESS_ORG }}
STAINLESS_PROJECT: ${{ vars.STAINLESS_PROJECT }}
OAS_PATH: packages/server-v3/openapi.v3.yaml
jobs:
preview:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Run preview builds
uses: stainless-api/upload-openapi-spec-action/preview@v1
with:
stainless_api_key: ${{ secrets.STAINLESS_API_KEY }}
org: ${{ env.STAINLESS_ORG }}
project: ${{ env.STAINLESS_PROJECT }}
oas_path: ${{ env.OAS_PATH }}
config_path: stainless.yml
merge:
if: github.event.action == 'closed' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Run merge build
uses: stainless-api/upload-openapi-spec-action/merge@v1
with:
stainless_api_key: ${{ secrets.STAINLESS_API_KEY }}
org: ${{ env.STAINLESS_ORG }}
project: ${{ env.STAINLESS_PROJECT }}
oas_path: ${{ env.OAS_PATH }}
config_path: stainless.yml
================================================
FILE: .gitignore
================================================
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
screenshot.png
.DS_STORE
.cache/
.env
downloads/
dist/
.browserbase/
packages/evals/**/public
packages/core/lib/dom/build/
packages/core/lib/v3/dom/build/
packages/evals/public
*.tgz
evals/playground.ts
tmp/
eval-summary.json
package-lock.json
evals/deterministic/tests/BrowserContext/tmp-test.har
packages/core/lib/version.ts
packages/core/test-results/
/examples/inference_summary
/inference_summary
.turbo
.idea
coverage/
ctrf/
.stagehand-sea/
================================================
FILE: .prettierignore
================================================
pnpm-lock.yaml
README.md
**/*.json
docs/
.github/
dist/
node_modules/
lib/dom/build/
lib/v3/dom/build/
packages/core/dist/
packages/core/lib/dom/build/
packages/core/lib/v3/dom/build/
packages/cli/dist/
packages/evals/dist/
packages/docs/
*.min.js
.browserbase/
.browserbase/**
**/.browserbase/
**/.browserbase/**
stainless.yml
openapi.*.yaml
================================================
FILE: .prettierrc
================================================
{}
================================================
FILE: .vscode/settings.json
================================================
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
================================================
FILE: CHANGELOG.md
================================================
# @browserbasehq/stagehand
## 3.0.0
### Major Changes
- Removes internal Playwright dependency
- A generous 20-40% speed increase across `act`, `extract`, & `observe` calls
- Compatibility with Playwright, Puppeteer, and Patchright
- Automatic action caching (agent, stagehand.act). Go from CUA → deterministic scripts w/o inference
- A suite of non AI primitives:
- `page`
- `locator` (built in closed mode shadow root traversal, with xpaths & css selectors)
- `frameLocator`
- `deepLocator` (crosses iframes & shadow roots)
- bun compatibility
- Simplified extract schemas
- CSS selector support (id-based support coming soon)
- Targeted extract and observe across iframes & shadow roots
- More intuitive type names (observeResult is now action, act accepts an instruction string instead of an action string, solidified ModelConfiguration)
Check the [migration guide](https://docs.stagehand.dev/v3/migrations/v2) for more information
## 2.5.0
### Minor Changes
- [#981](https://github.com/browserbase/stagehand/pull/981) [`8244ab2`](https://github.com/browserbase/stagehand/commit/8244ab247cd679962685ae2f7c54e874ce1fa614) Thanks [@sameelarif](https://github.com/sameelarif)! - Added support for `stagehand.agent` to interact with MCP servers as well as custom tools to be passed in. For more information, reference the [MCP integrations documentation](https://docs.stagehand.dev/best-practices/mcp-integrations)
### Patch Changes
- [#959](https://github.com/browserbase/stagehand/pull/959) [`09b5e1e`](https://github.com/browserbase/stagehand/commit/09b5e1e9c23c845903686db6665cc968ac34efbb) Thanks [@filip-michalsky](https://github.com/filip-michalsky)! - add webvoyager evals
- [#1049](https://github.com/browserbase/stagehand/pull/1049) [`e3734b9`](https://github.com/browserbase/stagehand/commit/e3734b9c98352d5f0a4eca49791b0bbf2130ab41) Thanks [@miguelg719](https://github.com/miguelg719)! - Support local MCP server connections
- [#1025](https://github.com/browserbase/stagehand/pull/1025) [`be85b19`](https://github.com/browserbase/stagehand/commit/be85b19679a826f19702e00f0aae72fce1118ec8) Thanks [@tkattkat](https://github.com/tkattkat)! - add support for custom baseUrl within openai provider
- [#1040](https://github.com/browserbase/stagehand/pull/1040) [`88d1565`](https://github.com/browserbase/stagehand/commit/88d1565c65bb65a104fea2d5f5e862bbbda69677) Thanks [@miguelg719](https://github.com/miguelg719)! - Allow OpenAI CUA to take in an optional baseURL
- [#1046](https://github.com/browserbase/stagehand/pull/1046) [`ab5d6ed`](https://github.com/browserbase/stagehand/commit/ab5d6ede19aabc059badc4247f1cb2c6c9e71bae) Thanks [@tkattkat](https://github.com/tkattkat)! - Add support for gpt-5 in operator agent
## 2.4.4
### Patch Changes
- [#1012](https://github.com/browserbase/stagehand/pull/1012) [`9e8c173`](https://github.com/browserbase/stagehand/commit/9e8c17374fdc8fbe7f26e6cf802c36bd14f11039) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix disabling api validation whenever a customLLM client is provided
## 2.4.3
### Patch Changes
- [#951](https://github.com/browserbase/stagehand/pull/951) [`f45afdc`](https://github.com/browserbase/stagehand/commit/f45afdccc8680650755fee66ffbeac32b41e075d) Thanks [@miguelg719](https://github.com/miguelg719)! - Patch GPT-5 new api format
- [#954](https://github.com/browserbase/stagehand/pull/954) [`261bba4`](https://github.com/browserbase/stagehand/commit/261bba43fa79ac3af95328e673ef3e9fced3279b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add support for shadow DOMs (open & closed mode) when experimental: true
- [#944](https://github.com/browserbase/stagehand/pull/944) [`8de7bd8`](https://github.com/browserbase/stagehand/commit/8de7bd8635c2051cd8025e365c6c8aa83d81c7e7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Bump zod version compatibility and add pathing spec
- [#919](https://github.com/browserbase/stagehand/pull/919) [`3d80421`](https://github.com/browserbase/stagehand/commit/3d804210a106a6828c7fa50f8b765b10afd4cc6a) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable scrolling inside of iframes
- [#963](https://github.com/browserbase/stagehand/pull/963) [`0ead63d`](https://github.com/browserbase/stagehand/commit/0ead63d6526f6c286362b74b6407c8bebc900e69) Thanks [@tkattkat](https://github.com/tkattkat)! - Properly handle images in evaluator + clean up response parsing logic
- [#961](https://github.com/browserbase/stagehand/pull/961) [`8422828`](https://github.com/browserbase/stagehand/commit/8422828c4cd5fd5ebcf348cfbdb40c768bb76dd9) Thanks [@tkattkat](https://github.com/tkattkat)! - Add more evals for stagehand agent
- [#946](https://github.com/browserbase/stagehand/pull/946) [`b769206`](https://github.com/browserbase/stagehand/commit/b7692060f98a2f49aeeefb90d8789ed034b08ec2) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: unable to act on/get content from some same process iframes
- [#962](https://github.com/browserbase/stagehand/pull/962) [`72d2683`](https://github.com/browserbase/stagehand/commit/72d2683202af7e578d98367893964b33e0828de5) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - handle namespaced elements in xpath build step
## 2.4.2
### Patch Changes
- [#865](https://github.com/browserbase/stagehand/pull/865) [`6b4e6e3`](https://github.com/browserbase/stagehand/commit/6b4e6e3f31d5496cf15728e9018eddeb04839542) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - improve type safety for trimTrailingTextNode
- [#897](https://github.com/browserbase/stagehand/pull/897) [`e77d018`](https://github.com/browserbase/stagehand/commit/e77d0188683ebf596dfb78dfafbbca1dc32993f0) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix selfHeal to remember intially received arguments
- [#920](https://github.com/browserbase/stagehand/pull/920) [`c20adb9`](https://github.com/browserbase/stagehand/commit/c20adb95539fed8c56a4aa413262a9c65a8e6474) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: tab handling on API
- [#882](https://github.com/browserbase/stagehand/pull/882) [`b86df93`](https://github.com/browserbase/stagehand/commit/b86df93b9136aae96292121a29c25f3d74d84bf7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - remove elements that don't have xpaths from observe response
- [#905](https://github.com/browserbase/stagehand/pull/905) [`023c2c2`](https://github.com/browserbase/stagehand/commit/023c2c273b46d3792d7e5d3c902089487b16b531) Thanks [@tkattkat](https://github.com/tkattkat)! - Delete old images from anthropic cua client
- [#925](https://github.com/browserbase/stagehand/pull/925) [`8c28647`](https://github.com/browserbase/stagehand/commit/8c2864755ecd05c8f7de235d4198deec0dd5f78e) Thanks [@miguelg719](https://github.com/miguelg719)! - Remove \_refreshPageFromApi()
- [#887](https://github.com/browserbase/stagehand/pull/887) [`87e09c6`](https://github.com/browserbase/stagehand/commit/87e09c618940f364ec8af00455a19a17ec63cbd3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: allow xpaths with prepended 'xpath=' for targeted extract
- [#864](https://github.com/browserbase/stagehand/pull/864) [`a611115`](https://github.com/browserbase/stagehand/commit/a61111525d70b450bdfc43f112380f44899c9e97) Thanks [@miguelg719](https://github.com/miguelg719)! - Temporarily patch custom clients serialization error on api
- [#881](https://github.com/browserbase/stagehand/pull/881) [`69913fe`](https://github.com/browserbase/stagehand/commit/69913fe1dfb8201ae2aeffa5f049fb46ab02cbc2) Thanks [@miguelg719](https://github.com/miguelg719)! - Pass sdk version number to API for debugging
- [#913](https://github.com/browserbase/stagehand/pull/913) [`b1b83a1`](https://github.com/browserbase/stagehand/commit/b1b83a1d334fe76e5f5f9dd32dc92c16b7d40ce6) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - move iframe out of 'experimental'
- [#891](https://github.com/browserbase/stagehand/pull/891) [`be8497c`](https://github.com/browserbase/stagehand/commit/be8497cb6b142cc893cea9692b8c47bd19514c60) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: nested iframe xpath bug
- [#883](https://github.com/browserbase/stagehand/pull/883) [`98704c9`](https://github.com/browserbase/stagehand/commit/98704c9ed225ca25bbde4bb3dc286936e9c54471) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add timeout for JS click
- [#907](https://github.com/browserbase/stagehand/pull/907) [`04978bd`](https://github.com/browserbase/stagehand/commit/04978bdd30d2edcbc69eb9fd91358a16975ea2eb) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - store mapping of CDP frame ID -> page
## 2.4.1
### Patch Changes
- [#856](https://github.com/browserbase/stagehand/pull/856) [`8a43c5a`](https://github.com/browserbase/stagehand/commit/8a43c5a86d4da40cfaedd9cf2e42186928bdf946) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - set download behaviour by default
- [#857](https://github.com/browserbase/stagehand/pull/857) [`890ffcc`](https://github.com/browserbase/stagehand/commit/890ffccac5e0a60ade64a46eb550c981ffb3e84a) Thanks [@miguelg719](https://github.com/miguelg719)! - return "not-supported" for elements inside the shadow-dom
- [#844](https://github.com/browserbase/stagehand/pull/844) [`64c1072`](https://github.com/browserbase/stagehand/commit/64c10727bda50470483a3eb175c02842db0923a1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - don't automatically close tabs
- [#860](https://github.com/browserbase/stagehand/pull/860) [`b077d3f`](https://github.com/browserbase/stagehand/commit/b077d3f48a97f47a71ccc79ae39b41e7f07f9c04) Thanks [@miguelg719](https://github.com/miguelg719)! - Set default schema on extract options with no schema
- [#842](https://github.com/browserbase/stagehand/pull/842) [`8bcb5d7`](https://github.com/browserbase/stagehand/commit/8bcb5d77debf6bf7601fd5c090efd7fde75c5d5e) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - improved handling for OS level dropdowns
- [#846](https://github.com/browserbase/stagehand/pull/846) [`7bf10c5`](https://github.com/browserbase/stagehand/commit/7bf10c55b267078fe847c1d7f7a60d604f9c7c94) Thanks [@miguelg719](https://github.com/miguelg719)! - Filter attaching to target worker / shared_worker
## 2.4.0
### Minor Changes
- [#819](https://github.com/browserbase/stagehand/pull/819) [`6a18c1e`](https://github.com/browserbase/stagehand/commit/6a18c1ee1e46d55c6e90c4d5572e17ed8daa140c) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - try playwright click and fall back to JS click event
### Patch Changes
- [#826](https://github.com/browserbase/stagehand/pull/826) [`124e0d3`](https://github.com/browserbase/stagehand/commit/124e0d3bb54ddb6738ede6d7aa99a945ef1cacd1) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix issue where we are unable to take actions on text nodes
- [#818](https://github.com/browserbase/stagehand/pull/818) [`1660751`](https://github.com/browserbase/stagehand/commit/1660751cd14cb5b27d44f8167216afb8d1c3c45c) Thanks [@miguelg719](https://github.com/miguelg719)! - Added CUA support for Claude 4 models
- [#821](https://github.com/browserbase/stagehand/pull/821) [`cadac9d`](https://github.com/browserbase/stagehand/commit/cadac9da09123d12e5d496a0e8b12660964c1b33) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - use playwright instead of playwright test
- [#832](https://github.com/browserbase/stagehand/pull/832) [`759da55`](https://github.com/browserbase/stagehand/commit/759da55775eb2df81d56ae18c0f386fd9b02a9f0) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix \_refreshPageFromAPI to use parametrized apiKey
- [#810](https://github.com/browserbase/stagehand/pull/810) [`a175a51`](https://github.com/browserbase/stagehand/commit/a175a519b8c14300db6f1ed30709e113d18e99db) Thanks [@miguelg719](https://github.com/miguelg719)! - Update logos
- [#822](https://github.com/browserbase/stagehand/pull/822) [`8527a80`](https://github.com/browserbase/stagehand/commit/8527a80522c3eedb9516a6caa1a0e4e4be981a3d) Thanks [@miguelg719](https://github.com/miguelg719)! - Add model with date tag for OpenAI CUA
- [#833](https://github.com/browserbase/stagehand/pull/833) [`55fca2f`](https://github.com/browserbase/stagehand/commit/55fca2f7da63cc0ef6e27b45a33f63c666cdce7e) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - adjust stagehandLogger.warn() level to be 1 instead of 0
## 2.3.1
### Patch Changes
- [#796](https://github.com/browserbase/stagehand/pull/796) [`12a99b3`](https://github.com/browserbase/stagehand/commit/12a99b398d8a4c3eea3ca69a3cf793faaaf4aea3) Thanks [@miguelg719](https://github.com/miguelg719)! - Added a experimental flag to enable the newest and most experimental features
- [#807](https://github.com/browserbase/stagehand/pull/807) [`2451797`](https://github.com/browserbase/stagehand/commit/2451797f64c0efa4a72fd70265110003c8d0a6cd) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - include version number in StagehandDefaultError message
- [#803](https://github.com/browserbase/stagehand/pull/803) [`1d631a5`](https://github.com/browserbase/stagehand/commit/1d631a57a197390f672b718ae5199991ab27cfb1) Thanks [@miguelg719](https://github.com/miguelg719)! - Enable session affinity for cache optimization
- [#804](https://github.com/browserbase/stagehand/pull/804) [`9c398bb`](https://github.com/browserbase/stagehand/commit/9c398bb9ec2d10bdb53ad5aa7e3b58cce24fdb2b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - update operatorResponseSchema based on new openai spec
- [#786](https://github.com/browserbase/stagehand/pull/786) [`c19ad7f`](https://github.com/browserbase/stagehand/commit/c19ad7f1e082e91fdeaa9c2ef63767a5a2b3a195) Thanks [@miguelg719](https://github.com/miguelg719)! - Handle reroute to account for rollout
## 2.3.0
### Minor Changes
- [#737](https://github.com/browserbase/stagehand/pull/737) [`6ef6073`](https://github.com/browserbase/stagehand/commit/6ef60730cab0ad9025f44b6eeb2c83751d1dcd35) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - deprecate useTextExtract and remove functionality
### Patch Changes
- [#741](https://github.com/browserbase/stagehand/pull/741) [`5680d25`](https://github.com/browserbase/stagehand/commit/5680d2509352c383ad502c9f4fabde01fa638833) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - use safeparse for zod validation
- [#783](https://github.com/browserbase/stagehand/pull/783) [`4de92a8`](https://github.com/browserbase/stagehand/commit/4de92a8af461fc95063faf39feee1d49259f58ba) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix the readme logo link
## 2.2.1
### Patch Changes
- [#721](https://github.com/browserbase/stagehand/pull/721) [`be8652e`](https://github.com/browserbase/stagehand/commit/be8652e770b57fdb3299fa0b2efa4eb0e816434e) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix stagehand.close() functionality to include calling browser.close()
- [#724](https://github.com/browserbase/stagehand/pull/724) [`6b413b7`](https://github.com/browserbase/stagehand/commit/6b413b7ad00b13ca0bd53ee2e7393023821408b6) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - rm refine step in extract
- [#712](https://github.com/browserbase/stagehand/pull/712) [`7eafbd9`](https://github.com/browserbase/stagehand/commit/7eafbd9b1a73b37effa444929767df7c592caf02) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - deprecated `onlyVisible` param and remove its functionality
- [#725](https://github.com/browserbase/stagehand/pull/725) [`1b50aa6`](https://github.com/browserbase/stagehand/commit/1b50aa61cf0a429dd6cb2760a08f7f698a50454b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - dont overwrite .describe() when user defines a zod schema with z.string().url().describe()
- [#717](https://github.com/browserbase/stagehand/pull/717) [`f2b7f1f`](https://github.com/browserbase/stagehand/commit/f2b7f1f284eef1f96753319b66c7d0b273a6f8cd) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - don't publish uncompiled ts to npm
- [#719](https://github.com/browserbase/stagehand/pull/719) [`c8d672f`](https://github.com/browserbase/stagehand/commit/c8d672f7c410c256defbc2e87ead99239837aa28) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix `Invalid schema for response_format` error when extracting links
- [#722](https://github.com/browserbase/stagehand/pull/722) [`bebf204`](https://github.com/browserbase/stagehand/commit/bebf2044502333c694743078c5b0c9deae11fb79) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - replace NBSP with regular space & remove special characters from dom+a11y tree
- [#714](https://github.com/browserbase/stagehand/pull/714) [`37d6810`](https://github.com/browserbase/stagehand/commit/37d6810a704773d0383a86f98f5f17c7d5b21975) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix the native AI SDK client implementation to optionally take in an API key
## 2.2.0
### Minor Changes
- [#655](https://github.com/browserbase/stagehand/pull/655) [`8814af9`](https://github.com/browserbase/stagehand/commit/8814af9ece99fddc3dd9fb32671d0513a3a00c67) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - extract links
- [#675](https://github.com/browserbase/stagehand/pull/675) [`35c55eb`](https://github.com/browserbase/stagehand/commit/35c55ebf6c2867801a0a6f6988a883c8cb90cf9a) Thanks [@tkattkat](https://github.com/tkattkat)! - Added Gemini 2.5 Flash to Google supported models
- [#668](https://github.com/browserbase/stagehand/pull/668) [`5c6d2cf`](https://github.com/browserbase/stagehand/commit/5c6d2cf89c9fbf198485506ed9ed75e07aec5cd4) Thanks [@miguelg719](https://github.com/miguelg719)! - Added a new class - Stagehand Evaluator - that wraps around a Stagehand object to determine whether a task is successful or not. Currently used for agent evals
### Patch Changes
- [#706](https://github.com/browserbase/stagehand/pull/706) [`18ac6fb`](https://github.com/browserbase/stagehand/commit/18ac6fba30f45b7557cecb890f4e84c75de8383c) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - remove unused fillInVariables fn
- [#692](https://github.com/browserbase/stagehand/pull/692) [`6b95248`](https://github.com/browserbase/stagehand/commit/6b95248d6e02e5304ce4dd60499e31fc42af57eb) Thanks [@miguelg719](https://github.com/miguelg719)! - Updated the list of OpenAI models (4.1, o3...)
- [#688](https://github.com/browserbase/stagehand/pull/688) [`7d81b3c`](https://github.com/browserbase/stagehand/commit/7d81b3c951c1f3dfc46845aefcc26ff175299bca) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - wrap page.evaluate to make sure we have injected browser side scripts before calling them
- [#664](https://github.com/browserbase/stagehand/pull/664) [`b5ca00a`](https://github.com/browserbase/stagehand/commit/b5ca00a25ad0c33a5f4d3198e1bc59edb9956e7c) Thanks [@miguelg719](https://github.com/miguelg719)! - remove unnecessary log
- [#683](https://github.com/browserbase/stagehand/pull/683) [`8f0f97b`](https://github.com/browserbase/stagehand/commit/8f0f97bc491e23ff0078c802aaf509fd04173c37) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - use javsacript click instead of playwright
- [#705](https://github.com/browserbase/stagehand/pull/705) [`346ef5d`](https://github.com/browserbase/stagehand/commit/346ef5d0132dc1418dac18d26640a8df0435af57) Thanks [@miguelg719](https://github.com/miguelg719)! - Fixed removing a hanging observation map that is no longer used
- [#698](https://github.com/browserbase/stagehand/pull/698) [`c145bc1`](https://github.com/browserbase/stagehand/commit/c145bc1d90ffd0d71c412de3af1c26c121e0b101) Thanks [@sameelarif](https://github.com/sameelarif)! - Fixing LLM client support to natively integrate with AI SDK
- [#687](https://github.com/browserbase/stagehand/pull/687) [`edd6d3f`](https://github.com/browserbase/stagehand/commit/edd6d3feb47aac9f312a5edad78bf850ae1541db) Thanks [@miguelg719](https://github.com/miguelg719)! - Fixed the schema input for Gemini's response model
- [#678](https://github.com/browserbase/stagehand/pull/678) [`5ec43d8`](https://github.com/browserbase/stagehand/commit/5ec43d8b9568c0f86b3e24bd83d1826c837656ed) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - allow form filling when form is not top-most element
- [#694](https://github.com/browserbase/stagehand/pull/694) [`b8cc164`](https://github.com/browserbase/stagehand/commit/b8cc16405b712064a54c8cd591750368a47f35ea) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add telemetry for cua agents to stagehand.metrics
- [#699](https://github.com/browserbase/stagehand/pull/699) [`d9f4243`](https://github.com/browserbase/stagehand/commit/d9f4243f6a8c8d4f3003ad6589f7eb4da6d23d0f) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - rm deprecated primitives from stagehand object
- [#710](https://github.com/browserbase/stagehand/pull/710) [`9f4ab76`](https://github.com/browserbase/stagehand/commit/9f4ab76a0c1f0c2171290765c48c3bcea5b50e0f) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - support targeted extract for domExtract
- [#677](https://github.com/browserbase/stagehand/pull/677) [`bc5a731`](https://github.com/browserbase/stagehand/commit/bc5a731241f7f4c5040dd672d8e3787555766421) Thanks [@miguelg719](https://github.com/miguelg719)! - Fixes a redundant unnecessary log
## 2.1.0
### Minor Changes
- [#659](https://github.com/browserbase/stagehand/pull/659) [`f9a435e`](https://github.com/browserbase/stagehand/commit/f9a435e938daccfb2e54ca23fad8ef75128a4486) Thanks [@miguelg719](https://github.com/miguelg719)! - Added native support for Google Generative models (Gemini)
### Patch Changes
- [#647](https://github.com/browserbase/stagehand/pull/647) [`ca5467d`](https://github.com/browserbase/stagehand/commit/ca5467de7d31bfb270b6b625224a926c52c97900) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - collapse redundant text nodes into parent elements
- [#636](https://github.com/browserbase/stagehand/pull/636) [`9037430`](https://github.com/browserbase/stagehand/commit/903743097367ba6bb12baa9f0fa8f7985f543fdc) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix token act metrics and inference logging being misplaced as observe metrics and inference logging
- [#648](https://github.com/browserbase/stagehand/pull/648) [`169e7ea`](https://github.com/browserbase/stagehand/commit/169e7ea9e229503ae5958eaa4511531578ee3841) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add mapping of node id -> url
- [#654](https://github.com/browserbase/stagehand/pull/654) [`57a9853`](https://github.com/browserbase/stagehand/commit/57a98538381e0e54fbb734b43c50d61fd0d567df) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix repeated up & down scrolling bug for clicks inside `act`
- [#624](https://github.com/browserbase/stagehand/pull/624) [`cf167a4`](https://github.com/browserbase/stagehand/commit/cf167a437865e8e8bdb8739d22c3b3bb84e185de) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - export stagehand error classes so they can be referenced from @dist
- [#640](https://github.com/browserbase/stagehand/pull/640) [`178f5f0`](https://github.com/browserbase/stagehand/commit/178f5f0a8fecd876adfb4e29983853bdf7ec72fd) Thanks [@yash1744](https://github.com/yash1744)! - Added support for stagehand agents to automatically redirect to https://google.com when the page URL is empty or set to about:blank, preventing empty screenshots and saving tokens.
- [#661](https://github.com/browserbase/stagehand/pull/661) [`bf823a3`](https://github.com/browserbase/stagehand/commit/bf823a36930b0686b416a42302ef8c021b4aba75) Thanks [@kamath](https://github.com/kamath)! - fix press enter
- [#633](https://github.com/browserbase/stagehand/pull/633) [`86724f6`](https://github.com/browserbase/stagehand/commit/86724f6fb0abc7292423ac5bd0bebcd352f95940) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix the getBrowser logic for redundant api calls and throw informed errors
- [#656](https://github.com/browserbase/stagehand/pull/656) [`c630373`](https://github.com/browserbase/stagehand/commit/c630373dede4c775875834bfb860436ba2ea48d2) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - parse out % signs from variables in act
- [#637](https://github.com/browserbase/stagehand/pull/637) [`944bbbf`](https://github.com/browserbase/stagehand/commit/944bbbfe8bfb357b4910584447a93f6f402c3826) Thanks [@kamath](https://github.com/kamath)! - Fix: forward along the stack trace in StagehandDefaultError
## 2.0.0
### Major Changes
- [#591](https://github.com/browserbase/stagehand/pull/591) [`e234a0f`](https://github.com/browserbase/stagehand/commit/e234a0f80bf4c07bcc57265da216cbc4ab3bd19d) Thanks [@miguelg719](https://github.com/miguelg719)! - Announcing **Stagehand 2.0**! 🎉
We're thrilled to announce the release of Stagehand 2.0, bringing significant improvements to make browser automation more powerful, faster, and easier to use than ever before.
### 🚀 New Features
- **Introducing `stagehand.agent`**: A powerful new way to integrate SOTA Computer use models or Browserbase's [Open Operator](https://operator.browserbase.com) into Stagehand with one line of code! Perfect for multi-step workflows and complex interactions. [Learn more](https://docs.stagehand.dev/concepts/agent)
- **Lightning-fast `act` and `extract`**: Major performance improvements to make your automations run significantly faster.
- **Enhanced Logging**: Better visibility into what's happening during automation with improved logging and debugging capabilities.
- **Comprehensive Documentation**: A completely revamped documentation site with better examples, guides, and best practices.
- **Improved Error Handling**: More descriptive errors and better error recovery to help you debug issues faster.
### 🛠️ Developer Experience
- **Better TypeScript Support**: Enhanced type definitions and better IDE integration
- **Better Error Messages**: Clearer, more actionable error messages to help you debug faster
- **Improved Caching**: More reliable action caching for better performance
We're excited to see what you build with Stagehand 2.0! For questions or support, join our [Slack community](https://stagehand.dev/slack).
For more details, check out our [documentation](https://docs.stagehand.dev).
### Minor Changes
- [#588](https://github.com/browserbase/stagehand/pull/588) [`ba9efc5`](https://github.com/browserbase/stagehand/commit/ba9efc5580a536bc3c158e507a6c6695825c2834) Thanks [@sameelarif](https://github.com/sameelarif)! - Added support for offloading agent tasks to the API.
- [#600](https://github.com/browserbase/stagehand/pull/600) [`11e015d`](https://github.com/browserbase/stagehand/commit/11e015daac56dc961b8c8d54ce360fd00d4fee38) Thanks [@sameelarif](https://github.com/sameelarif)! - Added a `stagehand.history` array which stores an array of `act`, `extract`, `observe`, and `goto` calls made. Since this history array is stored on the `StagehandPage` level, it will capture methods even if indirectly called by an agent.
- [#601](https://github.com/browserbase/stagehand/pull/601) [`1d22604`](https://github.com/browserbase/stagehand/commit/1d2260401e27bae25779a55bb2ed7b7153c34fd0) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add custom error classes
- [#599](https://github.com/browserbase/stagehand/pull/599) [`75d8fb3`](https://github.com/browserbase/stagehand/commit/75d8fb36a67cd84eb55b509bf959edc7b05059da) Thanks [@miguelg719](https://github.com/miguelg719)! - cleaner logging with pino
- [#609](https://github.com/browserbase/stagehand/pull/609) [`c92295d`](https://github.com/browserbase/stagehand/commit/c92295d8424dac1a4f81066ca260ade2d5fce80b) Thanks [@kamath](https://github.com/kamath)! - Removed deprecated fields and methods from Stagehand constructor and added cdpUrl to localBrowserLaunchOptions for custom CDP URLs support.
- [#571](https://github.com/browserbase/stagehand/pull/571) [`73d6736`](https://github.com/browserbase/stagehand/commit/73d67368b88002c17814e46e75a99456bf355c4e) Thanks [@miguelg719](https://github.com/miguelg719)! - You can now use Computer Using Agents (CUA) natively in Stagehand for both Anthropic and OpenAI models! This unlocks a brand new frontier of applications for Stagehand users 🤘
- [#619](https://github.com/browserbase/stagehand/pull/619) [`7b0b996`](https://github.com/browserbase/stagehand/commit/7b0b9969a58014ae3e99b2054e4463b785073cfd) Thanks [@sameelarif](https://github.com/sameelarif)! - add disablePino flag to stagehand constructor params
- [#620](https://github.com/browserbase/stagehand/pull/620) [`566e587`](https://github.com/browserbase/stagehand/commit/566e5877a1861e0eae5a118d34efe09d43a37098) Thanks [@kamath](https://github.com/kamath)! - You can now pass in an OpenAI instance as an `llmClient` to the Stagehand constructor! This allows you to use Stagehand with any OpenAI-compatible model, like Ollama, Gemini, etc., as well as OpenAI wrappers like Braintrust.
- [#586](https://github.com/browserbase/stagehand/pull/586) [`c57dc19`](https://github.com/browserbase/stagehand/commit/c57dc19c448b8c2aab82953291f4e38f202c4729) Thanks [@sameelarif](https://github.com/sameelarif)! - Added native Stagehand agentic loop functionality. This allows you to build agentic workflows with a single prompt without using a computer-use model. To try it out, create a `stagehand.agent` without passing in a provider.
### Patch Changes
- [#580](https://github.com/browserbase/stagehand/pull/580) [`179e17c`](https://github.com/browserbase/stagehand/commit/179e17c2d1c9837de49c776d9850a330a759e73f) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - refactor \_performPlaywrightMethod
- [#608](https://github.com/browserbase/stagehand/pull/608) [`71ee10d`](https://github.com/browserbase/stagehand/commit/71ee10d50cb46e83d43fd783e1404569e6f317cf) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - added support for "scrolling to next/previous chunk"
- [#594](https://github.com/browserbase/stagehand/pull/594) [`e483484`](https://github.com/browserbase/stagehand/commit/e48348412a6e651967ba22d097d5308af0e8d0a8) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - pass observeHandler into actHandler
- [#569](https://github.com/browserbase/stagehand/pull/569) [`17e8b40`](https://github.com/browserbase/stagehand/commit/17e8b40f94b30f6e253443a4bbb8a3e364e58e38) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - you can now call stagehand.metrics to get token usage metrics. you can also set logInferenceToFile in stagehand config to log the entire call/response history from stagehand & the LLM.
- [#617](https://github.com/browserbase/stagehand/pull/617) [`affa564`](https://github.com/browserbase/stagehand/commit/affa5646658399ab71ed08c1b9ce0fd776b46fca) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - use a11y tree for default extract
- [#589](https://github.com/browserbase/stagehand/pull/589) [`0c4b1e7`](https://github.com/browserbase/stagehand/commit/0c4b1e7e6ff4b8a60af4a2d0d2056bff847227d5) Thanks [@miguelg719](https://github.com/miguelg719)! - Added CDP support for screenshots, find more about the benefits here: https://docs.browserbase.com/features/screenshots#why-use-cdp-for-screenshots%3F
- [#584](https://github.com/browserbase/stagehand/pull/584) [`c7c1a80`](https://github.com/browserbase/stagehand/commit/c7c1a8066be33188ba1e900828045db61410025c) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix to remove unnecessary healtcheck ping on sdk
- [#616](https://github.com/browserbase/stagehand/pull/616) [`2a27e1c`](https://github.com/browserbase/stagehand/commit/2a27e1c8e967befbbbb05ea71369878ac1573658) Thanks [@miguelg719](https://github.com/miguelg719)! - Fixed new opened tab handling for CUA models
- [#582](https://github.com/browserbase/stagehand/pull/582) [`dfd24e6`](https://github.com/browserbase/stagehand/commit/dfd24e638ef3723d3a8a3a33ff7942af0ac4745f) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - support api usage for extract with no args
- [#563](https://github.com/browserbase/stagehand/pull/563) [`98166d7`](https://github.com/browserbase/stagehand/commit/98166d76d30bc67d6b04b3d5c39f78f92c254b49) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - support scrolling in `act`
- [#598](https://github.com/browserbase/stagehand/pull/598) [`53889d4`](https://github.com/browserbase/stagehand/commit/53889d4b6e772098beaba2e1ee5a24e6f07706bb) Thanks [@miguelg719](https://github.com/miguelg719)! - Fix the open operator handler to work with anthropic
- [#605](https://github.com/browserbase/stagehand/pull/605) [`b8beaec`](https://github.com/browserbase/stagehand/commit/b8beaec451a03eaa5d12281fe7c8d4eb9c9d7e81) Thanks [@sameelarif](https://github.com/sameelarif)! - Added support for resuming a Stagehand session created on the API.
- [#612](https://github.com/browserbase/stagehand/pull/612) [`cd36068`](https://github.com/browserbase/stagehand/commit/cd3606854c465747c78b44763469dfdfa16db1b0) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - remove all logic related to dom based act
- [#577](https://github.com/browserbase/stagehand/pull/577) [`4fdbf63`](https://github.com/browserbase/stagehand/commit/4fdbf6324a0dc68568bba73ea4d9018b2ed67849) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - remove debugDom
- [#603](https://github.com/browserbase/stagehand/pull/603) [`2a14a60`](https://github.com/browserbase/stagehand/commit/2a14a607f3e7fa3ca9a02670afdc7e60ccfbfb3f) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - rm unused handlePossiblePageNavigation
- [#614](https://github.com/browserbase/stagehand/pull/614) [`a59eaef`](https://github.com/browserbase/stagehand/commit/a59eaef67c2f4a0cb07bb0046fe7e93e2ba4dc41) Thanks [@kamath](https://github.com/kamath)! - override whatwg-url to avoid punycode warning
- [#573](https://github.com/browserbase/stagehand/pull/573) [`c24f3c9`](https://github.com/browserbase/stagehand/commit/c24f3c9a58873c3920fab0f9891c2bf5245c9b5e) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - return act result in actFromObserve
## 1.14.0
### Minor Changes
- [#518](https://github.com/browserbase/stagehand/pull/518) [`516725f`](https://github.com/browserbase/stagehand/commit/516725fc1c5d12d22caac0078a118c77bfe033a8) Thanks [@sameelarif](https://github.com/sameelarif)! - `act()` can now use `observe()` under the hood, resulting in significant performance improvements. To opt-in to this change, set `slowDomBasedAct: false` in `ActOptions`.
- [#483](https://github.com/browserbase/stagehand/pull/483) [`8c9445f`](https://github.com/browserbase/stagehand/commit/8c9445fde9724ae33eeeb1234fd5b9bbd418bfdb) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - When using `textExtract`, you can now do targetted extraction by passing an xpath string into extract via the `selector` parameter. This limits the dom processing step to a target element, reducing tokens and increasing speed. For example:
```typescript
const weatherData = await stagehand.page.extract({
instruction: "extract the weather data for Sun, Feb 23 at 11PM",
schema: z.object({
temperature: z.string(),
weather_description: z.string(),
wind: z.string(),
humidity: z.string(),
barometer: z.string(),
visibility: z.string(),
}),
modelName,
useTextExtract,
selector: xpath, // xpath of the element to extract from
});
```
- [#556](https://github.com/browserbase/stagehand/pull/556) [`499a72d`](https://github.com/browserbase/stagehand/commit/499a72dc56009791ce065270b854b12fc5570050) Thanks [@kamath](https://github.com/kamath)! - You can now set a timeout for dom-based stagehand act! Do this in `act` with `timeoutMs` as a parameter, or set a global param to `actTimeoutMs` in Stagehand config.
- [#544](https://github.com/browserbase/stagehand/pull/544) [`55c9673`](https://github.com/browserbase/stagehand/commit/55c9673c5948743b804d70646f425a61818c7789) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - you can now deterministically get the full text representation of a webpage by calling `extract()` (with no arguments)
- [#538](https://github.com/browserbase/stagehand/pull/538) [`d898d5b`](https://github.com/browserbase/stagehand/commit/d898d5b9e1c3b80e62e72d36d1754b3e50d5a2b4) Thanks [@sameelarif](https://github.com/sameelarif)! - Added `gpt-4.5-preview` and `claude-3-7-sonnet-latest` as supported models.
- [#523](https://github.com/browserbase/stagehand/pull/523) [`44cf7cc`](https://github.com/browserbase/stagehand/commit/44cf7cc9ac1209c97d9153281970899b10a2ddc9) Thanks [@kwt00](https://github.com/kwt00)! You can now natively run Cerebras LLMs! `cerebras-llama-3.3-70b` and `cerebras-llama-3.1-8b` are now supported models as long as `CEREBRAS_API_KEY` is set in your environment.
- [#542](https://github.com/browserbase/stagehand/pull/542) [`cf7fe66`](https://github.com/browserbase/stagehand/commit/cf7fe665e6d1eeda97582ee2816f1dc3a66c6152) Thanks [@sankalpgunturi](https://github.com/sankalpgunturi)! You can now natively run Groq LLMs! `groq-llama-3.3-70b-versatile` and `groq-llama-3.3-70b-specdec` are now supported models as long as `GROQ_API_KEY` is set in your environment.
### Patch Changes
- [#506](https://github.com/browserbase/stagehand/pull/506) [`e521645`](https://github.com/browserbase/stagehand/commit/e5216455ce3fc2a4f4f7aa5614ecc92354eb670c) Thanks [@miguelg719](https://github.com/miguelg719)! - fixing 5s timeout on actHandler
- [#535](https://github.com/browserbase/stagehand/pull/535) [`3782054`](https://github.com/browserbase/stagehand/commit/3782054734dcd0346f84003ddd8e0e484b379459) Thanks [@miguelg719](https://github.com/miguelg719)! - Adding backwards compatibility to new act->observe pipeline by accepting actOptions
- [#508](https://github.com/browserbase/stagehand/pull/508) [`270f666`](https://github.com/browserbase/stagehand/commit/270f6669f1638f52fd5cd3f133f76446ced6ef9f) Thanks [@miguelg719](https://github.com/miguelg719)! - Fixed stagehand to support multiple pages with an enhanced context
- [#559](https://github.com/browserbase/stagehand/pull/559) [`18533ad`](https://github.com/browserbase/stagehand/commit/18533ad824722e4e699323248297e184bae9254e) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix: continuously adjusting chunk size inside `act`
- [#554](https://github.com/browserbase/stagehand/pull/554) [`5f1868b`](https://github.com/browserbase/stagehand/commit/5f1868bd95478b3eb517319ebca7b0af4e91d144) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix targetted extract issue with scrollintoview and not chunking correctly
- [#555](https://github.com/browserbase/stagehand/pull/555) [`fc5e8b6`](https://github.com/browserbase/stagehand/commit/fc5e8b6c5a606da96e6ed572dc8ffc6caef57576) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix issue where processAllOfDom doesnt scroll to end of page when there is dynamic content
- [#552](https://github.com/browserbase/stagehand/pull/552) [`a25a4cb`](https://github.com/browserbase/stagehand/commit/a25a4cb538d64f50b5bd834dd88e8e6086a73078) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - accept xpaths with 'xpath=' prepended to the front in addition to xpaths without
- [#534](https://github.com/browserbase/stagehand/pull/534) [`f0c162a`](https://github.com/browserbase/stagehand/commit/f0c162a6b4d1ac72c42f26462d7241a08b5c4e0a) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - call this.end() if the process exists
- [#528](https://github.com/browserbase/stagehand/pull/528) [`c820bfc`](https://github.com/browserbase/stagehand/commit/c820bfcfc9571fea90afd1595775c5946118cfaf) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - handle attempt to close session that has already been closed when using the api
- [#520](https://github.com/browserbase/stagehand/pull/520) [`f49eebd`](https://github.com/browserbase/stagehand/commit/f49eebd98c1d61413a3ea4c798595db601d55da8) Thanks [@miguelg719](https://github.com/miguelg719)! - Performing act from a 'not-supported' ObserveResult will now throw an informed error
## 1.13.1
### Patch Changes
- [#509](https://github.com/browserbase/stagehand/pull/509) [`a7d345e`](https://github.com/browserbase/stagehand/commit/a7d345e75434aebb656e1aa5aa61caed00dc99a8) Thanks [@miguelg719](https://github.com/miguelg719)! - Bun runs will now throw a more informed error
## 1.13.0
### Minor Changes
- [#486](https://github.com/browserbase/stagehand/pull/486) [`33f2b3f`](https://github.com/browserbase/stagehand/commit/33f2b3f8deff86ac2073b6d35b7413b0aeaba2f9) Thanks [@sameelarif](https://github.com/sameelarif)! - [Unreleased] Parameterized offloading Stagehand method calls to the Stagehand API. In the future, this will allow for better observability and debugging experience.
- [#494](https://github.com/browserbase/stagehand/pull/494) [`9ba4b0b`](https://github.com/browserbase/stagehand/commit/9ba4b0b563cbc77d40cac31c11e17e365a9d1749) Thanks [@pkiv](https://github.com/pkiv)! - Added LocalBrowserLaunchOptions to provide comprehensive configuration options for local browser instances. Deprecated the top-level headless option in favor of using localBrowserLaunchOptions.headless
- [#500](https://github.com/browserbase/stagehand/pull/500) [`a683fab`](https://github.com/browserbase/stagehand/commit/a683fab9ca90c45d78f6602a228c2d3219b776dc) Thanks [@miguelg719](https://github.com/miguelg719)! - Including Iframes in ObserveResults. This appends any iframe(s) found in the page to the end of observe results on any observe call.
- [#504](https://github.com/browserbase/stagehand/pull/504) [`577662e`](https://github.com/browserbase/stagehand/commit/577662e985a6a6b0477815853d98610f3a6b567d) Thanks [@sameelarif](https://github.com/sameelarif)! - Enabled support for Browserbase captcha solving after page navigations. This can be enabled with the new constructor parameter: `waitForCaptchaSolves`.
- [#496](https://github.com/browserbase/stagehand/pull/496) [`28ca9fb`](https://github.com/browserbase/stagehand/commit/28ca9fbc6f3cdc88437001108a9a6c4388ba0303) Thanks [@sameelarif](https://github.com/sameelarif)! - Fixed browserbaseSessionCreateParams not being passed in to the API initialization payload.
### Patch Changes
- [#459](https://github.com/browserbase/stagehand/pull/459) [`62a29ee`](https://github.com/browserbase/stagehand/commit/62a29eea982bbb855e2f885c09ac4c1334f3e0dc) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - create a11y + dom hybrid input for observe
- [#463](https://github.com/browserbase/stagehand/pull/463) [`e40bf6f`](https://github.com/browserbase/stagehand/commit/e40bf6f517331fc9952c3c9f2683b7e02ffb9735) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - include 'Scrollable' annotations in a11y-dom hybrid
- [#480](https://github.com/browserbase/stagehand/pull/480) [`4c07c44`](https://github.com/browserbase/stagehand/commit/4c07c444f0e71faf54413b2eeab760c7916a36e3) Thanks [@miguelg719](https://github.com/miguelg719)! - Adding a fallback try on actFromObserveResult to use the description from observe and call regular act.
- [#487](https://github.com/browserbase/stagehand/pull/487) [`2c855cf`](https://github.com/browserbase/stagehand/commit/2c855cffdfa2b0af9924612b9c59df7b65df6443) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - update refine extraction prompt to ensure correct schema is used
- [#497](https://github.com/browserbase/stagehand/pull/497) [`945ed04`](https://github.com/browserbase/stagehand/commit/945ed0426d34d2cb833aec8ba67bd4cba6c3b660) Thanks [@kamath](https://github.com/kamath)! - add gpt 4o november snapshot
## 1.12.0
### Minor Changes
- [#426](https://github.com/browserbase/stagehand/pull/426) [`bbbcee7`](https://github.com/browserbase/stagehand/commit/bbbcee7e7d86f5bf90cbb93f2ac9ad5935f15896) Thanks [@miguelg719](https://github.com/miguelg719)! - Observe got a major upgrade. Now it will return a suggested playwright method with any necessary arguments for the generated candidate elements. It also includes a major speedup when using a11y tree processing for context.
- [#452](https://github.com/browserbase/stagehand/pull/452) [`16837ec`](https://github.com/browserbase/stagehand/commit/16837ece839e192fbf7b68bec128dd02f22c2613) Thanks [@kamath](https://github.com/kamath)! - add o3-mini to availablemodel
- [#441](https://github.com/browserbase/stagehand/pull/441) [`1032d7d`](https://github.com/browserbase/stagehand/commit/1032d7d7d9c1ef8f30183c9019ea8324f1bdd5c6) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - allow act to accept observe output
### Patch Changes
- [#458](https://github.com/browserbase/stagehand/pull/458) [`da2e5d1`](https://github.com/browserbase/stagehand/commit/da2e5d1314b7504877fd50090e6a4b47f44fb9f6) Thanks [@miguelg719](https://github.com/miguelg719)! - Updated getAccessibilityTree() to make sure it doesn't skip useful nodes. Improved getXPathByResolvedObjectId() to account for text nodes and not skip generation
- [#448](https://github.com/browserbase/stagehand/pull/448) [`b216072`](https://github.com/browserbase/stagehand/commit/b2160723923ed78eba83e75c7270634ca7d217de) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - improve handling of radio button clicks
- [#445](https://github.com/browserbase/stagehand/pull/445) [`5bc514f`](https://github.com/browserbase/stagehand/commit/5bc514fc18e6634b1c81553bbc1e8b7d71b67d34) Thanks [@miguelg719](https://github.com/miguelg719)! - Adding back useAccessibilityTree param to observe with a deprecation warning/error indicating to use onlyVisible instead
## 1.11.0
### Minor Changes
- [#428](https://github.com/browserbase/stagehand/pull/428) [`5efeb5a`](https://github.com/browserbase/stagehand/commit/5efeb5ad44852efe7b260862729a5ac74eaa0228) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - temporarily remove vision
## 1.10.1
### Patch Changes
- [#422](https://github.com/browserbase/stagehand/pull/422) [`a2878d0`](https://github.com/browserbase/stagehand/commit/a2878d0acaf393b37763fb0c07b1a24043f7eb8d) Thanks [@miguelg719](https://github.com/miguelg719)! - Fixing a build type error for async functions being called inside evaulate for observeHandler.
## 1.10.0
### Minor Changes
- [#412](https://github.com/browserbase/stagehand/pull/412) [`4aa4813`](https://github.com/browserbase/stagehand/commit/4aa4813ad62cefc333a04ea6b1004f5888dec70f) Thanks [@miguelg719](https://github.com/miguelg719)! - Includes a new format to get website context using accessibility (a11y) trees. The new context is provided optionally with the flag useAccessibilityTree for observe tasks.
- [#417](https://github.com/browserbase/stagehand/pull/417) [`1f2b2c5`](https://github.com/browserbase/stagehand/commit/1f2b2c57d93e3b276c61224e1e26c65c2cb50e12) Thanks [@sameelarif](https://github.com/sameelarif)! - Simplify Stagehand method calls by allowing a simple string input instead of an options object.
- [#405](https://github.com/browserbase/stagehand/pull/405) [`0df1e23`](https://github.com/browserbase/stagehand/commit/0df1e233d4ad4ba39da457b6ed85916d8d20e12e) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - in ProcessAllOfDom, scroll on large scrollable elements instead of just the root DOM
- [#373](https://github.com/browserbase/stagehand/pull/373) [`ff00965`](https://github.com/browserbase/stagehand/commit/ff00965160d568ae0bc3ca437c01f95b5c6e9039) Thanks [@sameelarif](https://github.com/sameelarif)! - Allow the input of custom instructions into the constructor so that users can guide, or provide guardrails to, the LLM in making decisions.
### Patch Changes
- [#386](https://github.com/browserbase/stagehand/pull/386) [`2cee0a4`](https://github.com/browserbase/stagehand/commit/2cee0a45ae2b48d1de6543b196e338e7021e59fe) Thanks [@kamath](https://github.com/kamath)! - add demo gif
- [#362](https://github.com/browserbase/stagehand/pull/362) [`9c20de3`](https://github.com/browserbase/stagehand/commit/9c20de3e66f0ac20374d5e5e02eb107c620a2263) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - reduce collisions and improve accuracy of textExtract
- [#413](https://github.com/browserbase/stagehand/pull/413) [`737b4b2`](https://github.com/browserbase/stagehand/commit/737b4b208c9214e8bb22535ab7a8daccf37610d9) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - remove topMostElement check when verifying visibility of text nodes
- [#388](https://github.com/browserbase/stagehand/pull/388) [`e93561d`](https://github.com/browserbase/stagehand/commit/e93561d7875210ce7bd7fe841fb52decf6011fb3) Thanks [@kamath](https://github.com/kamath)! - Export LLMClient type
## 1.9.0
### Minor Changes
- [#374](https://github.com/browserbase/stagehand/pull/374) [`207244e`](https://github.com/browserbase/stagehand/commit/207244e3a46c4474d4d28db039eab131164790ca) Thanks [@sameelarif](https://github.com/sameelarif)! - Pass in a Stagehand Page object into the `on("popup")` listener to allow for multi-page handling.
- [#367](https://github.com/browserbase/stagehand/pull/367) [`75c0e20`](https://github.com/browserbase/stagehand/commit/75c0e20cde54951399753e0fa841df463e1271b8) Thanks [@kamath](https://github.com/kamath)! - Logger in LLMClient is inherited by default from Stagehand. Named rather than positional arguments are used in implemented LLMClients.
- [#381](https://github.com/browserbase/stagehand/pull/381) [`db2ef59`](https://github.com/browserbase/stagehand/commit/db2ef5997664e81b1dfb5ca992392362f2d3bab1) Thanks [@kamath](https://github.com/kamath)! - make logs only sync
- [#385](https://github.com/browserbase/stagehand/pull/385) [`5899ec2`](https://github.com/browserbase/stagehand/commit/5899ec2c4b73c636bfd8120ec3aac225af7dd949) Thanks [@sameelarif](https://github.com/sameelarif)! - Moved the LLMClient logger paremeter to the createChatCompletion method options.
- [#364](https://github.com/browserbase/stagehand/pull/364) [`08907eb`](https://github.com/browserbase/stagehand/commit/08907ebbc2cb47cfc3151946764656a7f4ce99c6) Thanks [@kamath](https://github.com/kamath)! - exposed llmClient in stagehand constructor
### Patch Changes
- [#383](https://github.com/browserbase/stagehand/pull/383) [`a77efcc`](https://github.com/browserbase/stagehand/commit/a77efccfde3a3948013eda3a52935e8a21d45b3e) Thanks [@sameelarif](https://github.com/sameelarif)! - Unified LLM input/output types for reduced dependence on OpenAI types
- [`b7b3701`](https://github.com/browserbase/stagehand/commit/b7b370160bf35b09f5dc132f6e86f6e34fb70a85) Thanks [@kamath](https://github.com/kamath)! - Fix $1-types exposed to the user
- [#353](https://github.com/browserbase/stagehand/pull/353) [`5c6f14b`](https://github.com/browserbase/stagehand/commit/5c6f14bade201e08cb86d2e14e246cb65707f7ee) Thanks [@kamath](https://github.com/kamath)! - Throw custom error if context is referenced without initialization, remove act/extract handler from index
- [#360](https://github.com/browserbase/stagehand/pull/360) [`89841fc`](https://github.com/browserbase/stagehand/commit/89841fc42ae82559baddfe2a9593bc3260c082a2) Thanks [@kamath](https://github.com/kamath)! - Remove stagehand nav entirely
- [#379](https://github.com/browserbase/stagehand/pull/379) [`b1c6579`](https://github.com/browserbase/stagehand/commit/b1c657976847de86d82324030f90c2f6a1f3f976) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - dont require LLM Client to use non-ai stagehand functions
- [#371](https://github.com/browserbase/stagehand/pull/371) [`30e7d09`](https://github.com/browserbase/stagehand/commit/30e7d091445004c71aec1748d3a7d75fb86d1f11) Thanks [@kamath](https://github.com/kamath)! - pretty readme :)
- [#382](https://github.com/browserbase/stagehand/pull/382) [`a41271b`](https://github.com/browserbase/stagehand/commit/a41271baf351e20f4c79b4b654d8a947b615a121) Thanks [@sameelarif](https://github.com/sameelarif)! - Added example implementation of the Vercel AI SDK as an LLMClient
- [#344](https://github.com/browserbase/stagehand/pull/344) [`c1cf345`](https://github.com/browserbase/stagehand/commit/c1cf34535ed30262989b1dbe262fb0414cdf8230) Thanks [@kamath](https://github.com/kamath)! - Remove duplicate logging and expose Page/BrowserContext types
## 1.8.0
### Minor Changes
- [#324](https://github.com/browserbase/stagehand/pull/324) [`cd23fa3`](https://github.com/browserbase/stagehand/commit/cd23fa33450107f29cb1ddb6edadfc769d336aa5) Thanks [@kamath](https://github.com/kamath)! - Move stagehand.act() -> stagehand.page.act() and deprecate stagehand.act()
- [#319](https://github.com/browserbase/stagehand/pull/319) [`bacbe60`](https://github.com/browserbase/stagehand/commit/bacbe608058304bfa1f0ab049da4d8aa90e8d6f7) Thanks [@kamath](https://github.com/kamath)! - We now wrap playwright page/context within StagehandPage and StagehandContext objects. This helps us augment the Stagehand experience by being able to augment the underlying Playwright
- [#324](https://github.com/browserbase/stagehand/pull/324) [`cd23fa3`](https://github.com/browserbase/stagehand/commit/cd23fa33450107f29cb1ddb6edadfc769d336aa5) Thanks [@kamath](https://github.com/kamath)! - moves extract and act -> page and deprecates stagehand.extract and stagehand.observe
### Patch Changes
- [#320](https://github.com/browserbase/stagehand/pull/320) [`c0cdd0e`](https://github.com/browserbase/stagehand/commit/c0cdd0e985d66f0464d2e70b7d0cb343b0efbd3f) Thanks [@kamath](https://github.com/kamath)! - bug fix: set this.env to LOCAL if BROWSERBASE_API_KEY is not defined
- [#325](https://github.com/browserbase/stagehand/pull/325) [`cc46f34`](https://github.com/browserbase/stagehand/commit/cc46f345c0a1dc0af4abae7e207833df17da50e7) Thanks [@pkiv](https://github.com/pkiv)! - only start domdebug if enabled
## 1.7.0
### Minor Changes
- [#316](https://github.com/browserbase/stagehand/pull/316) [`902e633`](https://github.com/browserbase/stagehand/commit/902e633e126a58b80b757ea0ecada01a7675a473) Thanks [@kamath](https://github.com/kamath)! - rename browserbaseResumeSessionID -> browserbaseSessionID
- [#296](https://github.com/browserbase/stagehand/pull/296) [`f11da27`](https://github.com/browserbase/stagehand/commit/f11da27a20409c240ceeea2003d520f676def61a) Thanks [@kamath](https://github.com/kamath)! - - Deprecate fields in `init` in favor of constructor options
- Deprecate `initFromPage` in favor of `browserbaseResumeSessionID` in constructor
- Rename `browserBaseSessionCreateParams` -> `browserbaseSessionCreateParams`
- [#304](https://github.com/browserbase/stagehand/pull/304) [`0b72f75`](https://github.com/browserbase/stagehand/commit/0b72f75f6a62aaeb28b0c488ae96db098d6a2846) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add textExtract: an optional, text based approach to the existing extract method. textExtract often performs better on long form extraction tasks. By default `extract` uses the existing approach `domExtract`.
- [#298](https://github.com/browserbase/stagehand/pull/298) [`55f0cd2`](https://github.com/browserbase/stagehand/commit/55f0cd2fe7976e800833ec6e41e9af62d88d09d5) Thanks [@kamath](https://github.com/kamath)! - Add sessionId to public params
### Patch Changes
- [#283](https://github.com/browserbase/stagehand/pull/283) [`b902192`](https://github.com/browserbase/stagehand/commit/b902192bc7ff8eb02c85150c1fe6f89c2a95b211) Thanks [@sameelarif](https://github.com/sameelarif)! - allowed customization of eval config via .env
- [#299](https://github.com/browserbase/stagehand/pull/299) [`fbe2300`](https://github.com/browserbase/stagehand/commit/fbe23007176488043c2415519f25021612fff989) Thanks [@sameelarif](https://github.com/sameelarif)! - log playwright actions for better debugging
## 1.6.0
### Minor Changes
- [#286](https://github.com/browserbase/stagehand/pull/286) [`9605836`](https://github.com/browserbase/stagehand/commit/9605836ee6b8207ed7dc9146e12ced1c78630d59) Thanks [@kamath](https://github.com/kamath)! - minor improvement in action + new eval case
- [#279](https://github.com/browserbase/stagehand/pull/279) [`d6d7057`](https://github.com/browserbase/stagehand/commit/d6d70570623a718354797ef83aa8489eacc085d1) Thanks [@kamath](https://github.com/kamath)! - Add support for o1-mini and o1-preview in OpenAIClient
- [#282](https://github.com/browserbase/stagehand/pull/282) [`5291797`](https://github.com/browserbase/stagehand/commit/529179724a53bf2fd578a4012fd6bc6b7348d1ae) Thanks [@kamath](https://github.com/kamath)! - Added eslint for stricter type checking. Streamlined most of the internal types throughout the cache, llm, and handlers. This should make it easier to add new LLMs down the line, maintain and update the existing code, and make it easier to add new features in the future. Types can be checked by running `npx eslint .` from the project directory.
### Patch Changes
- [#270](https://github.com/browserbase/stagehand/pull/270) [`6b10b3b`](https://github.com/browserbase/stagehand/commit/6b10b3b1160649b19f50d66588395ceb679b3d68) Thanks [@sameelarif](https://github.com/sameelarif)! - add close link to readme
- [#288](https://github.com/browserbase/stagehand/pull/288) [`5afa0b9`](https://github.com/browserbase/stagehand/commit/5afa0b940a9f379a3719a5bbae249dd2a9ef8380) Thanks [@kamath](https://github.com/kamath)! - add multi-region support for browserbase
- [#284](https://github.com/browserbase/stagehand/pull/284) [`474217c`](https://github.com/browserbase/stagehand/commit/474217cfaff8e68614212b66baa62d35493fd2ce) Thanks [@kamath](https://github.com/kamath)! - Build wasn't working, this addresses tsc failure.
- [#236](https://github.com/browserbase/stagehand/pull/236) [`85483fe`](https://github.com/browserbase/stagehand/commit/85483fe091544fc079015c62b6923b03f8b9caa7) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - reduce chunk size
## 1.5.0
### Minor Changes
- [#266](https://github.com/browserbase/stagehand/pull/266) [`0e8f34f`](https://github.com/browserbase/stagehand/commit/0e8f34fc15aee91c548d09534deaccc8adca7c4d) Thanks [@kamath](https://github.com/kamath)! - Install wasn't working from NPM due to misconfigured build step. This attempts to fix that.
## 1.4.0
### Minor Changes
- [#253](https://github.com/browserbase/stagehand/pull/253) [`598cae2`](https://github.com/browserbase/stagehand/commit/598cae230c7b8d4e31ae22fd63047a91b63e51b8) Thanks [@sameelarif](https://github.com/sameelarif)! - clean up contexts after use
### Patch Changes
- [#225](https://github.com/browserbase/stagehand/pull/225) [`a2366fe`](https://github.com/browserbase/stagehand/commit/a2366feb023180fbb2ccc7a8379692f9f8347fe5) Thanks [@sameelarif](https://github.com/sameelarif)! - Ensuring cross-platform compatibility with tmp directories
- [#249](https://github.com/browserbase/stagehand/pull/249) [`7d06d43`](https://github.com/browserbase/stagehand/commit/7d06d43f2b9a477fed35793d7479de9b183e8d53) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - fix broken evals
- [#227](https://github.com/browserbase/stagehand/pull/227) [`647eefd`](https://github.com/browserbase/stagehand/commit/647eefd651852eec495faa1b8f4dbe6b1da17999) Thanks [@kamath](https://github.com/kamath)! - Fix debugDom still showing chunks when set to false
- [#250](https://github.com/browserbase/stagehand/pull/250) [`5886620`](https://github.com/browserbase/stagehand/commit/5886620dd1b0a57c68bf810cf130df2ca0a50a69) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add ci specific evals
- [#222](https://github.com/browserbase/stagehand/pull/222) [`8dff026`](https://github.com/browserbase/stagehand/commit/8dff02674df7a6448f2262c7e212b58c03be57bc) Thanks [@sameelarif](https://github.com/sameelarif)! - Streamline type definitions and fix existing typescript errors
- [#232](https://github.com/browserbase/stagehand/pull/232) [`b9f9949`](https://github.com/browserbase/stagehand/commit/b9f99494021e6a9e2487b77bb64ed0a491751400) Thanks [@kamath](https://github.com/kamath)! - Minor changes to package.json and tsconfig, mainly around the build process. Also add more type defs and remove unused dependencies.
## 1.3.0
### Minor Changes
- [#195](https://github.com/browserbase/stagehand/pull/195) [`87a6305`](https://github.com/browserbase/stagehand/commit/87a6305d9a2faf1ab5915965913bc14d5cc15772) Thanks [@kamath](https://github.com/kamath)! - - Adds structured and more standardized JSON logging
- Doesn't init cache if `enableCaching` is false, preventing `tmp/.cache` from being created
- Updates bundling for browser-side code to support NextJS and serverless
## 1.2.0
### Minor Changes
- [#179](https://github.com/browserbase/stagehand/pull/179) [`0031871`](https://github.com/browserbase/stagehand/commit/0031871d5a6d6180f272a68b88a8634e5a991785) Thanks [@navidkpr](https://github.com/navidkpr)! - Fixes:
The last big change we pushed out, introduced a small regression. As a result, the gray outline showing the elements Stagehand is looking out is missing. This commit fixes that. We now process selectorMap properly now (using the updated type Record<number, string[]
Improved the action prompt:
Improved the structure
Made it more straightforward
Improved working for completed arg and prioritized precision over recall
## 1.1.0
### Minor Changes
- [`9206ec6`](https://github.com/browserbase/stagehand/commit/9206ec640b2d0af9170f0a31788ab1eac448357b) Thanks [@kamath](https://github.com/kamath)! - Connect to a minor session
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2024 Browserbase Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<div id="toc" align="center" style="margin-bottom: 0;">
<ul style="list-style: none; margin: 0; padding: 0;">
<a href="https://stagehand.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="media/dark_logo.png" />
<img alt="Stagehand" src="media/light_logo.png" width="200" style="margin-right: 30px;" />
</picture>
</a>
</ul>
</div>
<p align="center">
<strong>The AI Browser Automation Framework</strong><br>
<a href="https://docs.stagehand.dev">Read the Docs</a>
</p>
<p align="center">
<a href="https://github.com/browserbase/stagehand/tree/main?tab=MIT-1-ov-file#MIT-1-ov-file">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="media/dark_license.svg" />
<img alt="MIT License" src="media/light_license.svg" />
</picture>
</a>
<a href="https://stagehand.dev/discord">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="media/dark_discord.svg" />
<img alt="Discord Community" src="media/light_discord.svg" />
</picture>
</a>
</p>
<p align="center">
<a href="https://trendshift.io/repositories/12122" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12122" alt="browserbase%2Fstagehand | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</p>
<p align="center">
<a href="https://deepwiki.com/browserbase/stagehand">
<img alt="Ask DeepWiki" src="https://deepwiki.com/badge.svg" />
</a>
</p>
<p align="center">
If you're looking for the Python implementation, you can find it
<a href="https://github.com/browserbase/stagehand-python"> here</a>
</p>
<div align="center" style="display: flex; align-items: center; justify-content: center; gap: 4px; margin-bottom: 0;">
<b>Vibe code</b>
<span style="font-size: 1.05em;"> Stagehand with </span>
<a href="https://director.ai" style="display: flex; align-items: center;">
<span>Director</span>
</a>
<span> </span>
<picture>
<img alt="Director" src="media/director_icon.svg" width="25" />
</picture>
</div>
## What is Stagehand?
Stagehand is a browser automation framework used to control web browsers with natural language and code. By combining the power of AI with the precision of code, Stagehand makes web automation flexible, maintainable, and actually reliable.
## Why Stagehand?
Most existing browser automation tools either require you to write low-level code in a framework like Selenium, Playwright, or Puppeteer, or use high-level agents that can be unpredictable in production. By letting developers choose what to write in code vs. natural language (and bridging the gap between the two) Stagehand is the natural choice for browser automations in production.
1. **Choose when to write code vs. natural language**: use AI when you want to navigate unfamiliar pages, and use code when you know exactly what you want to do.
2. **Go from AI-driven to repeatable workflows**: Stagehand lets you preview AI actions before running them, and also helps you easily cache repeatable actions to save time and tokens.
3. **Write once, run forever**: Stagehand's auto-caching combined with self-healing remembers previous actions, runs without LLM inference, and knows when to involve AI whenever the website changes and your automation breaks.
## Getting Started
Start with Stagehand with one line of code, or check out our [Quickstart Guide](https://docs.stagehand.dev/v3/first-steps/quickstart) for more information:
```bash
npx create-browser-app
```
## Example
Here's how to build a sample browser automation with Stagehand:
```typescript
// Stagehand's CDP engine provides an optimized, low level interface to the browser built for automation
const page = stagehand.context.pages()[0];
await page.goto("https://github.com/browserbase");
// Use act() to execute individual actions
await stagehand.act("click on the stagehand repo");
// Use agent() for multi-step tasks
const agent = stagehand.agent();
await agent.execute("Get to the latest PR");
// Use extract() to get structured data from the page
const { author, title } = await stagehand.extract(
"extract the author and title of the PR",
z.object({
author: z.string().describe("The username of the PR author"),
title: z.string().describe("The title of the PR"),
}),
);
```
## Documentation
Visit [docs.stagehand.dev](https://docs.stagehand.dev) to view the full documentation.
### Build and Run from Source
```bash
git clone https://github.com/browserbase/stagehand.git
cd stagehand
pnpm install
pnpm run build
pnpm run example # run the blank script at ./examples/example.ts
```
Stagehand is best when you have an API key for an LLM provider and Browserbase credentials. To add these to your project, run:
```bash
cp .env.example .env
nano .env # Edit the .env file to add API keys
```
### Installing from a branch
You can install and build Stagehand directly from a github branch using [gitpkg](https://github.com/EqualMa/gitpkg)
In your project's `package.json` set:
```json
"@browserbasehq/stagehand": "https://gitpkg.now.sh/browserbase/stagehand/packages/core?<branchName>",
```
## Contributing
> [!NOTE]
> We highly value contributions to Stagehand! For questions or support, please join our [Discord community](https://stagehand.dev/discord).
At a high level, we're focused on improving reliability, extensibility, speed, and cost in that order of priority. If you're interested in contributing, **bug fixes and small improvements are the best way to get started**. For more involved features, we strongly recommend reaching out to [Miguel Gonzalez](https://x.com/miguel_gonzf) or [Paul Klein](https://x.com/pk_iv) in our [Discord community](https://stagehand.dev/discord) before starting to ensure that your contribution aligns with our goals.
<!-- For more information, please see our [Contributing Guide](https://docs.stagehand.dev/examples/contributing). -->
## Acknowledgements
We'd like to thank the following people for their major contributions to Stagehand:
- [Paul Klein](https://github.com/pkiv)
- [Sean McGuire](https://github.com/seanmcguire12)
- [Miguel Gonzalez](https://github.com/miguelg719)
- [Sameel Arif](https://github.com/sameelarif)
- [Thomas Katwan](https://github.com/tkattkat)
- [Filip Michalsky](https://github.com/filip-michalsky)
- [Anirudh Kamath](https://github.com/kamath)
- [Jeremy Press](https://x.com/jeremypress)
- [Navid Pour](https://github.com/navidpour)
## License
Licensed under the MIT License.
Copyright 2025 Browserbase, Inc.
================================================
FILE: claude.md
================================================
# Stagehand Project
This is a project that uses Stagehand V3, a browser automation framework with AI-powered `act`, `extract`, `observe`, and `agent` methods.
The main class can be imported as `Stagehand` from `@browserbasehq/stagehand`.
**Key Classes:**
- `Stagehand`: Main orchestrator class providing `act`, `extract`, `observe`, and `agent` methods
- `context`: A `V3Context` object that manages browser contexts and pages
- `page`: Individual page objects accessed via `stagehand.context.pages()[i]` or created with `stagehand.context.newPage()`
## Initialize
```typescript
import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({
env: "LOCAL", // or "BROWSERBASE"
verbose: 2, // 0, 1, or 2
model: "openai/gpt-4.1-mini", // or any supported model
});
await stagehand.init();
// Access the browser context and pages
const page = stagehand.context.pages()[0];
const context = stagehand.context;
// Create new pages if needed
const page2 = await stagehand.context.newPage();
```
## Act
Actions are called on the `stagehand` instance (not the page). Use atomic, specific instructions:
```typescript
// Act on the current active page
await stagehand.act("click the sign in button");
// Act on a specific page (when you need to target a page that isn't currently active)
await stagehand.act("click the sign in button", { page: page2 });
```
**Important:** Act instructions should be atomic and specific:
- ✅ Good: "Click the sign in button" or "Type 'hello' into the search input"
- ❌ Bad: "Order me pizza" or "Type in the search bar and hit enter" (multi-step)
### Observe + Act Pattern (Recommended)
Cache the results of `observe` to avoid unexpected DOM changes:
```typescript
const instruction = "Click the sign in button";
// Get candidate actions
const actions = await stagehand.observe(instruction);
// Execute the first action
await stagehand.act(actions[0]);
```
To target a specific page:
```typescript
const actions = await stagehand.observe("select blue as the favorite color", {
page: page2,
});
await stagehand.act(actions[0], { page: page2 });
```
## Extract
Extract data from pages using natural language instructions. The `extract` method is called on the `stagehand` instance.
### Basic Extraction (with schema)
```typescript
import { z } from "zod";
// Extract with explicit schema
const data = await stagehand.extract(
"extract all apartment listings with prices and addresses",
z.object({
listings: z.array(
z.object({
price: z.string(),
address: z.string(),
}),
),
}),
);
console.log(data.listings);
```
### Simple Extraction (without schema)
```typescript
// Extract returns a default object with 'extraction' field
const result = await stagehand.extract("extract the sign in button text");
console.log(result);
// Output: { extraction: "Sign in" }
// Or destructure directly
const { extraction } = await stagehand.extract(
"extract the sign in button text",
);
console.log(extraction); // "Sign in"
```
### Targeted Extraction
Extract data from a specific element using a selector:
```typescript
const reason = await stagehand.extract(
"extract the reason why script injection fails",
z.string(),
{ selector: "/html/body/div[2]/div[3]/iframe/html/body/p[2]" },
);
```
### URL Extraction
When extracting links or URLs, use `z.string().url()`:
```typescript
const { links } = await stagehand.extract(
"extract all navigation links",
z.object({
links: z.array(z.string().url()),
}),
);
```
### Extracting from a Specific Page
```typescript
// Extract from a specific page (when you need to target a page that isn't currently active)
const data = await stagehand.extract(
"extract the placeholder text on the name field",
{ page: page2 },
);
```
## Observe
Plan actions before executing them. Returns an array of candidate actions:
```typescript
// Get c
gitextract_8uatdfoc/ ├── .changeset/ │ ├── config.json │ └── crazy-nights-prove.md ├── .cursorrules ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── actions/ │ │ ├── select-browserbase-region/ │ │ │ └── action.yml │ │ ├── setup-node-pnpm-turbo/ │ │ │ └── action.yml │ │ ├── upload-ctrf-report/ │ │ │ └── action.yml │ │ ├── upload-v8-coverage/ │ │ │ └── action.yml │ │ └── verify-chromium-launch/ │ │ └── action.yml │ ├── pull_request_template │ └── workflows/ │ ├── ci.yml │ ├── claude.yml │ ├── external-contributor-pr-approval-handoff.yml │ ├── external-contributor-pr.yml │ ├── feature-parity.yml │ ├── release.yml │ ├── stagehand-server-v3-release.yml │ ├── stagehand-server-v3-sea-build.yml │ ├── stagehand-server-v4-release.yml │ ├── stagehand-server-v4-sea-build.yml │ └── stainless.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode/ │ └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── claude.md ├── eslint.config.mjs ├── package.json ├── packages/ │ ├── README.md │ ├── cli/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── tests/ │ │ │ ├── cli.test.ts │ │ │ └── mode.test.ts │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.ts │ ├── core/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── examples/ │ │ │ ├── 2048.ts │ │ │ ├── CHANGELOG.md │ │ │ ├── actionable_observe_example.ts │ │ │ ├── agent-custom-tools.ts │ │ │ ├── agent_stream_example.ts │ │ │ ├── cua-example.ts │ │ │ ├── custom_client_aisdk.ts │ │ │ ├── custom_client_langchain.ts │ │ │ ├── custom_client_openai.ts │ │ │ ├── example.ts │ │ │ ├── external_clients/ │ │ │ │ ├── aisdk.ts │ │ │ │ ├── customOpenAI.ts │ │ │ │ └── langchain.ts │ │ │ ├── form_filling_sensible.ts │ │ │ ├── google_enter.ts │ │ │ ├── instructions.ts │ │ │ ├── integrations/ │ │ │ │ ├── exa.ts │ │ │ │ └── supabase.ts │ │ │ ├── mcp.ts │ │ │ ├── operator-example.ts │ │ │ ├── oss-cua-example.ts │ │ │ ├── parameterizeApiKey.ts │ │ │ ├── persist_logs_example.ts │ │ │ ├── tsconfig.json │ │ │ ├── v3/ │ │ │ │ ├── cuaReplay.ts │ │ │ │ ├── deepLocator.ts │ │ │ │ ├── dropdown.ts │ │ │ │ ├── highlight.ts │ │ │ │ ├── patchright.ts │ │ │ │ ├── playwright.ts │ │ │ │ ├── puppeteer.ts │ │ │ │ ├── recordVideo.ts │ │ │ │ ├── returnXpath.ts │ │ │ │ ├── shadowRoot.ts │ │ │ │ ├── targetedExtract.ts │ │ │ │ └── v3_agent.ts │ │ │ ├── v3_example.ts │ │ │ └── wordle.ts │ │ ├── lib/ │ │ │ ├── CHANGELOG.md │ │ │ ├── inference.ts │ │ │ ├── inferenceLogUtils.ts │ │ │ ├── logger.ts │ │ │ ├── modelUtils.ts │ │ │ ├── prompt.ts │ │ │ ├── utils.ts │ │ │ ├── v3/ │ │ │ │ ├── agent/ │ │ │ │ │ ├── AgentClient.ts │ │ │ │ │ ├── AgentProvider.ts │ │ │ │ │ ├── AnthropicCUAClient.ts │ │ │ │ │ ├── GoogleCUAClient.ts │ │ │ │ │ ├── MicrosoftCUAClient.ts │ │ │ │ │ ├── OpenAICUAClient.ts │ │ │ │ │ ├── prompts/ │ │ │ │ │ │ └── agentSystemPrompt.ts │ │ │ │ │ ├── tools/ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── act.ts │ │ │ │ │ │ ├── ariaTree.ts │ │ │ │ │ │ ├── braveSearch.ts │ │ │ │ │ │ ├── browserbaseSearch.ts │ │ │ │ │ │ ├── click.ts │ │ │ │ │ │ ├── clickAndHold.ts │ │ │ │ │ │ ├── dragAndDrop.ts │ │ │ │ │ │ ├── extract.ts │ │ │ │ │ │ ├── fillFormVision.ts │ │ │ │ │ │ ├── fillform.ts │ │ │ │ │ │ ├── goto.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── keys.ts │ │ │ │ │ │ ├── navback.ts │ │ │ │ │ │ ├── screenshot.ts │ │ │ │ │ │ ├── scroll.ts │ │ │ │ │ │ ├── think.ts │ │ │ │ │ │ ├── type.ts │ │ │ │ │ │ └── wait.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── actionMapping.ts │ │ │ │ │ ├── captchaSolver.ts │ │ │ │ │ ├── coordinateNormalization.ts │ │ │ │ │ ├── cuaKeyMapping.ts │ │ │ │ │ ├── googleCustomToolHandler.ts │ │ │ │ │ ├── handleDoneToolCall.ts │ │ │ │ │ ├── imageCompression.ts │ │ │ │ │ ├── messageProcessing.ts │ │ │ │ │ ├── screenshotHandler.ts │ │ │ │ │ ├── validateExperimentalFeatures.ts │ │ │ │ │ ├── variables.ts │ │ │ │ │ └── xpath.ts │ │ │ │ ├── api.ts │ │ │ │ ├── cache/ │ │ │ │ │ ├── ActCache.ts │ │ │ │ │ ├── AgentCache.ts │ │ │ │ │ ├── CacheStorage.ts │ │ │ │ │ ├── serverAgentCache.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── cli.js │ │ │ │ ├── dom/ │ │ │ │ │ ├── a11yScripts/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── genA11yScripts.ts │ │ │ │ │ ├── genDomScripts.ts │ │ │ │ │ ├── genLocatorScripts.ts │ │ │ │ │ ├── genScreenshotScripts.ts │ │ │ │ │ ├── global.d.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── locatorScripts/ │ │ │ │ │ │ ├── counts.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── scripts.ts │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── waitForSelector.ts │ │ │ │ │ │ ├── xpathParser.ts │ │ │ │ │ │ └── xpathResolver.ts │ │ │ │ │ ├── piercer.entry.ts │ │ │ │ │ ├── piercer.runtime.ts │ │ │ │ │ ├── rerenderMissingShadows.entry.ts │ │ │ │ │ ├── rerenderMissingShadows.runtime.ts │ │ │ │ │ └── screenshotScripts/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── resolveMaskRect.ts │ │ │ │ ├── external_clients/ │ │ │ │ │ ├── aisdk.ts │ │ │ │ │ └── customOpenAI.ts │ │ │ │ ├── flowlogger/ │ │ │ │ │ ├── EventEmitter.ts │ │ │ │ │ ├── EventSink.ts │ │ │ │ │ ├── EventStore.ts │ │ │ │ │ ├── FlowLogger.ts │ │ │ │ │ └── prettify.ts │ │ │ │ ├── handlers/ │ │ │ │ │ ├── actHandler.ts │ │ │ │ │ ├── extractHandler.ts │ │ │ │ │ ├── handlerUtils/ │ │ │ │ │ │ ├── actHandlerUtils.ts │ │ │ │ │ │ └── timeoutGuard.ts │ │ │ │ │ ├── observeHandler.ts │ │ │ │ │ ├── v3AgentHandler.ts │ │ │ │ │ └── v3CuaAgentHandler.ts │ │ │ │ ├── index.ts │ │ │ │ ├── launch/ │ │ │ │ │ ├── browserbase.ts │ │ │ │ │ └── local.ts │ │ │ │ ├── llm/ │ │ │ │ │ ├── AnthropicClient.ts │ │ │ │ │ ├── CerebrasClient.ts │ │ │ │ │ ├── GoogleClient.ts │ │ │ │ │ ├── GroqClient.ts │ │ │ │ │ ├── LLMClient.ts │ │ │ │ │ ├── LLMProvider.ts │ │ │ │ │ ├── OpenAIClient.ts │ │ │ │ │ └── aisdk.ts │ │ │ │ ├── logger.ts │ │ │ │ ├── mcp/ │ │ │ │ │ ├── connection.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── runtimePaths.ts │ │ │ │ ├── shutdown/ │ │ │ │ │ ├── cleanupLocal.ts │ │ │ │ │ ├── supervisor.ts │ │ │ │ │ └── supervisorClient.ts │ │ │ │ ├── timeoutConfig.ts │ │ │ │ ├── types/ │ │ │ │ │ ├── private/ │ │ │ │ │ │ ├── agent.ts │ │ │ │ │ │ ├── api.ts │ │ │ │ │ │ ├── cache.ts │ │ │ │ │ │ ├── evaluator.ts │ │ │ │ │ │ ├── handlers.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── internal.ts │ │ │ │ │ │ ├── locator.ts │ │ │ │ │ │ ├── network.ts │ │ │ │ │ │ ├── shutdown.ts │ │ │ │ │ │ ├── shutdownErrors.ts │ │ │ │ │ │ └── snapshot.ts │ │ │ │ │ └── public/ │ │ │ │ │ ├── agent.ts │ │ │ │ │ ├── api.ts │ │ │ │ │ ├── apiErrors.ts │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── locator.ts │ │ │ │ │ ├── logs.ts │ │ │ │ │ ├── methods.ts │ │ │ │ │ ├── metrics.ts │ │ │ │ │ ├── model.ts │ │ │ │ │ ├── options.ts │ │ │ │ │ ├── page.ts │ │ │ │ │ ├── screenshotTypes.ts │ │ │ │ │ └── sdkErrors.ts │ │ │ │ ├── understudy/ │ │ │ │ │ ├── a11y/ │ │ │ │ │ │ └── snapshot/ │ │ │ │ │ │ ├── a11yTree.ts │ │ │ │ │ │ ├── activeElement.ts │ │ │ │ │ │ ├── capture.ts │ │ │ │ │ │ ├── coordinateResolver.ts │ │ │ │ │ │ ├── domTree.ts │ │ │ │ │ │ ├── focusSelectors.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── sessions.ts │ │ │ │ │ │ ├── treeFormatUtils.ts │ │ │ │ │ │ └── xpathUtils.ts │ │ │ │ │ ├── a11yInvocation.ts │ │ │ │ │ ├── cdp.ts │ │ │ │ │ ├── consoleMessage.ts │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── cookies.ts │ │ │ │ │ ├── deepLocator.ts │ │ │ │ │ ├── executionContextRegistry.ts │ │ │ │ │ ├── fileUploadUtils.ts │ │ │ │ │ ├── frame.ts │ │ │ │ │ ├── frameLocator.ts │ │ │ │ │ ├── frameRegistry.ts │ │ │ │ │ ├── initScripts.ts │ │ │ │ │ ├── lifecycleWatcher.ts │ │ │ │ │ ├── locator.ts │ │ │ │ │ ├── locatorInvocation.ts │ │ │ │ │ ├── navigationResponseTracker.ts │ │ │ │ │ ├── networkManager.ts │ │ │ │ │ ├── page.ts │ │ │ │ │ ├── piercer.ts │ │ │ │ │ ├── response.ts │ │ │ │ │ ├── screenshotUtils.ts │ │ │ │ │ └── selectorResolver.ts │ │ │ │ ├── v3.ts │ │ │ │ └── zodCompat.ts │ │ │ └── v3Evaluator.ts │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── build-cjs.ts │ │ │ ├── build-esm.ts │ │ │ ├── coverage.ts │ │ │ ├── gen-version.ts │ │ │ ├── normalize-v8-coverage.ts │ │ │ ├── prepare.js │ │ │ ├── test-core.ts │ │ │ ├── test-e2e.ts │ │ │ └── test-utils.ts │ │ ├── tests/ │ │ │ ├── cache-variables.test.ts │ │ │ ├── integration/ │ │ │ │ ├── agent-abort-signal.spec.ts │ │ │ │ ├── agent-cache-self-heal.spec.ts │ │ │ │ ├── agent-callbacks.spec.ts │ │ │ │ ├── agent-captcha-autosolve.spec.ts │ │ │ │ ├── agent-experimental-validation.spec.ts │ │ │ │ ├── agent-hybrid-mode.spec.ts │ │ │ │ ├── agent-message-continuation.spec.ts │ │ │ │ ├── agent-streaming.spec.ts │ │ │ │ ├── cdp-close-api-region.spec.ts │ │ │ │ ├── cdp-connection-close.spec.ts │ │ │ │ ├── cdp-session-detached.spec.ts │ │ │ │ ├── click-count.spec.ts │ │ │ │ ├── connect-to-existing-browser.spec.ts │ │ │ │ ├── context-addInitScript.spec.ts │ │ │ │ ├── context-extra-http-headers.spec.ts │ │ │ │ ├── cookies.spec.ts │ │ │ │ ├── default-page-tracking.spec.ts │ │ │ │ ├── downloads.spec.ts │ │ │ │ ├── flowLogger.spec.ts │ │ │ │ ├── frame-get-location-and-click.spec.ts │ │ │ │ ├── iframe-ctx-addInitScript-race.spec.ts │ │ │ │ ├── iframe-ctx-addInitScript.spec.ts │ │ │ │ ├── keep-alive.child.ts │ │ │ │ ├── keep-alive.spec.ts │ │ │ │ ├── keyboard.spec.ts │ │ │ │ ├── locator-backend-node-id.spec.ts │ │ │ │ ├── locator-content-methods.spec.ts │ │ │ │ ├── locator-count-iframe.spec.ts │ │ │ │ ├── locator-count.spec.ts │ │ │ │ ├── locator-fill.spec.ts │ │ │ │ ├── locator-input-methods.spec.ts │ │ │ │ ├── locator-nth.spec.ts │ │ │ │ ├── locator-select-option.spec.ts │ │ │ │ ├── logger-initialization.spec.ts │ │ │ │ ├── multi-instance-logger.spec.ts │ │ │ │ ├── nested-div.spec.ts │ │ │ │ ├── page-addInitScript.spec.ts │ │ │ │ ├── page-console.spec.ts │ │ │ │ ├── page-drag-and-drop.spec.ts │ │ │ │ ├── page-extra-http-headers.spec.ts │ │ │ │ ├── page-goto-response.spec.ts │ │ │ │ ├── page-hover.spec.ts │ │ │ │ ├── page-screenshot.spec.ts │ │ │ │ ├── page-scroll.spec.ts │ │ │ │ ├── page-send-cdp.spec.ts │ │ │ │ ├── perform-understudy-method.spec.ts │ │ │ │ ├── setinputfiles.spec.ts │ │ │ │ ├── shadow-iframe-oopif.spec.ts │ │ │ │ ├── shadow-iframe-spif.spec.ts │ │ │ │ ├── testUtils.ts │ │ │ │ ├── text-selector-innermost.spec.ts │ │ │ │ ├── timeouts.spec.ts │ │ │ │ ├── user-data-dir.spec.ts │ │ │ │ ├── v3.config.ts │ │ │ │ ├── v3.dynamic.config.ts │ │ │ │ ├── v3.playwright.config.ts │ │ │ │ ├── wait-for-selector.spec.ts │ │ │ │ ├── wait-for-timeout.spec.ts │ │ │ │ └── xpath-for-location-deep.spec.ts │ │ │ └── unit/ │ │ │ ├── agent-captcha-hooks.test.ts │ │ │ ├── agent-execution-model.test.ts │ │ │ ├── api-multiregion.test.ts │ │ │ ├── browserbase-session-accessors.test.ts │ │ │ ├── cache-llm-resolution.test.ts │ │ │ ├── captcha-solver.test.ts │ │ │ ├── cdp-connection-close.test.ts │ │ │ ├── context-extra-http-headers.test.ts │ │ │ ├── cookies.test.ts │ │ │ ├── flowlogger-capturing-cdp.test.ts │ │ │ ├── flowlogger-capturing-llm.test.ts │ │ │ ├── flowlogger-eventstore.test.ts │ │ │ ├── helpers/ │ │ │ │ └── mockCDPSession.ts │ │ │ ├── llm-provider.test.ts │ │ │ ├── model-deprecation.test.ts │ │ │ ├── model-utils.test.ts │ │ │ ├── openai-cua-client.test.ts │ │ │ ├── page-extra-http-headers.test.ts │ │ │ ├── page-snapshot.test.ts │ │ │ ├── public-api/ │ │ │ │ ├── export-surface.test.ts │ │ │ │ ├── llm-and-agents.test.ts │ │ │ │ ├── public-error-types.test.ts │ │ │ │ ├── public-types.test.ts │ │ │ │ ├── runtime-utils.test.ts │ │ │ │ ├── schema-utils.test.ts │ │ │ │ ├── timeout-error-types.test.ts │ │ │ │ ├── tool-type-export.test.ts │ │ │ │ └── v3-core.test.ts │ │ │ ├── safety-confirmation.test.ts │ │ │ ├── snapshot-a11y-resolvers.test.ts │ │ │ ├── snapshot-a11y-tree-utils.test.ts │ │ │ ├── snapshot-capture-orchestration.test.ts │ │ │ ├── snapshot-cbor.test.ts │ │ │ ├── snapshot-dom-session-builders.test.ts │ │ │ ├── snapshot-dom-tree-utils.test.ts │ │ │ ├── snapshot-focus-selectors-utils.test.ts │ │ │ ├── snapshot-frame-merge.test.ts │ │ │ ├── snapshot-tree-format-utils.test.ts │ │ │ ├── snapshot-xpath-utils.test.ts │ │ │ ├── timeout-handlers.test.ts │ │ │ ├── understudy-command-exception.test.ts │ │ │ ├── xpath-parser.test.ts │ │ │ ├── xpath-resolver.test.ts │ │ │ └── zod-enum-compatibility.test.ts │ │ ├── tsconfig.json │ │ ├── vitest.cjs.config.mjs │ │ ├── vitest.config.ts │ │ └── vitest.esm.config.mjs │ ├── docs/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── docs.json │ │ ├── language-selector.js │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── runtimePaths.js │ │ │ └── sync-sdk-docs.js │ │ ├── snippets/ │ │ │ ├── excalidraw.mdx │ │ │ └── v3-banner.mdx │ │ ├── v2/ │ │ │ ├── basics/ │ │ │ │ ├── act.mdx │ │ │ │ ├── agent.mdx │ │ │ │ ├── extract.mdx │ │ │ │ └── observe.mdx │ │ │ ├── best-practices/ │ │ │ │ ├── agent-fallbacks.mdx │ │ │ │ ├── build-agent.mdx │ │ │ │ ├── caching.mdx │ │ │ │ ├── computer-use.mdx │ │ │ │ ├── contributing.mdx │ │ │ │ ├── cost-optimization.mdx │ │ │ │ ├── deployments.mdx │ │ │ │ ├── mcp-integrations.mdx │ │ │ │ ├── playwright-interop.mdx │ │ │ │ ├── prompting-best-practices.mdx │ │ │ │ ├── speed-optimization.mdx │ │ │ │ ├── usecase-observe.mdx │ │ │ │ ├── user-data.mdx │ │ │ │ ├── using-multiple-tabs.mdx │ │ │ │ └── working-with-iframes.mdx │ │ │ ├── configuration/ │ │ │ │ ├── browser.mdx │ │ │ │ ├── evals.mdx │ │ │ │ ├── logging.mdx │ │ │ │ ├── models.mdx │ │ │ │ └── observability.mdx │ │ │ ├── first-steps/ │ │ │ │ ├── ai-rules.mdx │ │ │ │ ├── installation.mdx │ │ │ │ ├── introduction.mdx │ │ │ │ └── quickstart.mdx │ │ │ ├── integrations/ │ │ │ │ ├── crew-ai/ │ │ │ │ │ ├── configuration.mdx │ │ │ │ │ └── introduction.mdx │ │ │ │ ├── langchain/ │ │ │ │ │ ├── configuration.mdx │ │ │ │ │ └── introduction.mdx │ │ │ │ ├── mcp/ │ │ │ │ │ ├── configuration.mdx │ │ │ │ │ ├── introduction.mdx │ │ │ │ │ ├── setup.mdx │ │ │ │ │ └── tools.mdx │ │ │ │ └── vercel/ │ │ │ │ ├── configuration.mdx │ │ │ │ └── introduction.mdx │ │ │ └── references/ │ │ │ ├── act.mdx │ │ │ ├── agent.mdx │ │ │ ├── extract.mdx │ │ │ ├── observe.mdx │ │ │ └── stagehand.mdx │ │ └── v3/ │ │ ├── basics/ │ │ │ ├── act.mdx │ │ │ ├── agent.mdx │ │ │ ├── evals.mdx │ │ │ ├── extract.mdx │ │ │ └── observe.mdx │ │ ├── best-practices/ │ │ │ ├── agent-fallbacks.mdx │ │ │ ├── caching.mdx │ │ │ ├── computer-use.mdx │ │ │ ├── cost-optimization.mdx │ │ │ ├── deployments.mdx │ │ │ ├── deterministic-agent.mdx │ │ │ ├── history.mdx │ │ │ ├── mcp-integrations.mdx │ │ │ ├── prompting-best-practices.mdx │ │ │ ├── speed-optimization.mdx │ │ │ ├── usecase-observe.mdx │ │ │ ├── user-data.mdx │ │ │ └── using-multiple-tabs.mdx │ │ ├── configuration/ │ │ │ ├── browser.mdx │ │ │ ├── logging.mdx │ │ │ ├── models.mdx │ │ │ └── observability.mdx │ │ ├── first-steps/ │ │ │ ├── ai-rules.mdx │ │ │ ├── installation.mdx │ │ │ ├── introduction.mdx │ │ │ └── quickstart.mdx │ │ ├── integrations/ │ │ │ ├── convex/ │ │ │ │ ├── configuration.mdx │ │ │ │ └── introduction.mdx │ │ │ ├── crew-ai/ │ │ │ │ ├── configuration.mdx │ │ │ │ └── introduction.mdx │ │ │ ├── langchain/ │ │ │ │ ├── configuration.mdx │ │ │ │ └── introduction.mdx │ │ │ ├── mcp/ │ │ │ │ ├── configuration.mdx │ │ │ │ ├── introduction.mdx │ │ │ │ ├── setup.mdx │ │ │ │ └── tools.mdx │ │ │ ├── playwright.mdx │ │ │ ├── puppeteer.mdx │ │ │ ├── selenium.mdx │ │ │ └── vercel/ │ │ │ ├── configuration.mdx │ │ │ └── introduction.mdx │ │ ├── migrations/ │ │ │ ├── python.mdx │ │ │ └── v2.mdx │ │ ├── references/ │ │ │ ├── act.mdx │ │ │ ├── agent.mdx │ │ │ ├── context.mdx │ │ │ ├── deeplocator.mdx │ │ │ ├── extract.mdx │ │ │ ├── locator.mdx │ │ │ ├── observe.mdx │ │ │ ├── page.mdx │ │ │ ├── response.mdx │ │ │ └── stagehand.mdx │ │ └── sdk/ │ │ ├── go.mdx │ │ ├── java.mdx │ │ ├── python.mdx │ │ └── ruby.mdx │ ├── evals/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── args.ts │ │ ├── assets/ │ │ │ ├── cart.html │ │ │ └── peeler.html │ │ ├── browserbaseCleanup.ts │ │ ├── cli.ts │ │ ├── datasets/ │ │ │ ├── gaia/ │ │ │ │ └── GAIA_web.jsonl │ │ │ ├── onlineMind2Web/ │ │ │ │ └── onlineMind2Web.jsonl │ │ │ ├── webtailbench/ │ │ │ │ └── WebTailBench_data.jsonl │ │ │ └── webvoyager/ │ │ │ └── WebVoyager_data.jsonl │ │ ├── env.ts │ │ ├── evals.config.json │ │ ├── index.eval.ts │ │ ├── initV3.ts │ │ ├── lib/ │ │ │ └── AISdkClientWrapped.ts │ │ ├── llm_clients/ │ │ │ ├── hn_aisdk.ts │ │ │ ├── hn_customOpenAI.ts │ │ │ └── hn_langchain.ts │ │ ├── logger.ts │ │ ├── package.json │ │ ├── run.ts │ │ ├── runtimePaths.ts │ │ ├── scoring.ts │ │ ├── scripts/ │ │ │ ├── build-cli.ts │ │ │ ├── build-esm.ts │ │ │ └── test-evals.ts │ │ ├── suites/ │ │ │ ├── gaia.ts │ │ │ ├── onlineMind2Web.ts │ │ │ ├── webtailbench.ts │ │ │ └── webvoyager.ts │ │ ├── summary.ts │ │ ├── taskConfig.ts │ │ ├── tasks/ │ │ │ ├── agent/ │ │ │ │ ├── alibaba_supplier_search.ts │ │ │ │ ├── all_recipes.ts │ │ │ │ ├── amazon_shoes_cart.ts │ │ │ │ ├── apple_trade_in.ts │ │ │ │ ├── apple_tv.ts │ │ │ │ ├── arxiv_gpt_report.ts │ │ │ │ ├── columbia_tuition.ts │ │ │ │ ├── flipkart_laptops.ts │ │ │ │ ├── gaia.ts │ │ │ │ ├── github.ts │ │ │ │ ├── github_react_version.ts │ │ │ │ ├── google_flights.ts │ │ │ │ ├── google_maps.ts │ │ │ │ ├── google_maps_2.ts │ │ │ │ ├── google_maps_3.ts │ │ │ │ ├── google_shopping.ts │ │ │ │ ├── hotel_booking.ts │ │ │ │ ├── hotels_paris_amenities.ts │ │ │ │ ├── hugging_face.ts │ │ │ │ ├── iframe_form.ts │ │ │ │ ├── iframe_form_multiple.ts │ │ │ │ ├── instacart_organic_bananas.ts │ │ │ │ ├── kayak.ts │ │ │ │ ├── kfc_tenders_combo.ts │ │ │ │ ├── kith.ts │ │ │ │ ├── made_in_china_supplier.ts │ │ │ │ ├── nba_trades.ts │ │ │ │ ├── nvidia_hgx_driver.ts │ │ │ │ ├── oed_word_search.ts │ │ │ │ ├── onlineMind2Web.ts │ │ │ │ ├── radiotimes_tv_schedule.ts │ │ │ │ ├── redfin_apartment_rental.ts │ │ │ │ ├── sf_library_card.ts │ │ │ │ ├── sf_library_card_multiple.ts │ │ │ │ ├── sign_in.ts │ │ │ │ ├── steam_games.ts │ │ │ │ ├── thegamer_opinion_article.ts │ │ │ │ ├── trailhead_superbadge.ts │ │ │ │ ├── trivago.ts │ │ │ │ ├── trustpilot_hr_companies.ts │ │ │ │ ├── ubereats.ts │ │ │ │ ├── uniqlo_mens_blazers.ts │ │ │ │ ├── webmd_audiologist_search.ts │ │ │ │ ├── webmd_ovulation_calculator.ts │ │ │ │ ├── webtailbench.ts │ │ │ │ └── webvoyager.ts │ │ │ ├── allrecipes.ts │ │ │ ├── amazon_add_to_cart.ts │ │ │ ├── apple.ts │ │ │ ├── arxiv.ts │ │ │ ├── bidnet.ts │ │ │ ├── checkboxes.ts │ │ │ ├── combination_sauce.ts │ │ │ ├── costar.ts │ │ │ ├── csr_in_oopif.ts │ │ │ ├── csr_in_spif.ts │ │ │ ├── custom_dropdown.ts │ │ │ ├── dropdown.ts │ │ │ ├── extract_aigrant_companies.ts │ │ │ ├── extract_aigrant_targeted.ts │ │ │ ├── extract_aigrant_targeted_2.ts │ │ │ ├── extract_apartments.ts │ │ │ ├── extract_area_codes.ts │ │ │ ├── extract_baptist_health.ts │ │ │ ├── extract_capacitor_info.ts │ │ │ ├── extract_collaborators.ts │ │ │ ├── extract_csa.ts │ │ │ ├── extract_geniusee.ts │ │ │ ├── extract_geniusee_2.ts │ │ │ ├── extract_github_commits.ts │ │ │ ├── extract_github_stars.ts │ │ │ ├── extract_hamilton_weather.ts │ │ │ ├── extract_jfk_links.ts │ │ │ ├── extract_jstor_news.ts │ │ │ ├── extract_memorial_healthcare.ts │ │ │ ├── extract_nhl_stats.ts │ │ │ ├── extract_partners.ts │ │ │ ├── extract_press_releases.ts │ │ │ ├── extract_professional_info.ts │ │ │ ├── extract_public_notices.ts │ │ │ ├── extract_recipe.ts │ │ │ ├── extract_regulations_table.ts │ │ │ ├── extract_repo_name.ts │ │ │ ├── extract_resistor_info.ts │ │ │ ├── extract_rockauto.ts │ │ │ ├── extract_single_link.ts │ │ │ ├── extract_snowshoeing_destinations.ts │ │ │ ├── extract_staff_members.ts │ │ │ ├── extract_zillow.ts │ │ │ ├── google_flights.ts │ │ │ ├── heal_custom_dropdown.ts │ │ │ ├── heal_scroll_50.ts │ │ │ ├── heal_simple_google_search.ts │ │ │ ├── hidden_input_dropdown.ts │ │ │ ├── history.ts │ │ │ ├── homedepot.ts │ │ │ ├── iframe_form_filling.ts │ │ │ ├── iframe_hn.ts │ │ │ ├── iframe_same_proc.ts │ │ │ ├── iframe_scroll.ts │ │ │ ├── iframes_nested.ts │ │ │ ├── imdb_movie_details.ts │ │ │ ├── instructions.ts │ │ │ ├── ionwave.ts │ │ │ ├── ionwave_observe.ts │ │ │ ├── login.ts │ │ │ ├── multi_tab.ts │ │ │ ├── namespace_xpath.ts │ │ │ ├── nested_iframes_2.ts │ │ │ ├── next_chunk.ts │ │ │ ├── no_js_click.ts │ │ │ ├── nonsense_action.ts │ │ │ ├── observe_amazon_add_to_cart.ts │ │ │ ├── observe_github.ts │ │ │ ├── observe_iframes1.ts │ │ │ ├── observe_iframes2.ts │ │ │ ├── observe_simple_google_search.ts │ │ │ ├── observe_taxes.ts │ │ │ ├── observe_vantechjournal.ts │ │ │ ├── observe_yc_startup.ts │ │ │ ├── oopif_in_csr.ts │ │ │ ├── oopif_in_osr.ts │ │ │ ├── os_dropdown.ts │ │ │ ├── osr_in_oopif.ts │ │ │ ├── osr_in_spif.ts │ │ │ ├── panamcs.ts │ │ │ ├── peeler_complex.ts │ │ │ ├── prev_chunk.ts │ │ │ ├── radio_btn.ts │ │ │ ├── rakuten_jp.ts │ │ │ ├── sciquest.ts │ │ │ ├── scroll_50.ts │ │ │ ├── scroll_75.ts │ │ │ ├── shadow_dom.ts │ │ │ ├── simple_google_search.ts │ │ │ ├── spif_in_csr.ts │ │ │ ├── spif_in_osr.ts │ │ │ ├── stock_x.ts │ │ │ ├── tab_handling.ts │ │ │ ├── ted_talk.ts │ │ │ ├── vanta_h.ts │ │ │ ├── vantechjournal.ts │ │ │ ├── wichita.ts │ │ │ └── wikipedia.ts │ │ ├── tsconfig.json │ │ ├── types/ │ │ │ ├── evals.ts │ │ │ └── screenshotCollector.ts │ │ ├── utils/ │ │ │ ├── ScreenshotCollector.ts │ │ │ └── imageResize.ts │ │ └── utils.ts │ ├── server-v3/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── SDK_RELEASE_WORKFLOW.md │ │ ├── openapi.v3.yaml │ │ ├── package.json │ │ ├── scripts/ │ │ │ ├── build-sea.ts │ │ │ ├── gen-openapi.ts │ │ │ ├── runtimePaths.ts │ │ │ └── test-server.ts │ │ ├── src/ │ │ │ ├── lib/ │ │ │ │ ├── InMemorySessionStore.ts │ │ │ │ ├── SessionStore.ts │ │ │ │ ├── auth.ts │ │ │ │ ├── env.ts │ │ │ │ ├── errorHandler.ts │ │ │ │ ├── header.ts │ │ │ │ ├── logging/ │ │ │ │ │ └── index.ts │ │ │ │ ├── response.ts │ │ │ │ ├── sessionStoreManager.ts │ │ │ │ ├── stream.ts │ │ │ │ └── utils.ts │ │ │ ├── routes/ │ │ │ │ ├── healthcheck.ts │ │ │ │ ├── readiness.ts │ │ │ │ └── v1/ │ │ │ │ └── sessions/ │ │ │ │ ├── _id/ │ │ │ │ │ ├── act.ts │ │ │ │ │ ├── agentExecute.ts │ │ │ │ │ ├── end.ts │ │ │ │ │ ├── extract.ts │ │ │ │ │ ├── navigate.ts │ │ │ │ │ ├── observe.ts │ │ │ │ │ └── replay.ts │ │ │ │ └── start.ts │ │ │ ├── sea-entry.ts │ │ │ ├── server.ts │ │ │ └── types/ │ │ │ ├── error.ts │ │ │ ├── fastify.d.ts │ │ │ ├── model.ts │ │ │ └── rrweb.ts │ │ ├── test/ │ │ │ └── integration/ │ │ │ ├── api-server-cache.test.ts │ │ │ ├── utils.ts │ │ │ └── v3/ │ │ │ ├── act.test.ts │ │ │ ├── agentExecute.test.ts │ │ │ ├── end.test.ts │ │ │ ├── extract.test.ts │ │ │ ├── multiRegion.test.ts │ │ │ ├── navigate.test.ts │ │ │ ├── observe.test.ts │ │ │ ├── replay.test.ts │ │ │ └── start.test.ts │ │ ├── tsconfig.json │ │ ├── tsconfig.tests.json │ │ └── vitest.config.ts │ └── server-v4/ │ ├── CHANGELOG.md │ ├── README.md │ ├── openapi.v4.yaml │ ├── package.json │ ├── scripts/ │ │ ├── build-sea.ts │ │ ├── gen-openapi.ts │ │ ├── runtimePaths.ts │ │ └── test-server.ts │ ├── src/ │ │ ├── routes/ │ │ │ ├── healthcheck.ts │ │ │ ├── readiness.ts │ │ │ └── v4/ │ │ │ ├── browsersession/ │ │ │ │ ├── _id/ │ │ │ │ │ ├── end.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── action/ │ │ │ │ │ ├── _actionId.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── activePage.ts │ │ │ │ ├── addCookies.ts │ │ │ │ ├── addInitScript.ts │ │ │ │ ├── awaitActivePage.ts │ │ │ │ ├── browserbaseDebugURL.ts │ │ │ │ ├── browserbaseSessionID.ts │ │ │ │ ├── browserbaseSessionURL.ts │ │ │ │ ├── clearCookies.ts │ │ │ │ ├── configuredViewport.ts │ │ │ │ ├── connectURL.ts │ │ │ │ ├── cookies.ts │ │ │ │ ├── getFullFrameTreeByMainFrameId.ts │ │ │ │ ├── index.ts │ │ │ │ ├── newPage.ts │ │ │ │ ├── pages.ts │ │ │ │ ├── resolvePageByMainFrameId.ts │ │ │ │ ├── routes.ts │ │ │ │ ├── setExtraHTTPHeaders.ts │ │ │ │ └── shared.ts │ │ │ ├── page/ │ │ │ │ ├── action/ │ │ │ │ │ ├── _actionId.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── addInitScript.ts │ │ │ │ ├── asProtocolFrameTree.ts │ │ │ │ ├── click.ts │ │ │ │ ├── close.ts │ │ │ │ ├── dragAndDrop.ts │ │ │ │ ├── enableCursorOverlay.ts │ │ │ │ ├── evaluate.ts │ │ │ │ ├── frames.ts │ │ │ │ ├── getFullFrameTree.ts │ │ │ │ ├── getOrdinal.ts │ │ │ │ ├── goBack.ts │ │ │ │ ├── goForward.ts │ │ │ │ ├── goto.ts │ │ │ │ ├── hover.ts │ │ │ │ ├── keyPress.ts │ │ │ │ ├── listAllFrameIds.ts │ │ │ │ ├── mainFrame.ts │ │ │ │ ├── mainFrameId.ts │ │ │ │ ├── reload.ts │ │ │ │ ├── routes.ts │ │ │ │ ├── screenshot.ts │ │ │ │ ├── scroll.ts │ │ │ │ ├── sendCDP.ts │ │ │ │ ├── setExtraHTTPHeaders.ts │ │ │ │ ├── setViewportSize.ts │ │ │ │ ├── shared.ts │ │ │ │ ├── snapshot.ts │ │ │ │ ├── targetId.ts │ │ │ │ ├── title.ts │ │ │ │ ├── type.ts │ │ │ │ ├── url.ts │ │ │ │ ├── waitForLoadState.ts │ │ │ │ ├── waitForMainLoadState.ts │ │ │ │ ├── waitForSelector.ts │ │ │ │ └── waitForTimeout.ts │ │ │ └── pluginUtils.ts │ │ ├── schemas/ │ │ │ └── v4/ │ │ │ ├── browserSession.ts │ │ │ └── page.ts │ │ ├── sea-entry.ts │ │ ├── server.ts │ │ └── types/ │ │ ├── error.ts │ │ ├── fastify.d.ts │ │ ├── model.ts │ │ └── rrweb.ts │ ├── test/ │ │ └── integration/ │ │ ├── utils.ts │ │ └── v4/ │ │ ├── browsersession.test.ts │ │ └── page.test.ts │ ├── tsconfig.json │ ├── tsconfig.tests.json │ └── vitest.config.ts ├── pnpm-workspace.yaml ├── stainless.yml ├── tsconfig.base.json ├── tsconfig.json └── turbo.json
Showing preview only (206K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2353 symbols across 284 files)
FILE: packages/cli/src/index.ts
type BrowseContext (line 25) | type BrowseContext = Stagehand["context"];
constant SOCKET_DIR (line 29) | const SOCKET_DIR = os.tmpdir();
function getSocketPath (line 31) | function getSocketPath(session: string): string {
function getLockPath (line 35) | function getLockPath(session: string): string {
function acquireLock (line 43) | async function acquireLock(
function releaseLock (line 79) | async function releaseLock(session: string): Promise<void> {
function isSocketConnectable (line 88) | async function isSocketConnectable(
function waitForSocketReady (line 115) | async function waitForSocketReady(
function getPidPath (line 130) | function getPidPath(session: string): string {
function getWsPath (line 134) | function getWsPath(session: string): string {
function getChromePidPath (line 138) | function getChromePidPath(session: string): string {
function getNetworkDir (line 142) | function getNetworkDir(session: string): string {
function getModePath (line 146) | function getModePath(session: string): string {
function getModeOverridePath (line 150) | function getModeOverridePath(session: string): string {
function getContextPath (line 154) | function getContextPath(session: string): string {
type BrowseMode (line 158) | type BrowseMode = "browserbase" | "local";
function hasBrowserbaseCredentials (line 160) | function hasBrowserbaseCredentials(): boolean {
function assertModeSupported (line 164) | function assertModeSupported(mode: BrowseMode): void {
function toModeTarget (line 172) | function toModeTarget(mode: BrowseMode): "local" | "remote" {
function readCurrentMode (line 176) | async function readCurrentMode(session: string): Promise<BrowseMode | nu...
function getDesiredMode (line 189) | async function getDesiredMode(session: string): Promise<BrowseMode> {
function isDaemonRunning (line 199) | async function isDaemonRunning(session: string): Promise<boolean> {
function cleanupStaleFiles (line 226) | async function cleanupStaleFiles(session: string): Promise<void> {
function cleanupDaemonStateFiles (line 241) | async function cleanupDaemonStateFiles(session: string): Promise<void> {
function killChromeProcesses (line 250) | async function killChromeProcesses(session: string): Promise<boolean> {
type DaemonRequest (line 275) | interface DaemonRequest {
type DaemonResponse (line 280) | interface DaemonResponse {
constant DEFAULT_VIEWPORT (line 289) | const DEFAULT_VIEWPORT = { width: 1288, height: 711 };
function runDaemon (line 291) | async function runDaemon(session: string, headless: boolean): Promise<vo...
type PendingRequest (line 476) | interface PendingRequest {
function sanitizeForFilename (line 493) | function sanitizeForFilename(str: string, maxLen: number = 30): string {
function getRequestDirName (line 502) | function getRequestDirName(
function writeRequestToFs (line 519) | async function writeRequestToFs(
function writeResponseToFs (line 556) | async function writeResponseToFs(
function parseRef (line 583) | function parseRef(selector: string): string | null {
function resolveSelector (line 612) | function resolveSelector(selector: string): string {
function executeCommand (line 628) | async function executeCommand(
function sendCommandOnce (line 1235) | async function sendCommandOnce(
function sendCommand (line 1286) | async function sendCommand(
function stopDaemonAndCleanup (line 1337) | async function stopDaemonAndCleanup(session: string): Promise<void> {
function ensureDaemon (line 1347) | async function ensureDaemon(session: string, headless: boolean): Promise...
type GlobalOpts (line 1433) | interface GlobalOpts {
function getSession (line 1441) | function getSession(opts: GlobalOpts): string {
function isHeadless (line 1445) | function isHeadless(opts: GlobalOpts): boolean {
function output (line 1449) | function output(data: unknown, json: boolean): void {
function runCommand (line 1459) | async function runCommand(command: string, args: unknown[]): Promise<unk...
FILE: packages/cli/tests/cli.test.ts
constant CLI_PATH (line 21) | const CLI_PATH = path.join(__dirname, "../dist/index.js");
constant TEST_SESSION (line 24) | const TEST_SESSION = `test-${Date.now()}`;
function browse (line 27) | async function browse(
function parseJson (line 47) | function parseJson<T = Record<string, unknown>>(output: string): T {
function cleanupSession (line 56) | async function cleanupSession(session: string): Promise<void> {
FILE: packages/cli/tests/mode.test.ts
constant CLI_PATH (line 7) | const CLI_PATH = path.join(__dirname, "../dist/index.js");
constant TEST_SESSION (line 8) | const TEST_SESSION = `env-test-${Date.now()}`;
function browse (line 10) | async function browse(
function parseJson (line 29) | function parseJson<T = Record<string, unknown>>(output: string): T {
function cleanupSession (line 37) | async function cleanupSession(session: string): Promise<void> {
FILE: packages/core/examples/2048.ts
function example (line 4) | async function example() {
FILE: packages/core/examples/actionable_observe_example.ts
function example (line 17) | async function example() {
FILE: packages/core/examples/agent-custom-tools.ts
function main (line 35) | async function main() {
FILE: packages/core/examples/agent_stream_example.ts
function main (line 5) | async function main() {
FILE: packages/core/examples/cua-example.ts
function main (line 12) | async function main() {
FILE: packages/core/examples/custom_client_aisdk.ts
function example (line 13) | async function example() {
FILE: packages/core/examples/custom_client_langchain.ts
function example (line 11) | async function example() {
FILE: packages/core/examples/custom_client_openai.ts
function example (line 13) | async function example() {
FILE: packages/core/examples/example.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/external_clients/langchain.ts
class LangchainClient (line 16) | class LangchainClient extends LLMClient {
method constructor (line 20) | constructor(model: BaseChatModel) {
method createChatCompletion (line 25) | async createChatCompletion<T = ChatCompletion>({
FILE: packages/core/examples/form_filling_sensible.ts
function formFillingSensible (line 9) | async function formFillingSensible() {
FILE: packages/core/examples/google_enter.ts
function example (line 9) | async function example() {
FILE: packages/core/examples/instructions.ts
function example (line 6) | async function example() {
FILE: packages/core/examples/integrations/exa.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/integrations/supabase.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/operator-example.ts
function main (line 13) | async function main() {
FILE: packages/core/examples/oss-cua-example.ts
function main (line 12) | async function main() {
FILE: packages/core/examples/parameterizeApiKey.ts
function example (line 14) | async function example() {
FILE: packages/core/examples/persist_logs_example.ts
function main (line 7) | async function main() {
FILE: packages/core/examples/v3/cuaReplay.ts
function runDemo (line 4) | async function runDemo(runNumber: number) {
function main (line 53) | async function main() {
FILE: packages/core/examples/v3/deepLocator.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/dropdown.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/highlight.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/patchright.ts
function example (line 5) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/playwright.ts
function example (line 5) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/puppeteer.ts
function example (line 4) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/recordVideo.ts
function recordPlaywrightVideo (line 7) | async function recordPlaywrightVideo(stagehand: Stagehand): Promise<void> {
FILE: packages/core/examples/v3/returnXpath.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/shadowRoot.ts
function example (line 3) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/targetedExtract.ts
function example (line 4) | async function example(stagehand: Stagehand) {
FILE: packages/core/examples/v3/v3_agent.ts
constant INSTRUCTION (line 4) | const INSTRUCTION = "scroll down and click on the last hn story";
function main (line 6) | async function main() {
FILE: packages/core/examples/v3_example.ts
function example (line 4) | async function example(v3: V3) {
FILE: packages/core/examples/wordle.ts
function example (line 3) | async function example() {
FILE: packages/core/lib/inference.ts
function withLlmTimeout (line 24) | function withLlmTimeout<T>(promise: Promise<T>, operation: string): Prom...
function extract (line 32) | async function extract<T extends StagehandZodObject>({
function observe (line 240) | async function observe({
function act (line 389) | async function act({
FILE: packages/core/lib/inferenceLogUtils.ts
function ensureInferenceSummaryDir (line 7) | function ensureInferenceSummaryDir(): string {
function appendSummary (line 18) | function appendSummary<T>(inferenceType: string, entry: T) {
function getTimestamp (line 29) | function getTimestamp(): string {
function writeTimestampedTxtFile (line 40) | function writeTimestampedTxtFile(
function getSummaryJsonPath (line 70) | function getSummaryJsonPath(inferenceType: string): string {
function readSummaryFile (line 90) | function readSummaryFile<T>(inferenceType: string): Record<string, T[]> {
FILE: packages/core/lib/logger.ts
type LoggerOptions (line 12) | interface LoggerOptions {
function createLogger (line 22) | function createLogger(options: LoggerOptions = {}) {
function isTestEnvironment (line 62) | function isTestEnvironment(): boolean {
class StagehandLogger (line 93) | class StagehandLogger {
method constructor (line 106) | constructor(
method setVerbosity (line 140) | setVerbosity(level: 0 | 1 | 2) {
method log (line 162) | log(logLine: LogLine): void {
method formatAuxiliaryData (line 255) | private formatAuxiliaryData(auxiliary?: LogLine["auxiliary"]) {
method error (line 303) | error(message: string, data?: Record<string, unknown>): void {
method warn (line 311) | warn(message: string, data?: Record<string, unknown>): void {
method info (line 320) | info(message: string, data?: Record<string, unknown>): void {
method debug (line 328) | debug(message: string, data?: Record<string, unknown>): void {
method convertToAuxiliary (line 339) | private convertToAuxiliary(
FILE: packages/core/lib/modelUtils.ts
function extractModelName (line 8) | function extractModelName(
function splitModelName (line 15) | function splitModelName(model: string): {
function resolveModel (line 25) | function resolveModel(model: string | ModelConfiguration): {
FILE: packages/core/lib/prompt.ts
function buildUserInstructionsString (line 4) | function buildUserInstructionsString(
function buildExtractSystemPrompt (line 20) | function buildExtractSystemPrompt(
function buildExtractUserPrompt (line 65) | function buildExtractUserPrompt(
function buildMetadataSystemPrompt (line 93) | function buildMetadataSystemPrompt(): ChatMessage {
function buildMetadataPrompt (line 100) | function buildMetadataPrompt(
function buildObserveSystemPrompt (line 112) | function buildObserveSystemPrompt(
function buildObserveUserMessage (line 139) | function buildObserveUserMessage(
function buildActSystemPrompt (line 150) | function buildActSystemPrompt(
function buildActPrompt (line 171) | function buildActPrompt(
function buildStepTwoPrompt (line 215) | function buildStepTwoPrompt(
function buildOperatorSystemPrompt (line 249) | function buildOperatorSystemPrompt(goal: string): ChatMessage {
function buildCuaDefaultSystemPrompt (line 284) | function buildCuaDefaultSystemPrompt(): string {
function buildGoogleCUASystemPrompt (line 288) | function buildGoogleCUASystemPrompt(): ChatMessage {
FILE: packages/core/lib/utils.ts
constant ID_PATTERN (line 11) | const ID_PATTERN = /^\d+-\d+$/;
function getZFactory (line 18) | function getZFactory(schema: StagehandZodSchema): typeof z {
constant TYPE_NAME_MAP (line 22) | const TYPE_NAME_MAP: Record<string, string> = {
function getZ4Def (line 52) | function getZ4Def(schema: StagehandZodSchema) {
function getZ4Bag (line 58) | function getZ4Bag(schema: StagehandZodSchema) {
function getZ3Def (line 64) | function getZ3Def(schema: StagehandZodSchema) {
function getObjectShape (line 70) | function getObjectShape(
function getArrayElement (line 92) | function getArrayElement(
function getInnerType (line 100) | function getInnerType(
function getUnionOptions (line 108) | function getUnionOptions(
function getIntersectionSides (line 121) | function getIntersectionSides(schema: StagehandZodSchema): {
function getEnumValues (line 139) | function getEnumValues(schema: StagehandZodSchema): string[] | undefined {
function getLiteralValues (line 148) | function getLiteralValues(schema: StagehandZodSchema): unknown[] {
function getStringChecks (line 157) | function getStringChecks(schema: StagehandZodSchema): unknown[] {
function getStringFormat (line 166) | function getStringFormat(schema: StagehandZodSchema): string | undefined {
function getPipeEndpoints (line 179) | function getPipeEndpoints(schema: StagehandZodSchema): {
function getEffectsBaseSchema (line 193) | function getEffectsBaseSchema(
type SchemaInternals (line 199) | type SchemaInternals = {
function validateZodSchema (line 204) | function validateZodSchema(schema: StagehandZodSchema, data: unknown) {
function isRunningInBun (line 217) | function isRunningInBun(): boolean {
function decorateGeminiSchema (line 228) | function decorateGeminiSchema(
function toGeminiSchema (line 243) | function toGeminiSchema(zodSchema: StagehandZodSchema): Schema {
function getZodType (line 360) | function getZodType(schema: StagehandZodSchema): string {
function transformSchema (line 389) | function transformSchema(
function injectUrls (line 605) | function injectUrls(
function isKind (line 653) | function isKind(s: StagehandZodSchema, kind: string): boolean {
function makeIdStringSchema (line 661) | function makeIdStringSchema(orig: StagehandZodSchema): StagehandZodSchema {
function loadApiKeyFromEnv (line 706) | function loadApiKeyFromEnv(
function trimTrailingTextNode (line 739) | function trimTrailingTextNode(
function toTitleCase (line 745) | function toTitleCase(str: string): string {
type JsonSchemaProperty (line 753) | interface JsonSchemaProperty {
type JsonSchema (line 764) | interface JsonSchema extends JsonSchemaProperty {
function jsonSchemaToZod (line 773) | function jsonSchemaToZod(schema: JsonSchema): ZodTypeAny {
FILE: packages/core/lib/v3/agent/AgentClient.ts
method constructor (line 19) | constructor(
method setPreStepHook (line 49) | setPreStepHook(handler: () => Promise<void>): void {
method addContextNote (line 57) | addContextNote(note: string): void {
FILE: packages/core/lib/v3/agent/AgentProvider.ts
class AgentProvider (line 36) | class AgentProvider {
method constructor (line 42) | constructor(logger: (message: LogLine) => void) {
method getClient (line 46) | getClient(
method getAgentProvider (line 115) | static getAgentProvider(modelName: string): AgentProviderType {
FILE: packages/core/lib/v3/agent/AnthropicCUAClient.ts
type ResponseInputItem (line 31) | type ResponseInputItem = AnthropicMessage | AnthropicToolResult;
class AnthropicCUAClient (line 37) | class AnthropicCUAClient extends AgentClient {
method constructor (line 49) | constructor(
method setViewport (line 86) | setViewport(width: number, height: number): void {
method setCurrentUrl (line 90) | setCurrentUrl(url: string): void {
method setScreenshotProvider (line 94) | setScreenshotProvider(provider: () => Promise<string>): void {
method setActionHandler (line 98) | setActionHandler(handler: (action: AgentAction) => Promise<void>): void {
method setTools (line 102) | setTools(tools: ToolSet): void {
method execute (line 111) | async execute(executionOptions: AgentExecutionOptions): Promise<AgentR...
method executeStep (line 221) | async executeStep(
method createInitialInputItems (line 400) | private createInitialInputItems(instruction: string): AnthropicMessage...
method getAction (line 414) | async getAction(inputItems: ResponseInputItem[]): Promise<{
method takeAction (line 559) | async takeAction(
method convertToolUseToAction (line 789) | private convertToolUseToAction(item: ToolUseItem): AgentAction | null {
method captureScreenshot (line 957) | async captureScreenshot(options?: {
FILE: packages/core/lib/v3/agent/GoogleCUAClient.ts
class GoogleCUAClient (line 47) | class GoogleCUAClient extends AgentClient {
method constructor (line 61) | constructor(
method setViewport (line 124) | public setViewport(width: number, height: number): void {
method setCurrentUrl (line 128) | setCurrentUrl(url: string): void {
method setScreenshotProvider (line 132) | setScreenshotProvider(provider: () => Promise<string>): void {
method setActionHandler (line 136) | setActionHandler(handler: (action: AgentAction) => Promise<void>): void {
method setTools (line 140) | setTools(tools: ToolSet): void {
method setSafetyConfirmationHandler (line 145) | setSafetyConfirmationHandler(handler?: SafetyConfirmationHandler): void {
method handleSafetyConfirmation (line 149) | private async handleSafetyConfirmation(
method updateGenerateContentConfig (line 203) | private updateGenerateContentConfig(): void {
method execute (line 227) | async execute(executionOptions: AgentExecutionOptions): Promise<AgentR...
method initializeHistory (line 316) | private async initializeHistory(instruction: string): Promise<void> {
method executeStep (line 345) | async executeStep(logger: (message: LogLine) => void): Promise<{
method processResponse (line 668) | private async processResponse(
method convertFunctionCallToAction (line 794) | private convertFunctionCallToAction(
method normalizeCoordinates (line 973) | private normalizeCoordinates(x: number, y: number): { x: number; y: nu...
method captureScreenshot (line 982) | async captureScreenshot(options?: {
FILE: packages/core/lib/v3/agent/MicrosoftCUAClient.ts
type FaraMessage (line 18) | interface FaraMessage {
type FaraMessageContent (line 23) | interface FaraMessageContent {
type FaraFunctionCall (line 34) | interface FaraFunctionCall {
class MicrosoftCUAClient (line 47) | class MicrosoftCUAClient extends AgentClient {
method constructor (line 75) | constructor(
method setViewport (line 125) | setViewport(width: number, height: number): void {
method setCurrentUrl (line 131) | setCurrentUrl(url: string): void {
method setScreenshotProvider (line 135) | setScreenshotProvider(provider: () => Promise<string>): void {
method setActionHandler (line 139) | setActionHandler(handler: (action: AgentAction) => Promise<void>): void {
method smartResize (line 147) | private smartResize(
method generateSystemPrompt (line 179) | private generateSystemPrompt(): string {
method parseThoughtsAndAction (line 309) | private parseThoughtsAndAction(response: string): {
method convertFunctionCallToAction (line 364) | private convertFunctionCallToAction(
method captureScreenshot (line 524) | async captureScreenshot(): Promise<string> {
method maybeRemoveOldScreenshots (line 537) | private maybeRemoveOldScreenshots(
method reconstructHistory (line 605) | private reconstructHistory(): FaraMessage[] {
method executeStep (line 631) | private async executeStep(
method execute (line 851) | async execute(executionOptions: AgentExecutionOptions): Promise<AgentR...
FILE: packages/core/lib/v3/agent/OpenAICUAClient.ts
constant CAPTCHA_PROCEED_TOOL (line 33) | const CAPTCHA_PROCEED_TOOL = "captchaSolvedProceed";
class OpenAICUAClient (line 35) | class OpenAICUAClient extends AgentClient {
method constructor (line 52) | constructor(
method setViewport (line 91) | setViewport(width: number, height: number): void {
method setCurrentUrl (line 95) | setCurrentUrl(url: string): void {
method setScreenshotProvider (line 99) | setScreenshotProvider(provider: () => Promise<string>): void {
method setActionHandler (line 103) | setActionHandler(handler: (action: AgentAction) => Promise<void>): void {
method setTools (line 107) | setTools(tools: ToolSet): void {
method setSafetyConfirmationHandler (line 111) | setSafetyConfirmationHandler(handler?: SafetyConfirmationHandler): void {
method addContextNote (line 115) | addContextNote(note: string): void {
method execute (line 131) | async execute(executionOptions: AgentExecutionOptions): Promise<AgentR...
method executeStep (line 243) | async executeStep(
method isComputerCallItem (line 376) | private isComputerCallItem(item: ResponseItem): item is ComputerCallIt...
method handleSafetyConfirmation (line 385) | private async handleSafetyConfirmation(
method isFunctionCallItem (line 424) | private isFunctionCallItem(item: ResponseItem): item is FunctionCallIt...
method createInitialInputItems (line 433) | private createInitialInputItems(instruction: string): ResponseInputIte...
method getAction (line 447) | async getAction(
method takeAction (line 561) | async takeAction(
method convertComputerCallToAction (line 828) | private convertComputerCallToAction(
method drainContextNotes (line 841) | private drainContextNotes(): string[] {
method convertFunctionCallToAction (line 851) | private convertFunctionCallToAction(
method captureScreenshot (line 867) | async captureScreenshot(options?: {
FILE: packages/core/lib/v3/agent/prompts/agentSystemPrompt.ts
type AgentSystemPromptOptions (line 4) | interface AgentSystemPromptOptions {
type ToolDefinition (line 25) | interface ToolDefinition {
function buildToolsSection (line 30) | function buildToolsSection(
function buildAgentSystemPrompt (line 120) | function buildAgentSystemPrompt(
FILE: packages/core/lib/v3/agent/tools/braveSearch.ts
type BraveSearchResult (line 5) | interface BraveSearchResult {
type SearchResponse (line 11) | interface SearchResponse {
type BraveWebResult (line 18) | interface BraveWebResult {
type BraveApiResponse (line 28) | interface BraveApiResponse {
function performBraveSearch (line 34) | async function performBraveSearch(query: string): Promise<SearchResponse> {
FILE: packages/core/lib/v3/agent/tools/browserbaseSearch.ts
type SearchResult (line 5) | interface SearchResult {
type BrowserbaseRawResult (line 11) | interface BrowserbaseRawResult {
type BrowserbaseApiResponse (line 17) | interface BrowserbaseApiResponse {
function performBrowserbaseSearch (line 21) | async function performBrowserbaseSearch(
FILE: packages/core/lib/v3/agent/tools/extract.ts
type JsonSchema (line 7) | interface JsonSchema {
function jsonSchemaToZod (line 15) | function jsonSchemaToZod(schema: JsonSchema): ZodTypeAny {
FILE: packages/core/lib/v3/agent/tools/index.ts
type V3AgentToolOptions (line 31) | interface V3AgentToolOptions {
function filterTools (line 77) | function filterTools(
function wrapToolWithTimeout (line 111) | function wrapToolWithTimeout<T extends Record<string, any>>(
function createAgentTools (line 145) | function createAgentTools(v3: V3, options?: V3AgentToolOptions) {
type AgentTools (line 207) | type AgentTools = ReturnType<typeof createAgentTools>;
type AgentToolTypesMap (line 213) | type AgentToolTypesMap = {
type AgentUITools (line 239) | type AgentUITools = InferUITools<AgentToolTypesMap>;
type AgentToolCall (line 245) | type AgentToolCall = {
type AgentToolResult (line 257) | type AgentToolResult = {
FILE: packages/core/lib/v3/agent/utils/actionMapping.ts
constant EXCLUDED_OUTPUT_KEYS (line 9) | const EXCLUDED_OUTPUT_KEYS = ["screenshotBase64"] as const;
function stripExcludedKeys (line 14) | function stripExcludedKeys(
function mapToolResultToActions (line 30) | function mapToolResultToActions({
function mapActToolResult (line 46) | function mapActToolResult(
function mapFillFormToolResult (line 75) | function mapFillFormToolResult(
function createStandardAction (line 114) | function createStandardAction(
FILE: packages/core/lib/v3/agent/utils/captchaSolver.ts
constant SOLVING_STARTED (line 4) | const SOLVING_STARTED = "browserbase-solving-started";
constant SOLVING_FINISHED (line 5) | const SOLVING_FINISHED = "browserbase-solving-finished";
constant SOLVING_ERRORED (line 6) | const SOLVING_ERRORED = "browserbase-solving-errored";
constant SOLVE_TIMEOUT_MS (line 9) | const SOLVE_TIMEOUT_MS = 90_000;
constant CAPTCHA_SOLVED_MSG (line 16) | const CAPTCHA_SOLVED_MSG =
constant CAPTCHA_ERRORED_MSG (line 20) | const CAPTCHA_ERRORED_MSG =
constant CAPTCHA_SYSTEM_PROMPT_NOTE (line 24) | const CAPTCHA_SYSTEM_PROMPT_NOTE =
constant CAPTCHA_CUA_SYSTEM_PROMPT_NOTE (line 28) | const CAPTCHA_CUA_SYSTEM_PROMPT_NOTE =
class CaptchaSolver (line 41) | class CaptchaSolver {
method init (line 60) | init(pageProvider: () => Promise<Page>): void {
method isSolving (line 65) | isSolving(): boolean {
method ensureAttached (line 74) | async ensureAttached(): Promise<void> {
method waitIfSolving (line 111) | async waitIfSolving(): Promise<void> {
method consumeSolveResult (line 137) | consumeSolveResult(): { solved: boolean; errored: boolean } {
method dispose (line 150) | dispose(): void {
method detachListener (line 165) | private detachListener(): void {
method settle (line 182) | private settle(): void {
FILE: packages/core/lib/v3/agent/utils/coordinateNormalization.ts
constant STEALTH_VIEWPORT (line 4) | const STEALTH_VIEWPORT = { width: 1288, height: 711 };
function isGoogleProvider (line 6) | function isGoogleProvider(provider?: string): boolean {
function normalizeGoogleCoordinates (line 13) | function normalizeGoogleCoordinates(
function processCoordinates (line 26) | function processCoordinates(
FILE: packages/core/lib/v3/agent/utils/cuaKeyMapping.ts
constant KEY_MAP (line 10) | const KEY_MAP: Record<string, string> = {
function mapKeyToPlaywright (line 58) | function mapKeyToPlaywright(key: string): string {
FILE: packages/core/lib/v3/agent/utils/googleCustomToolHandler.ts
type CustomToolExecutionResult (line 10) | interface CustomToolExecutionResult {
function executeGoogleCustomTool (line 20) | async function executeGoogleCustomTool(
function isCustomTool (line 90) | function isCustomTool(
function convertToolSetToFunctionDeclarations (line 101) | function convertToolSetToFunctionDeclarations(
function convertToolToFunctionDeclaration (line 119) | function convertToolToFunctionDeclaration(
function convertJsonSchemaToGoogleParameters (line 151) | function convertJsonSchemaToGoogleParameters(schema: {
function mapJsonTypeToGoogleType (line 190) | function mapJsonTypeToGoogleType(jsonType: string): Type {
FILE: packages/core/lib/v3/agent/utils/handleDoneToolCall.ts
type DoneResult (line 9) | interface DoneResult {
function buildBaseDoneSchema (line 16) | function buildBaseDoneSchema(factory: typeof z) {
function handleDoneToolCall (line 32) | async function handleDoneToolCall(options: {
FILE: packages/core/lib/v3/agent/utils/imageCompression.ts
type ResponseInputItem (line 12) | type ResponseInputItem = AnthropicMessage | AnthropicToolResult;
type FunctionResponseData (line 14) | interface FunctionResponseData {
type AnthropicResponseInputItem (line 20) | type AnthropicResponseInputItem = AnthropicMessage | AnthropicToolResult;
type SupportedInputItem (line 21) | type SupportedInputItem =
function findItemsWithImages (line 31) | function findItemsWithImages(items: ResponseInputItem[]): number[] {
function compressConversationImages (line 64) | function compressConversationImages(
function findGoogleItemsWithImages (line 111) | function findGoogleItemsWithImages(items: GoogleContent[]): number[] {
function findOpenAIItemsWithImages (line 153) | function findOpenAIItemsWithImages(
function compressOpenAIConversationImages (line 189) | function compressOpenAIConversationImages(
function compressGoogleConversationImages (line 229) | function compressGoogleConversationImages(
FILE: packages/core/lib/v3/agent/utils/messageProcessing.ts
constant VISION_ACTION_TOOLS (line 4) | const VISION_ACTION_TOOLS = [
function isToolMessage (line 13) | function isToolMessage(
function isScreenshotPart (line 24) | function isScreenshotPart(part: unknown): boolean {
function isVisionActionPart (line 32) | function isVisionActionPart(part: unknown): boolean {
function isVisionPart (line 38) | function isVisionPart(part: unknown): boolean {
function isAriaTreePart (line 42) | function isAriaTreePart(part: unknown): boolean {
function processMessages (line 60) | function processMessages(messages: ModelMessage[]): number {
type ToolResultPart (line 119) | interface ToolResultPart {
function isContentTypeOutput (line 130) | function isContentTypeOutput(output: {
function compressScreenshotMessage (line 142) | function compressScreenshotMessage(message: {
function compressVisionActionMessage (line 166) | function compressVisionActionMessage(message: {
function compressAriaTreeMessage (line 201) | function compressAriaTreeMessage(message: {
FILE: packages/core/lib/v3/agent/utils/screenshotHandler.ts
constant DEFAULT_DELAY_MS (line 7) | const DEFAULT_DELAY_MS = 500;
function waitAndCaptureScreenshot (line 17) | async function waitAndCaptureScreenshot(
FILE: packages/core/lib/v3/agent/utils/validateExperimentalFeatures.ts
type AgentValidationOptions (line 10) | interface AgentValidationOptions {
function validateExperimentalFeatures (line 35) | function validateExperimentalFeatures(
FILE: packages/core/lib/v3/agent/utils/variables.ts
function resolveVariableValue (line 7) | function resolveVariableValue(v: VariableValue): string {
function getVariableDescription (line 18) | function getVariableDescription(v: VariableValue): string | undefined {
function substituteVariables (line 29) | function substituteVariables(
function flattenVariables (line 46) | function flattenVariables(
FILE: packages/core/lib/v3/agent/utils/xpath.ts
function ensureXPath (line 12) | function ensureXPath(value: unknown): string | null {
FILE: packages/core/lib/v3/api.ts
constant REGION_API_URLS (line 45) | const REGION_API_URLS: Record<BrowserbaseRegion, string> = {
function getApiUrlForRegion (line 59) | function getApiUrlForRegion(
type StagehandAPIConstructorParams (line 85) | interface StagehandAPIConstructorParams {
type ClientSessionStartParams (line 104) | interface ClientSessionStartParams extends Api.SessionStartRequest {
type ApiResponse (line 112) | type ApiResponse<T> =
type ApiRequestBody (line 119) | type ApiRequestBody =
type ExecuteActionParams (line 129) | interface ExecuteActionParams {
type ClientActParameters (line 146) | interface ClientActParameters {
type ClientExtractParameters (line 157) | interface ClientExtractParameters {
type ClientObserveParameters (line 169) | interface ClientObserveParameters {
class StagehandAPIClient (line 175) | class StagehandAPIClient {
method constructor (line 188) | constructor({
method init (line 202) | async init({
method act (line 279) | async act({
method extract (line 313) | async extract<T extends StagehandZodSchema>({
method observe (line 352) | async observe({
method goto (line 386) | async goto(
method agentExecute (line 399) | async agentExecute(
method consumeLatestAgentCacheEntry (line 456) | consumeLatestAgentCacheEntry(): AgentCacheTransferPayload | null {
method end (line 462) | async end(): Promise<Response> {
method getReplayMetrics (line 470) | async getReplayMetrics(): Promise<StagehandMetrics> {
method prepareModelConfig (line 608) | private prepareModelConfig(
method consumeFinishedEventData (line 644) | private consumeFinishedEventData<T>(): T | null {
method execute (line 650) | private async execute<T>({
method attachCacheStatus (line 791) | private attachCacheStatus<T>(
method shouldUseCache (line 831) | private shouldUseCache(methodServerCache?: boolean): boolean {
method request (line 840) | private async request(
FILE: packages/core/lib/v3/cache/ActCache.ts
class ActCache (line 16) | class ActCache {
method constructor (line 23) | constructor({
method enabled (line 37) | get enabled(): boolean {
method prepareContext (line 41) | async prepareContext(
method tryReplay (line 67) | async tryReplay(
method store (line 144) | async store(context: ActCacheContext, result: ActResult): Promise<void> {
method buildActCacheKey (line 184) | private buildActCacheKey(
method replayCachedActions (line 197) | private async replayCachedActions(
method haveActionsChanged (line 283) | private haveActionsChanged(original: Action[], updated: Action[]): boo...
method refreshCacheEntry (line 323) | private async refreshCacheEntry(
method doVariableKeysMatch (line 358) | private doVariableKeysMatch(
method hasAllVariableValues (line 375) | private hasAllVariableValues(
FILE: packages/core/lib/v3/cache/AgentCache.ts
constant SENSITIVE_CONFIG_KEYS (line 38) | const SENSITIVE_CONFIG_KEYS = new Set(["apikey", "api_key", "api-key"]);
class AgentCache (line 40) | class AgentCache {
method constructor (line 55) | constructor({
method enabled (line 79) | get enabled(): boolean {
method shouldAttemptCache (line 83) | shouldAttemptCache(instruction: string): boolean {
method sanitizeExecuteOptions (line 87) | sanitizeExecuteOptions(
method buildConfigSignature (line 107) | buildConfigSignature(agentOptions?: AgentConfig): string {
method prepareContext (line 142) | async prepareContext(params: {
method tryReplay (line 175) | async tryReplay(
method tryReplayAsStream (line 232) | async tryReplayAsStream(
method createCachedStreamResult (line 252) | private createCachedStreamResult(
method wrapStreamForCaching (line 316) | wrapStreamForCaching(
method store (line 346) | async store(
method consumeBufferedEntry (line 398) | consumeBufferedEntry(): AgentCacheTransferPayload | null {
method storeTransferredEntry (line 408) | async storeTransferredEntry(
method pruneAgentResult (line 446) | private pruneAgentResult(result: AgentResult): AgentResult {
method beginRecording (line 461) | beginRecording(): void {
method endRecording (line 465) | endRecording(): AgentReplayStep[] {
method discardRecording (line 472) | discardRecording(): void {
method isRecording (line 476) | isRecording(): boolean {
method recordStep (line 480) | recordStep(step: AgentReplayStep): void {
method isReplayActive (line 496) | isReplayActive(): boolean {
method serializeAgentModelForCache (line 500) | private serializeAgentModelForCache(
method buildAgentCacheKey (line 518) | private buildAgentCacheKey(
method sanitizeModelOptionsForCache (line 535) | private sanitizeModelOptionsForCache(
method sanitizeModelValueForCache (line 555) | private sanitizeModelValueForCache(value: unknown): unknown {
method replayAgentCacheEntry (line 572) | private async replayAgentCacheEntry(
method executeAgentReplayStep (line 626) | private async executeAgentReplayStep(
method replayAgentActStep (line 680) | private async replayAgentActStep(
method replayAgentFillFormStep (line 722) | private async replayAgentFillFormStep(
method replayAgentGotoStep (line 766) | private async replayAgentGotoStep(
method replayAgentScrollStep (line 774) | private async replayAgentScrollStep(
method replayAgentWaitStep (line 798) | private async replayAgentWaitStep(step: AgentReplayWaitStep): Promise<...
method replayAgentNavBackStep (line 803) | private async replayAgentNavBackStep(
method replayAgentKeysStep (line 811) | private async replayAgentKeysStep(
method haveActionsChanged (line 830) | private haveActionsChanged(original: Action[], updated: Action[]): boo...
method refreshAgentCacheEntry (line 863) | private async refreshAgentCacheEntry(
FILE: packages/core/lib/v3/cache/CacheStorage.ts
class CacheStorage (line 14) | class CacheStorage {
method constructor (line 15) | private constructor(
method create (line 21) | static create(
method createMemory (line 48) | static createMemory(logger: Logger): CacheStorage {
method directory (line 52) | get directory(): string | undefined {
method enabled (line 56) | get enabled(): boolean {
method resolvePath (line 60) | private resolvePath(fileName: string): string | null {
method readJson (line 65) | async readJson<T>(fileName: string): Promise<ReadJsonResult<T>> {
method writeJson (line 91) | async writeJson(fileName: string, data: unknown): Promise<WriteJsonRes...
FILE: packages/core/lib/v3/cache/serverAgentCache.ts
type ServerAgentCacheHandle (line 11) | interface ServerAgentCacheHandle {
function getInternalField (line 19) | function getInternalField<T>(instance: V3, key: string): T {
function setInternalField (line 23) | function setInternalField(instance: V3, key: string, value: unknown): vo...
function createMemoryAgentCache (line 27) | function createMemoryAgentCache(stagehand: V3): AgentCache {
function __internalCreateInMemoryAgentCacheHandle (line 52) | function __internalCreateInMemoryAgentCacheHandle(
FILE: packages/core/lib/v3/cache/utils.ts
constant DEFAULT_WAIT_TIMEOUT_MS (line 4) | const DEFAULT_WAIT_TIMEOUT_MS = 15000;
function cloneForCache (line 6) | function cloneForCache<T>(value: T): T {
function safeGetPageUrl (line 10) | async function safeGetPageUrl(page: Page): Promise<string> {
function waitForCachedSelector (line 22) | async function waitForCachedSelector(params: {
FILE: packages/core/lib/v3/dom/a11yScripts/index.ts
function getScrollOffsets (line 1) | function getScrollOffsets(): { sx: number; sy: number } {
function getBoundingRectLite (line 19) | function getBoundingRectLite(this: Element): {
function resolveDeepActiveElement (line 34) | function resolveDeepActiveElement(): Element | null {
function nodeToAbsoluteXPath (line 49) | function nodeToAbsoluteXPath(this: Node | null | undefined): string {
function documentHasFocusStrict (line 110) | function documentHasFocusStrict(): boolean {
FILE: packages/core/lib/v3/dom/genA11yScripts.ts
function main (line 14) | async function main(): Promise<void> {
FILE: packages/core/lib/v3/dom/genLocatorScripts.ts
function main (line 13) | async function main(): Promise<void> {
FILE: packages/core/lib/v3/dom/genScreenshotScripts.ts
function main (line 13) | async function main(): Promise<void> {
FILE: packages/core/lib/v3/dom/global.d.ts
type StagehandV3Backdoor (line 1) | interface StagehandV3Backdoor {
type Window (line 15) | interface Window {
FILE: packages/core/lib/v3/dom/locatorScripts/counts.ts
type TextMatchSample (line 3) | interface TextMatchSample {
type TextMatchResult (line 10) | interface TextMatchResult {
function countCssMatchesPrimary (line 16) | function countCssMatchesPrimary(selectorRaw: string): number {
function countCssMatchesPierce (line 68) | function countCssMatchesPierce(selectorRaw: string): number {
function countTextMatches (line 141) | function countTextMatches(rawNeedle: string): TextMatchResult {
function countXPathMatchesMainWorld (line 303) | function countXPathMatchesMainWorld(rawXp: string): number {
FILE: packages/core/lib/v3/dom/locatorScripts/scripts.ts
type ClickEventOptions (line 9) | interface ClickEventOptions {
function ensureFileInputElement (line 16) | function ensureFileInputElement(this: Element): boolean {
type SerializedFilePayload (line 27) | interface SerializedFilePayload {
function assignFilePayloadsToInputElement (line 35) | function assignFilePayloadsToInputElement(
function dispatchDomClick (line 82) | function dispatchDomClick(
function scrollElementToPercent (line 106) | function scrollElementToPercent(
type FillElementResult (line 184) | type FillElementResult =
function prepareElementForTyping (line 189) | function prepareElementForTyping(this: Element): boolean {
function fillElementValue (line 252) | function fillElementValue(
function focusElement (line 375) | function focusElement(this: Element): void {
function selectElementOptions (line 385) | function selectElementOptions(
function isElementVisible (line 429) | function isElementVisible(this: Element): boolean {
function isElementChecked (line 453) | function isElementChecked(this: Element): boolean {
function readElementInputValue (line 471) | function readElementInputValue(this: Element): string {
function readElementTextContent (line 492) | function readElementTextContent(this: Element): string {
function readElementInnerHTML (line 500) | function readElementInnerHTML(this: Element): string {
function readElementInnerText (line 508) | function readElementInnerText(this: Element): string {
FILE: packages/core/lib/v3/dom/locatorScripts/selectors.ts
function resolveCssSelector (line 60) | function resolveCssSelector(
function resolveCssSelectorPierce (line 72) | function resolveCssSelectorPierce(
function resolveTextSelector (line 148) | function resolveTextSelector(
function resolveXPathMainWorld (line 306) | function resolveXPathMainWorld(
FILE: packages/core/lib/v3/dom/locatorScripts/waitForSelector.ts
type WaitForSelectorState (line 12) | type WaitForSelectorState = "attached" | "detached" | "visible" | "hidden";
function waitForSelector (line 223) | function waitForSelector(
FILE: packages/core/lib/v3/dom/locatorScripts/xpathParser.ts
type XPathPredicate (line 1) | type XPathPredicate =
type XPathStep (line 23) | interface XPathStep {
function parseXPathSteps (line 58) | function parseXPathSteps(input: string): XPathStep[] {
function extractPredicates (line 109) | function extractPredicates(str: string): string[] {
function parseStep (line 137) | function parseStep(raw: string): {
function parsePredicateExpression (line 161) | function parsePredicateExpression(input: string): XPathPredicate | null {
function parseAtomicPredicate (line 192) | function parseAtomicPredicate(input: string): XPathPredicate | null {
function splitTopLevel (line 293) | function splitTopLevel(input: string, keyword: string): string[] {
function isKeywordAt (line 340) | function isKeywordAt(input: string, index: number, keyword: string): boo...
function isBoundary (line 349) | function isBoundary(ch: string): boolean {
function unwrapFunctionCall (line 353) | function unwrapFunctionCall(input: string, name: string): string | null {
function hasBalancedParens (line 360) | function hasBalancedParens(input: string): boolean {
function textValue (line 383) | function textValue(element: Element): string {
function normalizeMaybe (line 387) | function normalizeMaybe(value: string, normalize?: boolean): string {
function evaluatePredicate (line 391) | function evaluatePredicate(
function applyPredicates (line 443) | function applyPredicates(
FILE: packages/core/lib/v3/dom/locatorScripts/xpathResolver.ts
type ClosedRootGetter (line 7) | type ClosedRootGetter = (host: Element) => ShadowRoot | null;
type XPathResolveOptions (line 9) | type XPathResolveOptions = {
type ShadowContext (line 13) | type ShadowContext = {
function resolveXPathFirst (line 24) | function resolveXPathFirst(
function resolveXPathAtIndex (line 31) | function resolveXPathAtIndex(
function countXPathMatches (line 59) | function countXPathMatches(
function resolveXPathComposedMatches (line 82) | function resolveXPathComposedMatches(
function matchesTag (line 130) | function matchesTag(element: Element, step: XPathStep): boolean {
function getShadowContext (line 135) | function getShadowContext(): ShadowContext {
function composedChildren (line 179) | function composedChildren(
function composedDescendants (line 210) | function composedDescendants(
function resolveNativeAtIndexWithError (line 233) | function resolveNativeAtIndexWithError(
function resolveNativeCountWithError (line 254) | function resolveNativeCountWithError(xp: string): {
FILE: packages/core/lib/v3/dom/piercer.runtime.ts
type V3ShadowPatchOptions (line 1) | interface V3ShadowPatchOptions {
type StagehandV3Backdoor (line 6) | interface StagehandV3Backdoor {
type V3InternalState (line 19) | type V3InternalState = {
type Window (line 27) | interface Window {
function installV3ShadowPiercer (line 33) | function installV3ShadowPiercer(opts: V3ShadowPatchOptions = {}): void {
FILE: packages/core/lib/v3/dom/rerenderMissingShadows.runtime.ts
function rerenderMissingShadowHosts (line 1) | function rerenderMissingShadowHosts(): void {
FILE: packages/core/lib/v3/dom/screenshotScripts/resolveMaskRect.ts
type MaskRect (line 1) | type MaskRect = {
function resolveMaskRect (line 9) | function resolveMaskRect(
FILE: packages/core/lib/v3/external_clients/aisdk.ts
class AISdkClient (line 17) | class AISdkClient extends LLMClient {
method constructor (line 21) | constructor({ model }: { model: LanguageModelV2 }) {
method createChatCompletion (line 26) | async createChatCompletion<T = ChatCompletion>({
FILE: packages/core/lib/v3/external_clients/customOpenAI.ts
class CustomOpenAIClient (line 28) | class CustomOpenAIClient extends LLMClient {
method constructor (line 32) | constructor({ modelName, client }: { modelName: string; client: OpenAI...
method createChatCompletion (line 38) | async createChatCompletion<T = ChatCompletion>({
FILE: packages/core/lib/v3/flowlogger/EventEmitter.ts
type WildcardEventListener (line 3) | type WildcardEventListener = (...args: unknown[]) => void;
class EventEmitterWithWildcardSupport (line 5) | class EventEmitterWithWildcardSupport extends EventEmitter {
method on (line 8) | override on(
method off (line 20) | override off(
method emit (line 32) | override emit(eventName: string | symbol, ...args: unknown[]): boolean {
FILE: packages/core/lib/v3/flowlogger/EventSink.ts
type EventSink (line 16) | interface EventSink {
function matchesEventStoreQuery (line 23) | function matchesEventStoreQuery(
function isWritable (line 57) | function isWritable(stream: fs.WriteStream | null): stream is fs.WriteSt...
function writeToStream (line 62) | function writeToStream(stream: fs.WriteStream, value: string): Promise<v...
method constructor (line 86) | constructor(sessionDirPromise: Promise<string | null>, fileName: string) {
method emit (line 97) | async emit(event: FlowEvent): Promise<void> {
method query (line 116) | async query(): Promise<FlowEvent[]> {
method destroy (line 121) | async destroy(): Promise<void> {
class JsonlFileEventSink (line 133) | class JsonlFileEventSink extends FileEventSink {
method constructor (line 135) | constructor(sessionDirPromise: Promise<string | null>) {
method serialize (line 140) | protected async serialize(event: FlowEvent): Promise<string> {
class PrettyLogFileEventSink (line 145) | class PrettyLogFileEventSink extends FileEventSink {
method constructor (line 147) | constructor(
method serialize (line 155) | protected async serialize(event: FlowEvent): Promise<string | null> {
class PrettyStderrEventSink (line 161) | class PrettyStderrEventSink implements EventSink {
method constructor (line 163) | constructor(private readonly store: Pick<EventStoreApi, "query">) {} /...
method emit (line 166) | async emit(event: FlowEvent): Promise<void> {
method query (line 202) | async query(): Promise<FlowEvent[]> {
method destroy (line 207) | async destroy(): Promise<void> {}
class InMemoryEventSink (line 210) | class InMemoryEventSink implements EventSink {
method constructor (line 212) | constructor(protected readonly limit = Infinity) {}
method storeEvent (line 217) | protected storeEvent(event: FlowEvent): FlowEvent {
method emit (line 222) | async emit(event: FlowEvent): Promise<void> {
method query (line 230) | async query(query: EventStoreQuery): Promise<FlowEvent[]> {
method destroy (line 248) | async destroy(): Promise<void> {
class ShallowInMemoryEventSink (line 253) | class ShallowInMemoryEventSink extends InMemoryEventSink {
method storeEvent (line 255) | protected override storeEvent(event: FlowEvent): FlowEvent {
FILE: packages/core/lib/v3/flowlogger/EventStore.ts
constant DEFAULT_IN_MEMORY_EVENT_LIMIT (line 13) | const DEFAULT_IN_MEMORY_EVENT_LIMIT = 500;
constant CONFIG_DIR (line 14) | const CONFIG_DIR = process.env.BROWSERBASE_CONFIG_DIR || "";
constant FLOW_LOGS_ENABLED (line 15) | const FLOW_LOGS_ENABLED = process.env.BROWSERBASE_FLOW_LOGS === "1";
constant SENSITIVE_KEYS (line 16) | const SENSITIVE_KEYS =
type EventStoreQuery (line 23) | interface EventStoreQuery {
type EventStoreApi (line 30) | interface EventStoreApi {
function sanitizeOptions (line 42) | function sanitizeOptions(options: V3Options): Record<string, unknown> {
function getConfigDir (line 58) | function getConfigDir(): string {
function createSessionDir (line 63) | async function createSessionDir(
class EventStore (line 114) | class EventStore implements EventStoreApi {
method constructor (line 120) | constructor(
method registerSink (line 153) | private registerSink(sink: EventSink): void {
method destroy (line 171) | async destroy(): Promise<void> {
FILE: packages/core/lib/v3/flowlogger/FlowLogger.ts
type FlowEventData (line 21) | type FlowEventData = z.infer<typeof FlowEventDataSchema>;
type FlowEventInput (line 22) | type FlowEventInput = z.input<typeof FlowEventInputSchema>;
type FlowEventFields (line 25) | type FlowEventFields = Omit<
class FlowEvent (line 36) | class FlowEvent implements FlowEventFields {
method deriveEventIdSuffix (line 38) | private static deriveEventIdSuffix(eventType: string): string {
method createEventId (line 50) | static createEventId(eventType: string): string {
method constructor (line 65) | constructor(input: FlowEventInput) {
type FlowLoggerContext (line 82) | interface FlowLoggerContext {
type AsyncOriginalMethod (line 89) | type AsyncOriginalMethod<
type FlowLoggerLogOptions (line 95) | type FlowLoggerLogOptions = FlowEventInput & {
function dataToKb (line 103) | function dataToKb(data: string): string {
type CdpLogEventType (line 111) | type CdpLogEventType = "call" | "response" | "responseError" | "message";
type CdpLogPayload (line 113) | type CdpLogPayload = {
constant CDP_EVENT_NAMES (line 121) | const CDP_EVENT_NAMES: Record<CdpLogEventType, string> = {
class FlowLogger (line 128) | class FlowLogger {
method cloneContext (line 130) | private static cloneContext(ctx: FlowLoggerContext): FlowLoggerContext {
method resolveReentryContext (line 145) | private static resolveReentryContext(
method emit (line 188) | private static emit(event: FlowEventInput): FlowEvent | null {
method runWithAutoStatusEventLogging (line 204) | private static async runWithAutoStatusEventLogging<TResult>(
method logCdpEvent (line 267) | private static logCdpEvent(
method emitLlmEvent (line 298) | private static emitLlmEvent(event: FlowEventInput): void {
method buildMiddlewarePromptSummary (line 310) | private static buildMiddlewarePromptSummary(params: {
method buildMiddlewareOutputSummary (line 362) | private static buildMiddlewareOutputSummary(result: {
method init (line 406) | static init(
method close (line 422) | static async close(context?: FlowLoggerContext | null): Promise<void> {
method currentContext (line 430) | static get currentContext(): FlowLoggerContext {
method resolveContext (line 442) | static resolveContext(
method wrapWithLogging (line 456) | static wrapWithLogging<TMethod extends AsyncOriginalMethod>(
method runWithLogging (line 508) | static runWithLogging(
method withContext (line 549) | static withContext<T>(context: FlowLoggerContext, fn: () => T): T {
method logCdpCallEvent (line 573) | static logCdpCallEvent(
method logCdpResponseEvent (line 585) | static logCdpResponseEvent(
method logCdpMessageEvent (line 604) | static logCdpMessageEvent(
method logLlmRequest (line 624) | static logLlmRequest({
method logLlmResponse (line 644) | static logLlmResponse({
method createLlmLoggingMiddleware (line 675) | static createLlmLoggingMiddleware(
type ContentPart (line 713) | type ContentPart = {
type LlmMessageContent (line 722) | type LlmMessageContent = {
function extractLlmMessageContent (line 731) | function extractLlmMessageContent(content: unknown[]): {
function extractLlmMessageSummary (line 774) | function extractLlmMessageSummary(
function extractLlmPromptSummary (line 817) | function extractLlmPromptSummary(
function extractLlmCuaPromptSummary (line 838) | function extractLlmCuaPromptSummary(
function extractLlmCuaResponseSummary (line 860) | function extractLlmCuaResponseSummary(output: unknown): string {
FILE: packages/core/lib/v3/flowlogger/prettify.ts
constant MAX_LINE_LENGTH (line 5) | const MAX_LINE_LENGTH = 160;
function prettifySanitizeValue (line 14) | function prettifySanitizeValue(value: unknown): unknown {
function prettifySanitizeEvent (line 36) | function prettifySanitizeEvent(event: FlowEvent): FlowEvent {
function prettifyTruncateLine (line 48) | function prettifyTruncateLine(value: string, maxLen: number): string {
function prettifyFormatValue (line 60) | function prettifyFormatValue(value: unknown): string {
function prettifyFormatArgs (line 72) | function prettifyFormatArgs(args?: unknown | unknown[]): string {
function shortId (line 85) | function shortId(id: string | null | undefined): string {
function truncateCdpIds (line 90) | function truncateCdpIds(value: string): string {
function prettifyFormatTimestamp (line 101) | function prettifyFormatTimestamp(date: Date): string {
function prettifyRemoveQuotes (line 107) | function prettifyRemoveQuotes(value: string): string {
function prettifyEventName (line 115) | function prettifyEventName(eventType: string): string {
function prettifyEventAction (line 123) | function prettifyEventAction(eventType: string): string {
function prettifyFormatMethodCall (line 132) | function prettifyFormatMethodCall(
function prettifyIsAgentEvent (line 142) | function prettifyIsAgentEvent(event: FlowEvent): boolean {
function prettifyIsStagehandEvent (line 147) | function prettifyIsStagehandEvent(event: FlowEvent): boolean {
function prettifyIsActionEvent (line 152) | function prettifyIsActionEvent(event: FlowEvent): boolean {
function prettifyIsCdpEvent (line 157) | function prettifyIsCdpEvent(event: FlowEvent): boolean {
function prettifyIsLlmEvent (line 162) | function prettifyIsLlmEvent(event: FlowEvent): boolean {
function prettifyIsCompletedEvent (line 167) | function prettifyIsCompletedEvent(event: FlowEvent): boolean {
function prettifyIsErrorEvent (line 172) | function prettifyIsErrorEvent(event: FlowEvent): boolean {
function prettifyFormatTag (line 177) | function prettifyFormatTag(
function prettifyFormatDuration (line 186) | function prettifyFormatDuration(durationMs?: unknown): string | null {
function prettifySummarizePrompt (line 193) | function prettifySummarizePrompt(value: unknown): string | undefined {
function prettifyCompactValue (line 206) | function prettifyCompactValue(value: unknown): unknown {
function prettifyFormatEventArgs (line 239) | function prettifyFormatEventArgs(args?: unknown | unknown[]): string {
function prettifyFindNearestEvent (line 244) | function prettifyFindNearestEvent(
function prettifyBuildContextTags (line 266) | function prettifyBuildContextTags(
function prettifyFormatStartedDetails (line 374) | function prettifyFormatStartedDetails(event: FlowEvent): string {
function prettifyFormatCompletedDetails (line 406) | function prettifyFormatCompletedDetails(event: FlowEvent): string {
function prettifyFormatCdpDetails (line 419) | function prettifyFormatCdpDetails(event: FlowEvent): string {
function prettifyFormatLlmDetails (line 443) | function prettifyFormatLlmDetails(event: FlowEvent): string {
function prettifyEvent (line 467) | async function prettifyEvent(
function prettifyColorStderrLine (line 505) | function prettifyColorStderrLine(line: string): string {
FILE: packages/core/lib/v3/handlers/actHandler.ts
type ActInferenceElement (line 30) | type ActInferenceElement = {
type ActInferenceResponse (line 37) | type ActInferenceResponse = Awaited<ReturnType<typeof actInference>>;
class ActHandler (line 39) | class ActHandler {
method constructor (line 57) | constructor(
method recordActMetrics (line 86) | private recordActMetrics(response: ActInferenceResponse): void {
method getActionFromLLM (line 97) | private async getActionFromLLM({
method act (line 137) | async act(params: ActHandlerParams): Promise<ActResult> {
method takeDeterministicAction (line 268) | async takeDeterministicAction(
function normalizeActInferenceElement (line 445) | function normalizeActInferenceElement(
function substituteVariablesInArguments (line 518) | function substituteVariablesInArguments(
FILE: packages/core/lib/v3/handlers/extractHandler.ts
function transformUrlStringsToNumericIds (line 46) | function transformUrlStringsToNumericIds<T extends StagehandZodSchema>(
type ExtractionResponseBase (line 53) | interface ExtractionResponseBase {
type ExtractionResponse (line 62) | type ExtractionResponse<T extends StagehandZodObject> = ExtractionRespon...
class ExtractHandler (line 65) | class ExtractHandler {
method constructor (line 82) | constructor(
method extract (line 109) | async extract<T extends StagehandZodSchema>(
FILE: packages/core/lib/v3/handlers/handlerUtils/actHandlerUtils.ts
type UnderstudyMethodHandlerContext (line 16) | interface UnderstudyMethodHandlerContext {
function normalizeRootXPath (line 28) | function normalizeRootXPath(input: string): string {
function performUnderstudyMethod (line 35) | async function performUnderstudyMethod(
constant METHOD_HANDLER_MAP (line 124) | const METHOD_HANDLER_MAP: Record<
function selectOption (line 146) | async function selectOption(ctx: UnderstudyMethodHandlerContext) {
function scrollIntoView (line 168) | async function scrollIntoView(
function scrollElementToPercentage (line 186) | async function scrollElementToPercentage(
function scrollByPixelOffset (line 205) | async function scrollByPixelOffset(
function wheelScroll (line 221) | async function wheelScroll(ctx: UnderstudyMethodHandlerContext): Promise...
function fillOrType (line 239) | async function fillOrType(ctx: UnderstudyMethodHandlerContext): Promise<...
function typeText (line 259) | async function typeText(ctx: UnderstudyMethodHandlerContext): Promise<vo...
function pressKey (line 278) | async function pressKey(ctx: UnderstudyMethodHandlerContext): Promise<vo...
function clickElement (line 308) | async function clickElement(
function doubleClick (line 329) | async function doubleClick(ctx: UnderstudyMethodHandlerContext): Promise...
function dragAndDrop (line 348) | async function dragAndDrop(ctx: UnderstudyMethodHandlerContext): Promise...
function scrollToNextChunk (line 425) | async function scrollToNextChunk(
function scrollToPreviousChunk (line 431) | async function scrollToPreviousChunk(
function scrollByElementHeight (line 437) | async function scrollByElementHeight(
function hover (line 495) | async function hover(ctx: UnderstudyMethodHandlerContext) {
function getFrameUrl (line 518) | async function getFrameUrl(frame: Frame): Promise<string> {
function waitForDomNetworkQuiet (line 528) | async function waitForDomNetworkQuiet(
FILE: packages/core/lib/v3/handlers/handlerUtils/timeoutGuard.ts
type TimeoutGuard (line 3) | type TimeoutGuard = () => void;
function createTimeoutGuard (line 5) | function createTimeoutGuard(
FILE: packages/core/lib/v3/handlers/observeHandler.ts
class ObserveHandler (line 22) | class ObserveHandler {
method constructor (line 39) | constructor(
method observe (line 66) | async observe(params: ObserveHandlerParams): Promise<Action[]> {
FILE: packages/core/lib/v3/handlers/v3AgentHandler.ts
function getErrorMessage (line 49) | function getErrorMessage(error: unknown): string {
function prependSystemMessage (line 57) | function prependSystemMessage(
class V3AgentHandler (line 75) | class V3AgentHandler {
method constructor (line 85) | constructor(
method prepareAgent (line 105) | private async prepareAgent(
method createPrepareStep (line 196) | private createPrepareStep(
method createStepHandler (line 245) | private createStepHandler(
method execute (line 305) | public async execute(
method stream (line 444) | public async stream(
method consolidateMetricsAndResult (line 585) | private consolidateMetricsAndResult(
method createTools (line 645) | private createTools(
method handleStop (line 665) | private handleStop(
method ensureDone (line 680) | private async ensureDone(
FILE: packages/core/lib/v3/handlers/v3CuaAgentHandler.ts
class V3CuaAgentHandler (line 29) | class V3CuaAgentHandler {
method constructor (line 41) | constructor(
method ensureNotClosed (line 67) | private ensureNotClosed(): void {
method setupAgentClient (line 73) | private setupAgentClient(): void {
method setSafetyConfirmationHandler (line 180) | setSafetyConfirmationHandler(handler?: SafetyConfirmationHandler): void {
method execute (line 189) | async execute(
method executeAction (line 271) | private async executeAction(
method computePointerTarget (line 560) | private computePointerTarget(action: AgentAction): string | undefined {
method describePointerAction (line 572) | private describePointerAction(kind: string, x: unknown, y: unknown): s...
method describeTypeAction (line 581) | private describeTypeAction(text: string): string {
method describeDragAction (line 586) | private describeDragAction(): string {
method buildInstructionFallback (line 590) | private buildInstructionFallback(
method recordCuaActStep (line 601) | private recordCuaActStep(
method updateClientViewport (line 626) | private async updateClientViewport(): Promise<void> {
method updateClientUrl (line 649) | private async updateClientUrl(): Promise<void> {
method captureAndSendScreenshot (line 659) | async captureAndSendScreenshot(): Promise<unknown> {
method handleCaptchaSolveResult (line 684) | private handleCaptchaSolveResult(result?: {
method shouldSkipSolvedCaptchaInteraction (line 711) | private async shouldSkipSolvedCaptchaInteraction(
method injectCursor (line 779) | private async injectCursor(): Promise<void> {
FILE: packages/core/lib/v3/launch/browserbase.ts
function createBrowserbaseSession (line 9) | async function createBrowserbaseSession(
FILE: packages/core/lib/v3/launch/local.ts
type LaunchLocalOptions (line 5) | interface LaunchLocalOptions {
function launchLocalChrome (line 15) | async function launchLocalChrome(
function waitForWebSocketDebuggerUrl (line 52) | async function waitForWebSocketDebuggerUrl(
function waitForWebSocketReady (line 82) | async function waitForWebSocketReady(
function probeWebSocket (line 104) | function probeWebSocket(wsUrl: string, timeoutMs: number): Promise<void> {
FILE: packages/core/lib/v3/llm/AnthropicClient.ts
class AnthropicClient (line 21) | class AnthropicClient extends LLMClient {
method constructor (line 26) | constructor({
method createChatCompletion (line 43) | async createChatCompletion<T = LLMResponse>({
FILE: packages/core/lib/v3/llm/CerebrasClient.ts
class CerebrasClient (line 14) | class CerebrasClient extends LLMClient {
method constructor (line 20) | constructor({
method createChatCompletion (line 43) | async createChatCompletion<T = LLMResponse>({
FILE: packages/core/lib/v3/llm/GoogleClient.ts
class GoogleClient (line 60) | class GoogleClient extends LLMClient {
method constructor (line 67) | constructor({
method formatMessages (line 91) | private formatMessages(
method formatTools (line 186) | private formatTools(
method createChatCompletion (line 216) | async createChatCompletion<T = LLMResponse>({
FILE: packages/core/lib/v3/llm/GroqClient.ts
class GroqClient (line 14) | class GroqClient extends LLMClient {
method constructor (line 20) | constructor({
method createChatCompletion (line 43) | async createChatCompletion<T = LLMResponse>({
FILE: packages/core/lib/v3/llm/LLMClient.ts
type ChatMessage (line 18) | interface ChatMessage {
type ChatMessageContent (line 23) | type ChatMessageContent =
type ChatMessageImageContent (line 27) | interface ChatMessageImageContent {
type ChatMessageTextContent (line 38) | interface ChatMessageTextContent {
type ChatCompletionOptions (line 46) | interface ChatCompletionOptions {
type LLMResponse (line 66) | type LLMResponse = {
type CreateChatCompletionOptions (line 94) | interface CreateChatCompletionOptions {
type LLMUsage (line 101) | interface LLMUsage {
type LLMParsedResponse (line 112) | interface LLMParsedResponse<T> {
method constructor (line 124) | constructor(modelName: AvailableModel, userProvidedInstructions?: string) {
FILE: packages/core/lib/v3/llm/LLMProvider.ts
function getAISDKLanguageModel (line 102) | function getAISDKLanguageModel(
class LLMProvider (line 134) | class LLMProvider {
method constructor (line 137) | constructor(logger: (message: LogLine) => void) {
method getClient (line 141) | getClient(
method getModelProvider (line 223) | static getModelProvider(modelName: AvailableModel): ModelProvider {
FILE: packages/core/lib/v3/llm/OpenAIClient.ts
class OpenAIClient (line 28) | class OpenAIClient extends LLMClient {
method constructor (line 33) | constructor({
method createChatCompletion (line 47) | async createChatCompletion<T = LLMResponse>({
FILE: packages/core/lib/v3/llm/aisdk.ts
class AISdkClient (line 26) | class AISdkClient extends LLMClient {
method constructor (line 31) | constructor({
method getLanguageModel (line 43) | public getLanguageModel(): LanguageModelV2 {
method createChatCompletion (line 47) | async createChatCompletion<T = ChatCompletion>({
FILE: packages/core/lib/v3/logger.ts
function bindInstanceLogger (line 35) | function bindInstanceLogger(
function unbindInstanceLogger (line 42) | function unbindInstanceLogger(instanceId: string): void {
function withInstanceLogContext (line 46) | function withInstanceLogContext<T>(instanceId: string, fn: () => T): T {
function v3Logger (line 54) | function v3Logger(line: LogLine): void {
FILE: packages/core/lib/v3/mcp/connection.ts
type ConnectToMCPServerOptions (line 12) | interface ConnectToMCPServerOptions {
type StdioServerConfig (line 18) | interface StdioServerConfig {
FILE: packages/core/lib/v3/runtimePaths.ts
constant PACKAGE_SEGMENT (line 13) | const PACKAGE_SEGMENT = "/packages/core/";
constant EVAL_FRAMES (line 14) | const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]);
constant INTERNAL_FRAME_NAMES (line 15) | const INTERNAL_FRAME_NAMES = new Set([
type CallSiteWithScriptName (line 44) | type CallSiteWithScriptName = NodeJS.CallSite & {
FILE: packages/core/lib/v3/shutdown/cleanupLocal.ts
function cleanupLocalBrowser (line 11) | async function cleanupLocalBrowser(opts: {
FILE: packages/core/lib/v3/shutdown/supervisor.ts
constant SIGKILL_POLL_MS (line 14) | const SIGKILL_POLL_MS = 250;
constant SIGKILL_TIMEOUT_MS (line 15) | const SIGKILL_TIMEOUT_MS = 7_000;
constant PID_POLL_INTERVAL_MS (line 16) | const PID_POLL_INTERVAL_MS = 500;
FILE: packages/core/lib/v3/shutdown/supervisorClient.ts
function startShutdownSupervisor (line 76) | function startShutdownSupervisor(
FILE: packages/core/lib/v3/timeoutConfig.ts
function getEnvTimeoutMs (line 3) | function getEnvTimeoutMs(name: string): number | undefined {
function withTimeout (line 12) | async function withTimeout<T>(
FILE: packages/core/lib/v3/types/private/agent.ts
type ActionMappingOptions (line 1) | interface ActionMappingOptions {
FILE: packages/core/lib/v3/types/private/api.ts
type SerializableResponse (line 3) | interface SerializableResponse {
FILE: packages/core/lib/v3/types/private/cache.ts
type ActFn (line 15) | type ActFn = (
type AgentCacheContext (line 20) | type AgentCacheContext = {
type AgentCacheTransferPayload (line 31) | type AgentCacheTransferPayload = {
type AgentCacheDeps (line 36) | type AgentCacheDeps = {
type ActCacheContext (line 49) | type ActCacheContext = {
type ActCacheDeps (line 57) | type ActCacheDeps = {
type ReadJsonResult (line 65) | type ReadJsonResult<T> = {
type WriteJsonResult (line 71) | type WriteJsonResult = {
type CachedActEntry (line 76) | interface CachedActEntry {
type AgentReplayStep (line 86) | type AgentReplayStep =
type AgentReplayActStep (line 96) | interface AgentReplayActStep {
type AgentReplayFillFormStep (line 105) | interface AgentReplayFillFormStep {
type AgentReplayGotoStep (line 112) | interface AgentReplayGotoStep {
type AgentReplayScrollStep (line 118) | interface AgentReplayScrollStep {
type AgentReplayWaitStep (line 125) | interface AgentReplayWaitStep {
type AgentReplayNavBackStep (line 130) | interface AgentReplayNavBackStep {
type AgentReplayKeysStep (line 135) | interface AgentReplayKeysStep {
type SanitizedAgentExecuteOptions (line 146) | interface SanitizedAgentExecuteOptions {
type CachedAgentEntry (line 151) | interface CachedAgentEntry {
FILE: packages/core/lib/v3/types/private/evaluator.ts
type EvaluateOptions (line 1) | type EvaluateOptions = {
type BatchAskOptions (line 16) | type BatchAskOptions = {
type EvaluationResult (line 33) | interface EvaluationResult {
FILE: packages/core/lib/v3/types/private/handlers.ts
type ActHandlerParams (line 6) | interface ActHandlerParams {
type ExtractHandlerParams (line 14) | interface ExtractHandlerParams<T extends StagehandZodSchema> {
type ObserveHandlerParams (line 23) | interface ObserveHandlerParams {
type SupportedUnderstudyAction (line 32) | enum SupportedUnderstudyAction {
FILE: packages/core/lib/v3/types/private/internal.ts
type InitState (line 4) | type InitState =
type EncodedId (line 16) | type EncodedId = `${number}-${number}`;
type ZodPathSegments (line 28) | interface ZodPathSegments {
type InitScriptSource (line 36) | type InitScriptSource<Arg> =
FILE: packages/core/lib/v3/types/private/locator.ts
type NormalizedFilePayload (line 3) | interface NormalizedFilePayload {
FILE: packages/core/lib/v3/types/private/network.ts
type NetworkRequestInfo (line 4) | type NetworkRequestInfo = {
type NetworkObserver (line 17) | interface NetworkObserver {
type WaitForIdleOptions (line 24) | type WaitForIdleOptions = {
constant DEFAULT_IDLE_WAIT (line 32) | const DEFAULT_IDLE_WAIT = 500;
constant IGNORED_RESOURCE_TYPES (line 33) | const IGNORED_RESOURCE_TYPES = new Set<
type WaitForIdleHandle (line 38) | type WaitForIdleHandle = {
FILE: packages/core/lib/v3/types/private/shutdown.ts
type ShutdownSupervisorConfig (line 5) | type ShutdownSupervisorConfig =
type ShutdownSupervisorHandle (line 20) | interface ShutdownSupervisorHandle {
FILE: packages/core/lib/v3/types/private/shutdownErrors.ts
class ShutdownSupervisorError (line 5) | class ShutdownSupervisorError extends Error {
method constructor (line 6) | constructor(message: string) {
class ShutdownSupervisorResolveError (line 12) | class ShutdownSupervisorResolveError extends ShutdownSupervisorError {
method constructor (line 13) | constructor(message: string) {
class ShutdownSupervisorSpawnError (line 19) | class ShutdownSupervisorSpawnError extends ShutdownSupervisorError {
method constructor (line 20) | constructor(message: string) {
FILE: packages/core/lib/v3/types/private/snapshot.ts
type SnapshotOptions (line 4) | type SnapshotOptions = {
type HybridSnapshot (line 28) | type HybridSnapshot = {
type PerFrameSnapshot (line 39) | type PerFrameSnapshot = {
type SessionDomIndex (line 50) | type SessionDomIndex = {
type FrameDomMaps (line 59) | type FrameDomMaps = {
type ResolvedLocation (line 66) | type ResolvedLocation = {
type ResolvedFocusFrame (line 72) | type ResolvedFocusFrame = {
type ResolvedCssFocus (line 78) | type ResolvedCssFocus = {
type Axis (line 84) | type Axis = "child" | "desc";
type Step (line 86) | type Step = {
type A11yNode (line 92) | type A11yNode = {
type A11yOptions (line 105) | type A11yOptions = {
type AccessibilityTreeResult (line 113) | type AccessibilityTreeResult = {
type FrameParentIndex (line 119) | type FrameParentIndex = Map<string, string | null>;
type FrameContext (line 127) | type FrameContext = {
FILE: packages/core/lib/v3/types/public/agent.ts
type VariableValue (line 49) | type VariableValue =
type Variables (line 58) | type Variables = Record<string, VariableValue>;
type AgentContext (line 60) | interface AgentContext {
type AgentState (line 70) | interface AgentState {
type AgentAction (line 78) | interface AgentAction {
type AgentResult (line 91) | interface AgentResult {
type AgentStreamResult (line 118) | type AgentStreamResult = StreamTextResult<ToolSet, never> & {
type AgentCallbacks (line 125) | interface AgentCallbacks {
type StreamingCallbackNotAvailable (line 145) | type StreamingCallbackNotAvailable =
type SafetyConfirmationCallbackNotAvailable (line 152) | type SafetyConfirmationCallbackNotAvailable =
type AgentExecuteCallbacks (line 158) | interface AgentExecuteCallbacks extends AgentCallbacks {
type AgentStreamCallbacks (line 237) | interface AgentStreamCallbacks extends AgentCallbacks {
type AgentExecuteOptionsBase (line 272) | interface AgentExecuteOptionsBase {
type AgentExecuteOptions (line 425) | interface AgentExecuteOptions extends AgentExecuteOptionsBase {
type AgentStreamExecuteOptions (line 437) | interface AgentStreamExecuteOptions extends AgentExecuteOptionsBase {
type AgentType (line 444) | type AgentType =
constant AVAILABLE_CUA_MODELS (line 451) | const AVAILABLE_CUA_MODELS = [
type AvailableCuaModel (line 465) | type AvailableCuaModel = (typeof AVAILABLE_CUA_MODELS)[number];
type AgentExecutionOptions (line 467) | interface AgentExecutionOptions<
type AgentHandlerOptions (line 475) | interface AgentHandlerOptions {
type ActionExecutionResult (line 482) | interface ActionExecutionResult {
type SafetyCheck (line 493) | interface SafetyCheck {
type SafetyConfirmationResponse (line 505) | interface SafetyConfirmationResponse {
type SafetyConfirmationHandler (line 535) | type SafetyConfirmationHandler = (
type ToolUseItem (line 541) | interface ToolUseItem extends ResponseItem {
type AnthropicMessage (line 548) | interface AnthropicMessage {
type AnthropicContentBlock (line 553) | interface AnthropicContentBlock {
type AnthropicTextBlock (line 558) | interface AnthropicTextBlock extends AnthropicContentBlock {
type AnthropicToolResult (line 563) | interface AnthropicToolResult {
type ResponseItem (line 571) | interface ResponseItem {
type ComputerCallItem (line 577) | interface ComputerCallItem extends ResponseItem {
type FunctionCallItem (line 591) | interface FunctionCallItem extends ResponseItem {
type ResponseInputItem (line 598) | type ResponseInputItem =
type AgentInstance (line 624) | interface AgentInstance {
type AgentProviderType (line 630) | type AgentProviderType = AgentType;
type AgentModelConfig (line 632) | type AgentModelConfig<TModelName extends string = string> = {
type AgentToolMode (line 642) | type AgentToolMode = "dom" | "hybrid" | "cua";
type AgentConfig (line 644) | type AgentConfig = {
type StreamingAgentInstance (line 693) | interface StreamingAgentInstance {
type NonStreamingAgentInstance (line 704) | interface NonStreamingAgentInstance {
type ModelOutputContentItem (line 718) | type ModelOutputContentItem =
type ClickToolResult (line 722) | interface ClickToolResult {
type TypeToolResult (line 730) | interface TypeToolResult {
type DragAndDropToolResult (line 738) | interface DragAndDropToolResult {
type FillFormField (line 745) | interface FillFormField {
type FillFormVisionToolResult (line 751) | interface FillFormVisionToolResult {
type ScrollToolResult (line 758) | interface ScrollToolResult {
type ScrollVisionToolResult (line 765) | interface ScrollVisionToolResult extends ScrollToolResult {
type WaitToolResult (line 769) | interface WaitToolResult {
FILE: packages/core/lib/v3/types/public/api.ts
type Action (line 1055) | type Action = z.infer<typeof ActionSchema>;
type ModelConfig (line 1056) | type ModelConfig = z.infer<typeof ModelConfigSchema>;
type BrowserConfig (line 1057) | type BrowserConfig = z.infer<typeof BrowserConfigSchema>;
type SessionIdParams (line 1058) | type SessionIdParams = z.infer<typeof SessionIdParamsSchema>;
type SessionHeaders (line 1061) | type SessionHeaders = z.infer<typeof SessionHeadersSchema>;
type BrowserbaseViewport (line 1064) | type BrowserbaseViewport = z.infer<typeof BrowserbaseViewportSchema>;
type BrowserbaseFingerprintScreen (line 1065) | type BrowserbaseFingerprintScreen = z.infer<
type BrowserbaseFingerprint (line 1068) | type BrowserbaseFingerprint = z.infer<
type BrowserbaseContext (line 1071) | type BrowserbaseContext = z.infer<typeof BrowserbaseContextSchema>;
type BrowserbaseBrowserSettings (line 1072) | type BrowserbaseBrowserSettings = z.infer<
type BrowserbaseProxyGeolocation (line 1075) | type BrowserbaseProxyGeolocation = z.infer<
type BrowserbaseProxyConfig (line 1078) | type BrowserbaseProxyConfig = z.infer<
type ExternalProxyConfig (line 1081) | type ExternalProxyConfig = z.infer<typeof ExternalProxyConfigSchema>;
type BrowserbaseRegion (line 1082) | type BrowserbaseRegion = z.infer<typeof BrowserbaseRegionSchema>;
type BrowserbaseSessionCreateParams (line 1083) | type BrowserbaseSessionCreateParams = z.infer<
type _BrowserbaseSessionCreateParamsCheck (line 1090) | type _BrowserbaseSessionCreateParamsCheck =
type SessionStartRequest (line 1096) | type SessionStartRequest = z.infer<typeof SessionStartRequestSchema>;
type SessionStartResult (line 1097) | type SessionStartResult = z.infer<typeof SessionStartResultSchema>;
type SessionStartResponse (line 1098) | type SessionStartResponse = z.infer<typeof SessionStartResponseSchema>;
type SessionEndResult (line 1101) | type SessionEndResult = z.infer<typeof SessionEndResultSchema>;
type SessionEndResponse (line 1102) | type SessionEndResponse = z.infer<typeof SessionEndResponseSchema>;
type ActRequest (line 1105) | type ActRequest = z.infer<typeof ActRequestSchema>;
type ActResultData (line 1106) | type ActResultData = z.infer<typeof ActResultDataSchema>;
type ActResult (line 1107) | type ActResult = z.infer<typeof ActResultSchema>;
type ActResponse (line 1108) | type ActResponse = z.infer<typeof ActResponseSchema>;
type ExtractRequest (line 1111) | type ExtractRequest = z.infer<typeof ExtractRequestSchema>;
type ExtractResult (line 1112) | type ExtractResult = z.infer<typeof ExtractResultSchema>;
type ExtractResponse (line 1113) | type ExtractResponse = z.infer<typeof ExtractResponseSchema>;
type ObserveRequest (line 1116) | type ObserveRequest = z.infer<typeof ObserveRequestSchema>;
type ObserveResult (line 1117) | type ObserveResult = z.infer<typeof ObserveResultSchema>;
type ObserveResponse (line 1118) | type ObserveResponse = z.infer<typeof ObserveResponseSchema>;
type AgentAction (line 1121) | type AgentAction = z.infer<typeof AgentActionSchema>;
type AgentUsage (line 1122) | type AgentUsage = z.infer<typeof AgentUsageSchema>;
type AgentResultData (line 1123) | type AgentResultData = z.infer<typeof AgentResultDataSchema>;
type AgentExecuteRequest (line 1124) | type AgentExecuteRequest = z.infer<typeof AgentExecuteRequestSchema>;
type AgentExecuteResult (line 1125) | type AgentExecuteResult = z.infer<typeof AgentExecuteResultSchema>;
type AgentExecuteResponse (line 1126) | type AgentExecuteResponse = z.infer<typeof AgentExecuteResponseSchema>;
type NavigateRequest (line 1129) | type NavigateRequest = z.infer<typeof NavigateRequestSchema>;
type NavigateResult (line 1130) | type NavigateResult = z.infer<typeof NavigateResultSchema>;
type NavigateResponse (line 1131) | type NavigateResponse = z.infer<typeof NavigateResponseSchema>;
type TokenUsage (line 1134) | type TokenUsage = z.infer<typeof TokenUsageSchema>;
type ReplayAction (line 1135) | type ReplayAction = z.infer<typeof ReplayActionSchema>;
type ReplayPage (line 1136) | type ReplayPage = z.infer<typeof ReplayPageSchema>;
type ReplayResult (line 1137) | type ReplayResult = z.infer<typeof ReplayResultSchema>;
type ReplayResponse (line 1138) | type ReplayResponse = z.infer<typeof ReplayResponseSchema>;
type StreamEventStatus (line 1141) | type StreamEventStatus = z.infer<typeof StreamEventStatusSchema>;
type StreamEventType (line 1142) | type StreamEventType = z.infer<typeof StreamEventTypeSchema>;
type StreamEventSystemData (line 1143) | type StreamEventSystemData = z.infer<typeof StreamEventSystemDataSchema>;
type StreamEventLogData (line 1144) | type StreamEventLogData = z.infer<typeof StreamEventLogDataSchema>;
type StreamEvent (line 1145) | type StreamEvent = z.infer<typeof StreamEventSchema>;
FILE: packages/core/lib/v3/types/public/apiErrors.ts
class StagehandAPIError (line 1) | class StagehandAPIError extends Error {
method constructor (line 2) | constructor(message: string) {
class StagehandAPIUnauthorizedError (line 8) | class StagehandAPIUnauthorizedError extends StagehandAPIError {
method constructor (line 9) | constructor(message?: string) {
class StagehandHttpError (line 14) | class StagehandHttpError extends StagehandAPIError {
method constructor (line 15) | constructor(message: string) {
class StagehandServerError (line 20) | class StagehandServerError extends StagehandAPIError {
method constructor (line 21) | constructor(message: string) {
class StagehandResponseBodyError (line 26) | class StagehandResponseBodyError extends StagehandAPIError {
method constructor (line 27) | constructor() {
class StagehandResponseParseError (line 32) | class StagehandResponseParseError extends StagehandAPIError {
method constructor (line 33) | constructor(message: string) {
FILE: packages/core/lib/v3/types/public/context.ts
type Cookie (line 2) | interface Cookie {
type CookieParam (line 15) | interface CookieParam {
type ClearCookieOptions (line 30) | interface ClearCookieOptions {
FILE: packages/core/lib/v3/types/public/locator.ts
type MouseButton (line 3) | type MouseButton = "left" | "right" | "middle";
type SetInputFilePayload (line 5) | interface SetInputFilePayload {
type SetInputFilesArgument (line 12) | type SetInputFilesArgument =
FILE: packages/core/lib/v3/types/public/logs.ts
type LogLevel (line 1) | type LogLevel = 0 | 1 | 2;
constant LOG_LEVEL_NAMES (line 10) | const LOG_LEVEL_NAMES: Record<LogLevel, string> = {
type LogLine (line 16) | type LogLine = {
type Logger (line 30) | type Logger = (logLine: LogLine) => void;
FILE: packages/core/lib/v3/types/public/methods.ts
type ActOptions (line 13) | interface ActOptions {
type ActResult (line 26) | interface ActResult {
type ExtractResult (line 34) | type ExtractResult<T extends StagehandZodSchema> =
type Action (line 39) | interface Action {
type HistoryEntry (line 46) | interface HistoryEntry {
type ExtractOptions (line 53) | interface ExtractOptions {
type ObserveOptions (line 74) | interface ObserveOptions {
type ObserveResult (line 93) | type ObserveResult = Action[] & { cacheStatus?: "HIT" | "MISS" };
type V3FunctionName (line 95) | enum V3FunctionName {
FILE: packages/core/lib/v3/types/public/metrics.ts
type StagehandMetrics (line 1) | interface StagehandMetrics {
FILE: packages/core/lib/v3/types/public/model.ts
type OpenAIClientOptions (line 7) | type OpenAIClientOptions = Pick<
type AnthropicClientOptions (line 12) | type AnthropicClientOptions = Pick<
type GoogleServiceAccountCredentials (line 17) | interface GoogleServiceAccountCredentials {
type GoogleVertexProviderSettings (line 31) | type GoogleVertexProviderSettings = Pick<
type AnthropicJsonSchemaObject (line 40) | type AnthropicJsonSchemaObject = {
type LLMTool (line 51) | interface LLMTool {
type AISDKProvider (line 58) | type AISDKProvider = (modelName: string) => LanguageModelV2;
type AISDKCustomProvider (line 60) | type AISDKCustomProvider = (options: ClientOptions) => AISDKProvider;
type AvailableModel (line 62) | type AvailableModel =
type ModelProvider (line 89) | type ModelProvider =
type ClientOptions (line 97) | type ClientOptions = (
type ModelConfiguration (line 121) | type ModelConfiguration =
FILE: packages/core/lib/v3/types/public/options.ts
type V3Env (line 10) | type V3Env = "LOCAL" | "BROWSERBASE";
type LocalBrowserLaunchOptions (line 15) | type LocalBrowserLaunchOptions = z.infer<
type V3Options (line 20) | interface V3Options {
FILE: packages/core/lib/v3/types/public/page.ts
type AnyPage (line 7) | type AnyPage = PlaywrightPage | PuppeteerPage | PatchrightPage | Page;
type LoadState (line 12) | type LoadState = "load" | "domcontentloaded" | "networkidle";
type SnapshotResult (line 15) | type SnapshotResult = {
type PageSnapshotOptions (line 21) | type PageSnapshotOptions = {
FILE: packages/core/lib/v3/types/public/screenshotTypes.ts
type ScreenshotAnimationsOption (line 3) | type ScreenshotAnimationsOption = "disabled" | "allow";
type ScreenshotCaretOption (line 4) | type ScreenshotCaretOption = "hide" | "initial";
type ScreenshotScaleOption (line 5) | type ScreenshotScaleOption = "css" | "device";
type ScreenshotClip (line 7) | interface ScreenshotClip {
type ScreenshotOptions (line 14) | interface ScreenshotOptions {
FILE: packages/core/lib/v3/types/public/sdkErrors.ts
class StagehandError (line 5) | class StagehandError extends Error {
method constructor (line 8) | constructor(message: string, cause?: unknown) {
class StagehandDefaultError (line 17) | class StagehandDefaultError extends StagehandError {
method constructor (line 18) | constructor(error?: unknown) {
class StagehandEnvironmentError (line 27) | class StagehandEnvironmentError extends StagehandError {
method constructor (line 28) | constructor(
class MissingEnvironmentVariableError (line 40) | class MissingEnvironmentVariableError extends StagehandError {
method constructor (line 41) | constructor(missingEnvironmentVariable: string, feature: string) {
class UnsupportedModelError (line 49) | class UnsupportedModelError extends StagehandError {
method constructor (line 50) | constructor(supportedModels: string[], feature?: string) {
class UnsupportedModelProviderError (line 63) | class UnsupportedModelProviderError extends StagehandError {
method constructor (line 64) | constructor(supportedProviders: string[], feature?: string) {
class UnsupportedAISDKModelProviderError (line 73) | class UnsupportedAISDKModelProviderError extends StagehandError {
method constructor (line 74) | constructor(provider: string, supportedProviders: string[]) {
class InvalidAISDKModelFormatError (line 81) | class InvalidAISDKModelFormatError extends StagehandError {
method constructor (line 82) | constructor(modelName: string) {
class StagehandNotInitializedError (line 89) | class StagehandNotInitializedError extends StagehandError {
method constructor (line 90) | constructor(prop: string) {
class BrowserbaseSessionNotFoundError (line 99) | class BrowserbaseSessionNotFoundError extends StagehandError {
method constructor (line 100) | constructor() {
class CaptchaTimeoutError (line 105) | class CaptchaTimeoutError extends StagehandError {
method constructor (line 106) | constructor() {
class MissingLLMConfigurationError (line 111) | class MissingLLMConfigurationError extends StagehandError {
method constructor (line 112) | constructor() {
class HandlerNotInitializedError (line 120) | class HandlerNotInitializedError extends StagehandError {
method constructor (line 121) | constructor(handlerType: string) {
class StagehandInvalidArgumentError (line 126) | class StagehandInvalidArgumentError extends StagehandError {
method constructor (line 127) | constructor(message: string) {
class CookieValidationError (line 132) | class CookieValidationError extends StagehandError {
method constructor (line 133) | constructor(message: string) {
class CookieSetError (line 138) | class CookieSetError extends StagehandError {
method constructor (line 139) | constructor(message: string) {
class StagehandElementNotFoundError (line 144) | class StagehandElementNotFoundError extends StagehandError {
method constructor (line 145) | constructor(xpaths: string[]) {
class AgentScreenshotProviderError (line 150) | class AgentScreenshotProviderError extends StagehandError {
method constructor (line 151) | constructor(message: string) {
class StagehandMissingArgumentError (line 156) | class StagehandMissingArgumentError extends StagehandError {
method constructor (line 157) | constructor(message: string) {
class CreateChatCompletionResponseError (line 162) | class CreateChatCompletionResponseError extends StagehandError {
method constructor (line 163) | constructor(message: string) {
class StagehandEvalError (line 168) | class StagehandEvalError extends StagehandError {
method constructor (line 169) | constructor(message: string) {
class StagehandDomProcessError (line 174) | class StagehandDomProcessError extends StagehandError {
method constructor (line 175) | constructor(message: string) {
class StagehandLocatorError (line 180) | class StagehandLocatorError extends StagehandError {
method constructor (line 181) | constructor(action: string, selector: string, message: string) {
class StagehandClickError (line 188) | class StagehandClickError extends StagehandError {
method constructor (line 189) | constructor(message: string, selector: string) {
class LLMResponseError (line 196) | class LLMResponseError extends StagehandError {
method constructor (line 197) | constructor(primitive: string, message: string) {
class StagehandIframeError (line 202) | class StagehandIframeError extends StagehandError {
method constructor (line 203) | constructor(frameUrl: string, message: string) {
class ContentFrameNotFoundError (line 210) | class ContentFrameNotFoundError extends StagehandError {
method constructor (line 211) | constructor(selector: string) {
class XPathResolutionError (line 216) | class XPathResolutionError extends StagehandError {
method constructor (line 217) | constructor(xpath: string) {
class ExperimentalApiConflictError (line 222) | class ExperimentalApiConflictError extends StagehandError {
method constructor (line 223) | constructor() {
class ExperimentalNotConfiguredError (line 232) | class ExperimentalNotConfiguredError extends StagehandError {
method constructor (line 233) | constructor(featureName: string) {
class CuaModelRequiredError (line 241) | class CuaModelRequiredError extends StagehandError {
method constructor (line 242) | constructor(availableModels: readonly string[]) {
class ZodSchemaValidationError (line 250) | class ZodSchemaValidationError extends Error {
method constructor (line 251) | constructor(
class StagehandInitError (line 266) | class StagehandInitError extends StagehandError {
method constructor (line 267) | constructor(message: string) {
class MCPConnectionError (line 272) | class MCPConnectionError extends StagehandError {
method constructor (line 276) | constructor(serverUrl: string, originalError: unknown) {
class StagehandShadowRootMissingError (line 292) | class StagehandShadowRootMissingError extends StagehandError {
method constructor (line 293) | constructor(detail?: string) {
class StagehandShadowSegmentEmptyError (line 301) | class StagehandShadowSegmentEmptyError extends StagehandError {
method constructor (line 302) | constructor() {
class StagehandShadowSegmentNotFoundError (line 307) | class StagehandShadowSegmentNotFoundError extends StagehandError {
method constructor (line 308) | constructor(segment: string, hint?: string) {
class ElementNotVisibleError (line 316) | class ElementNotVisibleError extends StagehandError {
method constructor (line 317) | constructor(selector: string) {
class ResponseBodyError (line 322) | class ResponseBodyError extends StagehandError {
method constructor (line 323) | constructor(message: string) {
class ResponseParseError (line 328) | class ResponseParseError extends StagehandError {
method constructor (line 329) | constructor(message: string) {
class TimeoutError (line 334) | class TimeoutError extends StagehandError {
method constructor (line 335) | constructor(operation: string, timeoutMs: number) {
class ActTimeoutError (line 340) | class ActTimeoutError extends TimeoutError {
method constructor (line 341) | constructor(timeoutMs: number) {
class ExtractTimeoutError (line 347) | class ExtractTimeoutError extends TimeoutError {
method constructor (line 348) | constructor(timeoutMs: number) {
class ObserveTimeoutError (line 354) | class ObserveTimeoutError extends TimeoutError {
method constructor (line 355) | constructor(timeoutMs: number) {
class PageNotFoundError (line 361) | class PageNotFoundError extends StagehandError {
method constructor (line 362) | constructor(identifier: string) {
class ConnectionTimeoutError (line 367) | class ConnectionTimeoutError extends StagehandError {
method constructor (line 368) | constructor(message: string) {
class StreamingCallbacksInNonStreamingModeError (line 373) | class StreamingCallbacksInNonStreamingModeError extends StagehandError {
method constructor (line 376) | constructor(invalidCallbacks: string[]) {
class AgentAbortError (line 385) | class AgentAbortError extends StagehandError {
method constructor (line 388) | constructor(reason?: string) {
class StagehandClosedError (line 397) | class StagehandClosedError extends StagehandError {
method constructor (line 398) | constructor() {
class CdpConnectionClosedError (line 403) | class CdpConnectionClosedError extends StagehandError {
method constructor (line 404) | constructor(reason: string) {
class StagehandSetExtraHTTPHeadersError (line 409) | class StagehandSetExtraHTTPHeadersError extends StagehandError {
method constructor (line 412) | constructor(failures: string[]) {
class StagehandSnapshotError (line 420) | class StagehandSnapshotError extends StagehandError {
method constructor (line 421) | constructor(cause?: unknown) {
class UnderstudyCommandException (line 432) | class UnderstudyCommandException extends StagehandError {
method constructor (line 433) | constructor(message: string, cause?: unknown) {
FILE: packages/core/lib/v3/understudy/a11y/snapshot/a11yTree.ts
function a11yForFrame (line 18) | async function a11yForFrame(
function decorateRoles (line 102) | function decorateRoles(
function buildHierarchicalTree (line 147) | async function buildHierarchicalTree(
function isStructural (line 213) | function isStructural(role: string): boolean {
function extractUrlFromAXNode (line 218) | function extractUrlFromAXNode(
function removeRedundantStaticTextChildren (line 227) | function removeRedundantStaticTextChildren(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/activeElement.ts
function computeActiveElementXpath (line 18) | async function computeActiveElementXpath(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/capture.ts
function captureHybridSnapshot (line 45) | async function captureHybridSnapshot(
function buildFrameContext (line 98) | function buildFrameContext(page: Page): FrameContext {
function tryScopedSnapshot (line 119) | async function tryScopedSnapshot(
function buildSessionIndexes (line 241) | async function buildSessionIndexes(
function collectPerFrameMaps (line 268) | async function collectPerFrameMaps(
function computeFramePrefixes (line 348) | async function computeFramePrefixes(
function mergeFramesIntoSnapshot (line 417) | function mergeFramesIntoSnapshot(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/coordinateResolver.ts
function resolveXpathForLocation (line 15) | async function resolveXpathForLocation(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/domTree.ts
constant DOM_DEPTH_ATTEMPTS (line 12) | const DOM_DEPTH_ATTEMPTS = [-1, 256, 128, 64, 32, 16, 8, 4, 2, 1];
constant DESCRIBE_DEPTH_ATTEMPTS (line 13) | const DESCRIBE_DEPTH_ATTEMPTS = [-1, 64, 32, 16, 8, 4, 2, 1];
function isCborStackError (line 16) | function isCborStackError(message: string): boolean {
function shouldExpandNode (line 25) | function shouldExpandNode(node: Protocol.DOM.Node): boolean {
function mergeDomNodes (line 32) | function mergeDomNodes(
function collectDomTraversalTargets (line 43) | function collectDomTraversalTargets(
function hydrateDomTree (line 57) | async function hydrateDomTree(
function getDomTreeWithFallback (line 138) | async function getDomTreeWithFallback(
function domMapsForSession (line 177) | async function domMapsForSession(
function buildSessionDomIndex (line 257) | async function buildSessionDomIndex(
function relativizeXPath (line 318) | function relativizeXPath(baseAbs: string, nodeAbs: string): string {
function findNodeByBackendId (line 332) | function findNodeByBackendId(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/focusSelectors.ts
function parseXPathToSteps (line 20) | function parseXPathToSteps(path: string): Step[] {
function buildXPathFromSteps (line 45) | function buildXPathFromSteps(steps: ReadonlyArray<Step>): string {
constant IFRAME_STEP_RE (line 54) | const IFRAME_STEP_RE = /^i?frame(?:\[\d+])?$/i;
function resolveFocusFrameAndTail (line 62) | async function resolveFocusFrameAndTail(
function resolveCssFocusFrameAndTail (line 139) | async function resolveCssFocusFrameAndTail(
function resolveObjectIdForXPath (line 203) | async function resolveObjectIdForXPath(
function resolveObjectIdForCss (line 238) | async function resolveObjectIdForCss(
function listChildrenOf (line 283) | function listChildrenOf(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/sessions.ts
function ownerSession (line 12) | function ownerSession(page: Page, frameId: string): CDPSessionLike {
function parentSession (line 21) | function parentSession(
FILE: packages/core/lib/v3/understudy/a11y/snapshot/treeFormatUtils.ts
function formatTreeLine (line 8) | function formatTreeLine(node: A11yNode, level = 0): string {
function injectSubtrees (line 21) | function injectSubtrees(
function indentBlock (line 59) | function indentBlock(block: string, indent: string): string {
function diffCombinedTrees (line 72) | function diffCombinedTrees(prevTree: string, nextTree: string): string {
function cleanText (line 108) | function cleanText(input: string): string {
function normaliseSpaces (line 135) | function normaliseSpaces(s: string): string {
FILE: packages/core/lib/v3/understudy/a11y/snapshot/xpathUtils.ts
function buildAbsoluteXPathFromChain (line 9) | async function buildAbsoluteXPathFromChain(
function absoluteXPathForBackendNode (line 38) | async function absoluteXPathForBackendNode(
function prefixXPath (line 71) | function prefixXPath(parentAbs: string, child: string): string {
function normalizeXPath (line 81) | function normalizeXPath(x?: string): string {
function buildChildXPathSegments (line 90) | function buildChildXPathSegments(kids: Protocol.DOM.Node[]): string[] {
function joinXPath (line 111) | function joinXPath(base: string, step: string): string {
FILE: packages/core/lib/v3/understudy/a11yInvocation.ts
function buildA11yInvocation (line 13) | function buildA11yInvocation(
FILE: packages/core/lib/v3/understudy/cdp.ts
type CDPSessionLike (line 23) | interface CDPSessionLike {
type Inflight (line 31) | type Inflight = {
type EventHandler (line 43) | type EventHandler = (params: unknown) => void;
type SessionDispatchWaiter (line 44) | type SessionDispatchWaiter = {
type RawMessage (line 52) | type RawMessage =
class CdpConnection (line 61) | class CdpConnection implements CDPSessionLike {
method onTransportClosed (line 83) | public onTransportClosed(handler: (why: string) => void): void {
method offTransportClosed (line 86) | public offTransportClosed(handler: (why: string) => void): void {
method emitTransportClosed (line 90) | private emitTransportClosed(why: string) {
method constructor (line 100) | private constructor(ws: WebSocket) {
method connect (line 117) | static async connect(
method enableAutoAttach (line 135) | async enableAutoAttach(): Promise<void> {
method send (line 144) | async send<R = unknown>(method: string, params?: object): Promise<R> {
method on (line 181) | on<P = unknown>(event: string, handler: (params: P) => void): void {
method off (line 187) | off<P = unknown>(event: string, handler: (params: P) => void): void {
method close (line 192) | async close(): Promise<void> {
method rejectAllInflight (line 200) | private rejectAllInflight(why: string): void {
method getSession (line 211) | getSession(sessionId: string): CdpSession | undefined {
method waitForSessionDispatch (line 215) | waitForSessionDispatch(
method attachToTarget (line 238) | async attachToTarget(targetId: string): Promise<CdpSession> {
method getTargets (line 253) | async getTargets(): Promise<Protocol.Target.TargetInfo[]> {
method onMessage (line 260) | private onMessage(json: string): void {
method _sendViaSession (line 429) | _sendViaSession<R = unknown>(
method _onSessionEvent (line 485) | _onSessionEvent(
method _offSessionEvent (line 496) | _offSessionEvent(
method _dispatchToSession (line 506) | _dispatchToSession(sessionId: string, event: string, params: unknown):...
class CdpSession (line 513) | class CdpSession implements CDPSessionLike {
method constructor (line 514) | constructor(
method send (line 519) | send<R = unknown>(method: string, params?: object): Promise<R> {
method on (line 523) | on<P = unknown>(event: string, handler: (params: P) => void): void {
method off (line 527) | off<P = unknown>(event: string, handler: (params: P) => void): void {
method close (line 531) | async close(): Promise<void> {
method dispatch (line 537) | dispatch(event: string, params: unknown): void {
FILE: packages/core/lib/v3/understudy/consoleMessage.ts
type RemoteObject (line 4) | type RemoteObject = Protocol.Runtime.RemoteObject;
type ConsoleListener (line 6) | type ConsoleListener = (message: ConsoleMessage) => void;
function formatRemoteObject (line 8) | function formatRemoteObject(obj: RemoteObject | undefined): string {
class ConsoleMessage (line 28) | class ConsoleMessage {
method constructor (line 29) | constructor(
method type (line 34) | type(): Protocol.Runtime.ConsoleAPICalledEvent["type"] {
method text (line 38) | text(): string {
method args (line 47) | args(): RemoteObject[] {
method location (line 51) | location(): { url?: string; lineNumber?: number; columnNumber?: number...
method page (line 60) | page(): Page | undefined {
method timestamp (line 64) | timestamp(): number | undefined {
method raw (line 68) | raw(): Protocol.Runtime.ConsoleAPICalledEvent {
method toString (line 72) | toString(): string {
FILE: packages/core/lib/v3/understudy/context.ts
type TargetId (line 32) | type TargetId = string;
type SessionId (line 33) | type SessionId = string;
type TargetType (line 35) | type TargetType = "page" | "iframe" | string;
function hasInjectableDOM (line 43) | function hasInjectableDOM(url: string | undefined): boolean {
function isNonWebTarget (line 62) | function isNonWebTarget(info: Protocol.Target.TargetInfo): boolean {
function isTopLevelPage (line 69) | function isTopLevelPage(info: Protocol.Target.TargetInfo): boolean {
constant DEFAULT_FIRST_TOP_LEVEL_PAGE_TIMEOUT_MS (line 74) | const DEFAULT_FIRST_TOP_LEVEL_PAGE_TIMEOUT_MS = 5000;
constant CI_FIRST_TOP_LEVEL_PAGE_TIMEOUT_MS (line 75) | const CI_FIRST_TOP_LEVEL_PAGE_TIMEOUT_MS = 30000;
constant FIRST_TOP_LEVEL_PAGE_TIMEOUT_ENV (line 76) | const FIRST_TOP_LEVEL_PAGE_TIMEOUT_ENV =
constant WAIT_FOR_FIRST_TOP_LEVEL_PAGE_OPERATION (line 78) | const WAIT_FOR_FIRST_TOP_LEVEL_PAGE_OPERATION =
function getFirstTopLevelPageTimeoutMs (line 81) | function getFirstTopLevelPageTimeoutMs(): number {
class V3Context (line 101) | class V3Context {
method constructor (line 102) | private constructor(
method installTargetSessionListeners (line 127) | private installTargetSessionListeners(session: CDPSessionLike): void {
method create (line 156) | static async create(
method hasTopLevelPage (line 207) | private hasTopLevelPage(): boolean {
method ensureFirstTopLevelPage (line 216) | private async ensureFirstTopLevelPage(timeoutMs: number): Promise<void> {
method waitForFirstTopLevelPage (line 241) | private async waitForFirstTopLevelPage(timeoutMs: number): Promise<voi...
method waitForInitialTopLevelTargets (line 257) | private async waitForInitialTopLevelTargets(
method ensurePiercer (line 288) | private async ensurePiercer(session: CDPSessionLike): Promise<boolean> {
method _pushActive (line 300) | private _pushActive(tid: TargetId): void {
method _removeFromOrder (line 308) | private _removeFromOrder(tid: TargetId): void {
method activePage (line 314) | public activePage(): Page | undefined {
method setActivePage (line 337) | public setActivePage(page: Page): void {
method addInitScript (line 361) | public async addInitScript<Arg>(
method setExtraHTTPHeaders (line 372) | public async setExtraHTTPHeaders(
method pages (line 420) | pages(): Page[] {
method applyInitScriptsToPage (line 431) | private async applyInitScriptsToPage(
method resolvePageByMainFrameId (line 450) | resolvePageByMainFrameId(frameId: string): Page | undefined {
method getFullFrameTreeByMainFrameId (line 458) | async getFullFrameTreeByMainFrameId(
method newPage (line 470) | public async newPage(url = "about:blank"): Promise<Page> {
method close (line 504) | async close(): Promise<void> {
method bootstrap (line 522) | private async bootstrap(): Promise<void> {
method onAttachedToTarget (line 586) | private async onAttachedToTarget(
method onDetachedFromTarget (line 892) | private onDetachedFromTarget(
method cleanupByTarget (line 920) | private cleanupByTarget(targetId: TargetId): void {
method installFrameEventBridges (line 948) | private installFrameEventBridges(sessionId: SessionId, owner: Page): v...
method wireSessionToOwnerPage (line 1020) | private wireSessionToOwnerPage(sessionId: SessionId, owner: Page): void {
method findTargetIdByPage (line 1027) | private findTargetIdByPage(page: Page): TargetId | undefined {
method _notePopupSignal (line 1034) | private _notePopupSignal(): void {
method awaitActivePage (line 1042) | async awaitActivePage(timeoutMs?: number): Promise<Page> {
method cookies (line 1083) | async cookies(urls?: string | string[]): Promise<Cookie[]> {
method addCookies (line 1112) | async addCookies(cookies: CookieParam[]): Promise<void> {
method clearCookies (line 1141) | async clearCookies(options?: ClearCookieOptions): Promise<void> {
FILE: packages/core/lib/v3/understudy/cookies.ts
function filterCookies (line 19) | function filterCookies(cookies: Cookie[], urls: string[]): Cookie[] {
function normalizeCookieParams (line 64) | function normalizeCookieParams(cookies: CookieParam[]): CookieParam[] {
function toCdpCookieParam (line 133) | function toCdpCookieParam(
function cookieMatchesFilter (line 152) | function cookieMatchesFilter(
FILE: packages/core/lib/v3/understudy/deepLocator.ts
type Axis (line 8) | type Axis = "child" | "desc";
type Step (line 9) | type Step = { axis: Axis; raw: string; name: string };
type ResolvedLocatorTarget (line 11) | type ResolvedLocatorTarget = {
function parseXPath (line 17) | function parseXPath(path: string): Step[] {
function buildXPathFromSteps (line 42) | function buildXPathFromSteps(steps: ReadonlyArray<Step>): string {
function deepLocatorThroughIframes (line 52) | async function deepLocatorThroughIframes(
function resolveLocatorTarget (line 65) | async function resolveLocatorTarget(
function resolveLocatorWithHops (line 94) | async function resolveLocatorWithHops(
class DeepLocatorDelegate (line 110) | class DeepLocatorDelegate {
method constructor (line 111) | constructor(
method real (line 118) | private async real(): Promise<Locator> {
method click (line 128) | async click(options?: {
method count (line 134) | async count() {
method hover (line 137) | async hover() {
method fill (line 140) | async fill(value: string) {
method type (line 143) | async type(text: string, options?: { delay?: number }) {
method selectOption (line 146) | async selectOption(values: string | string[]) {
method scrollTo (line 149) | async scrollTo(percent: number | string) {
method isVisible (line 152) | async isVisible() {
method isChecked (line 155) | async isChecked() {
method inputValue (line 158) | async inputValue() {
method textContent (line 161) | async textContent() {
method innerHtml (line 164) | async innerHtml() {
method innerText (line 167) | async innerText() {
method centroid (line 170) | async centroid() {
method backendNodeId (line 173) | async backendNodeId() {
method highlight (line 176) | async highlight(options?: {
method sendClickEvent (line 183) | async sendClickEvent(options?: {
method setInputFiles (line 191) | async setInputFiles(
method first (line 208) | first() {
method nth (line 211) | nth(index: number): DeepLocatorDelegate {
function deepLocatorFromPage (line 232) | function deepLocatorFromPage(
function resolveDeepXPathTarget (line 240) | async function resolveDeepXPathTarget(
FILE: packages/core/lib/v3/understudy/executionContextRegistry.ts
type FrameId (line 4) | type FrameId = Protocol.Page.FrameId;
type ExecId (line 5) | type ExecId = Protocol.Runtime.ExecutionContextId;
class ExecutionContextRegistry (line 7) | class ExecutionContextRegistry {
method attachSession (line 15) | attachSession(session: CDPSessionLike): void {
method getMainWorld (line 48) | getMainWorld(session: CDPSessionLike, frameId: FrameId): ExecId | null {
method waitForMainWorld (line 52) | async waitForMainWorld(
method register (line 94) | private register(
FILE: packages/core/lib/v3/understudy/fileUploadUtils.ts
constant DEFAULT_MIME_TYPE (line 11) | const DEFAULT_MIME_TYPE = "application/octet-stream";
function normalizeInputFiles (line 19) | async function normalizeInputFiles(
function statFile (line 78) | async function statFile(absolutePath: string): Promise<Stats> {
function toBuffer (line 92) | function toBuffer(
FILE: packages/core/lib/v3/understudy/frame.ts
type FrameManager (line 8) | interface FrameManager {
class Frame (line 22) | class Frame implements FrameManager {
method constructor (line 26) | constructor(
method isBrowserRemote (line 36) | public isBrowserRemote(): boolean {
method getNodeAtLocation (line 41) | async getNodeAtLocation(x: number, y: number): Promise<Protocol.DOM.No...
method getLocationForSelector (line 60) | async getLocationForSelector(
method getAccessibilityTree (line 87) | async getAccessibilityTree(
method evaluate (line 124) | async evaluate<R = unknown, Arg = unknown>(
method screenshot (line 187) | async screenshot(options?: {
method childFrames (line 238) | async childFrames(): Promise<Frame[]> {
method waitForLoadState (line 263) | async waitForLoadState(
method locator (line 308) | locator(
method getMainWorldExecutionContextId (line 316) | private async getMainWorldExecutionContextId(): Promise<number> {
FILE: packages/core/lib/v3/understudy/frameLocator.ts
class FrameLocator (line 15) | class FrameLocator {
method constructor (line 21) | constructor(
method frameLocator (line 34) | frameLocator(selector: string): FrameLocator {
method resolveFrame (line 39) | async resolveFrame(): Promise<Frame> {
method locator (line 88) | locator(selector: string): LocatorDelegate {
class LocatorDelegate (line 94) | class LocatorDelegate {
method constructor (line 95) | constructor(
method real (line 101) | private async real(): Promise<Locator> {
method click (line 109) | async click(options?: {
method hover (line 115) | async hover() {
method fill (line 118) | async fill(value: string) {
method type (line 121) | async type(text: string, options?: { delay?: number }) {
method selectOption (line 124) | async selectOption(values: string | string[]) {
method scrollTo (line 127) | async scrollTo(percent: number | string) {
method isVisible (line 130) | async isVisible() {
method isChecked (line 133) | async isChecked() {
method inputValue (line 136) | async inputValue() {
method textContent (line 139) | async textContent() {
method innerHtml (line 142) | async innerHtml() {
method innerText (line 145) | async innerText() {
method count (line 148) | async count() {
method first (line 151) | first(): LocatorDelegate {
method nth (line 154) | nth(index: number): LocatorDelegate {
function frameLocatorFromFrame (line 170) | function frameLocatorFromFrame(
function listDirectChildFrameIdsFromRegistry (line 178) | async function listDirectChildFrameIdsFromRegistry(
function findFrameNode (line 197) | function findFrameNode(
function ensureChildFrameReady (line 214) | async function ensureChildFrameReady(
FILE: packages/core/lib/v3/understudy/frameRegistry.ts
type FrameId (line 22) | type FrameId = string;
type SessionId (line 23) | type SessionId = string;
type FrameInfo (line 25) | type FrameInfo = {
function shellFrame (line 44) | function shellFrame(id: FrameId): Protocol.Page.Frame {
class FrameRegistry (line 58) | class FrameRegistry {
method constructor (line 71) | constructor(ownerTargetId: string, mainFrameId: FrameId) {
method onFrameAttached (line 85) | onFrameAttached(
method onFrameNavigated (line 118) | onFrameNavigated(frame: Protocol.Page.Frame, sessionId: SessionId): vo...
method onNavigatedWithinDocument (line 136) | onNavigatedWithinDocument(
method onFrameDetached (line 152) | onFrameDetached(
method adoptChildSession (line 202) | adoptChildSession(
method seedFromFrameTree (line 216) | seedFromFrameTree(
method setOwnerBackendNodeId (line 240) | setOwnerBackendNodeId(childFrameId: FrameId, backendNodeId: number): v...
method mainFrameId (line 247) | mainFrameId(): FrameId {
method getOwnerSessionId (line 254) | getOwnerSessionId(frameId: FrameId): SessionId | undefined {
method getOwnerBackendNodeId (line 262) | getOwnerBackendNodeId(frameId: FrameId): number | undefined {
method getParent (line 269) | getParent(frameId: FrameId): FrameId | null {
method listAllFrames (line 276) | listAllFrames(): FrameId[] {
method asProtocolFrameTree (line 290) | asProtocolFrameTree(rootId: FrameId): Protocol.Page.FrameTree {
method sessionsForFrame (line 310) | sessionsForFrame(frameId: FrameId): SessionId[] {
method framesForSession (line 318) | framesForSession(sessionId: SessionId): FrameId[] {
method ensureNode (line 324) | private ensureNode(fid: FrameId): void {
method renameNodeId (line 335) | private renameNodeId(oldId: FrameId, newId: FrameId): void {
method setOwnerSessionIdInternal (line 372) | private setOwnerSessionIdInternal(
FILE: packages/core/lib/v3/understudy/initScripts.ts
constant DEFAULT_CALLER (line 5) | const DEFAULT_CALLER = "context.addInitScript";
function appendSourceURL (line 7) | function appendSourceURL(source: string, filePath: string): string {
function normalizeInitScriptSource (line 12) | async function normalizeInitScriptSource<Arg>(
FILE: packages/core/lib/v3/understudy/lifecycleWatcher.ts
class LifecycleWatcher (line 26) | class LifecycleWatcher {
method constructor (line 52) | constructor(params: {
method setExpectedLoaderId (line 77) | public setExpectedLoaderId(loaderId: string | undefined): void {
method wait (line 86) | public async wait(): Promise<void> {
method dispose (line 125) | public dispose(): void {
method installSessionListeners (line 147) | private installSessionListeners(): void {
method timeRemaining (line 202) | private timeRemaining(deadline: number): number {
method awaitWithAbort (line 211) | private async awaitWithAbort<T>(operation: Promise<T>): Promise<T> {
method triggerAbort (line 221) | private triggerAbort(error: Error): void {
method waitForNetworkIdle (line 229) | private waitForNetworkIdle(deadline: number): Promise<void> {
method shouldRestartAfterFollowup (line 247) | private shouldRestartAfterFollowup(error: unknown): boolean {
method adoptNewMainLoader (line 255) | private adoptNewMainLoader(loaderId: string): void {
method buildIdleFilter (line 271) | private buildIdleFilter(): (info: NetworkRequestInfo) => boolean {
FILE: packages/core/lib/v3/understudy/locator.ts
constant MAX_REMOTE_UPLOAD_BYTES (line 26) | const MAX_REMOTE_UPLOAD_BYTES = 50 * 1024 * 1024;
class Locator (line 47) | class Locator {
method constructor (line 55) | constructor(
method getFrame (line 68) | public getFrame(): Frame {
method setInputFiles (line 81) | public async setInputFiles(files: SetInputFilesArgument): Promise<void> {
method assignFilesViaPayloadInjection (line 169) | private async assignFilesViaPayloadInjection(
method backendNodeId (line 217) | async backendNodeId(): Promise<Protocol.DOM.BackendNodeId> {
method count (line 235) | public async count(): Promise<number> {
method centroid (line 246) | public async centroid(): Promise<{ x: number; y: number }> {
method highlight (line 272) | public async highlight(options?: {
method hover (line 349) | async hover(): Promise<void> {
method click (line 385) | async click(options?: {
method sendClickEvent (line 456) | async sendClickEvent(options?: {
method scrollTo (line 497) | async scrollTo(percent: number | string): Promise<void> {
method fill (line 523) | async fill(value: string): Promise<void> {
method type (line 652) | async type(text: string, options?: { delay?: number }): Promise<void> {
method selectOption (line 696) | async selectOption(values: string | string[]): Promise<string[]> {
method isVisible (line 721) | async isVisible(): Promise<boolean> {
method isChecked (line 743) | async isChecked(): Promise<boolean> {
method inputValue (line 764) | async inputValue(): Promise<string> {
method textContent (line 785) | async textContent(): Promise<string> {
method innerHtml (line 806) | async innerHtml(): Promise<string> {
method innerText (line 827) | async innerText(): Promise<string> {
method first (line 848) | first(): Locator {
method nth (line 853) | nth(index: number): Locator {
method resolveNode (line 875) | public async resolveNode(): Promise<{
method resolveNodesForMask (line 900) | public async resolveNodesForMask(): Promise<
method centerFromBoxContent (line 930) | private centerFromBoxContent(content: number[]): { cx: number; cy: num...
FILE: packages/core/lib/v3/understudy/locatorInvocation.ts
function buildLocatorInvocation (line 13) | function buildLocatorInvocation(
FILE: packages/core/lib/v3/understudy/navigationResponseTracker.ts
class NavigationResponseTracker (line 24) | class NavigationResponseTracker {
method constructor (line 57) | constructor(params: {
method dispose (line 78) | public dispose(): void {
method setExpectedLoaderId (line 92) | public setExpectedLoaderId(loaderId: string | undefined): void {
method expectNavigationWithoutKnownLoader (line 107) | public expectNavigationWithoutKnownLoader(): void {
method navigationCompleted (line 115) | public async navigationCompleted(): Promise<Response | null> {
method response (line 125) | public async response(): Promise<Response | null> {
method installListeners (line 130) | private installListeners(): void {
method addListener (line 148) | private addListener(event: string, handler: (event: unknown) => void):...
method onResponseReceived (line 154) | private onResponseReceived(
method onResponseReceivedExtraInfo (line 187) | private onResponseReceivedExtraInfo(
method onLoadingFinished (line 199) | private onLoadingFinished(
method onLoadingFailed (line 208) | private onLoadingFailed(event: Protocol.Network.LoadingFailedEvent): v...
method selectResponse (line 223) | private selectResponse(event: Protocol.Network.ResponseReceivedEvent):...
FILE: packages/core/lib/v3/understudy/networkManager.ts
class NetworkManager (line 25) | class NetworkManager {
method trackSession (line 44) | public trackSession(session: CDPSessionLike): void {
method untrackSession (line 161) | public untrackSession(rawSessionId: string | undefined): void {
method addObserver (line 183) | public addObserver(observer: NetworkObserver): () => void {
method waitForIdle (line 194) | public waitForIdle(options: WaitForIdleOptions): WaitForIdleHandle {
method dispose (line 303) | public dispose(): void {
method emitStart (line 314) | private emitStart(info: NetworkRequestInfo): void {
method emitFinish (line 321) | private emitFinish(info: NetworkRequestInfo): void {
method emitFailure (line 328) | private emitFailure(info: NetworkRequestInfo): void {
method sessionKey (line 335) | private sessionKey(session: CDPSessionLike): string {
method requestKey (line 340) | private requestKey(sessionId: string, requestId: string): string {
FILE: packages/core/lib/v3/understudy/page.ts
constant LIFECYCLE_NAME (line 74) | const LIFECYCLE_NAME: Record<LoadState, string> = {
class Page (line 80) | class Page {
method constructor (line 118) | private constructor(
method installInitScriptOnSession (line 149) | private async installInitScriptOnSession(
method applyInitScriptsToSession (line 159) | private async applyInitScriptsToSession(
method registerInitScript (line 168) | public async registerInitScript(source: string): Promise<void> {
method seedInitScript (line 182) | public seedInitScript(source: string): void {
method ensureCursorScript (line 189) | private async ensureCursorScript(): Promise<void> {
method enableCursorOverlay (line 266) | public async enableCursorOverlay(): Promise<void> {
method updateCursor (line 272) | private async updateCursor(x: number, y: number): Promise<void> {
method addInitScript (line 283) | public async addInitScript<Arg>(
method create (line 299) | static async create(
method onFrameAttached (line 356) | public onFrameAttached(
method onFrameDetached (line 370) | public onFrameDetached(
method onFrameNavigated (line 382) | public onFrameNavigated(
method onNavigatedWithinDocument (line 418) | public onNavigatedWithinDocument(
method adoptOopifSession (line 441) | public adoptOopifSession(
method detachOopifSession (line 516) | public detachOopifSession(sessionId: string): void {
method getSessionForFrame (line 530) | public getSessionForFrame(frameId: string): CDPSessionLike {
method frameForId (line 537) | public frameForId(frameId: string): Frame {
method getSessionById (line 548) | public getSessionById(id: string): CDPSessionLike | undefined {
method registerSessionForNetwork (line 552) | public registerSessionForNetwork(session: CDPSessionLike): void {
method unregisterSessionForNetwork (line 556) | public unregisterSessionForNetwork(sessionId: string | undefined): void {
method on (line 560) | public on(event: "console", listener: ConsoleListener): Page {
method once (line 575) | public once(event: "console", listener: ConsoleListener): Page {
method off (line 588) | public off(event: "console", listener: ConsoleListener): Page {
method targetId (line 604) | public targetId(): string {
method sendCDP (line 627) | public sendCDP<T = unknown>(method: string, params?: object): Promise<...
method seedCurrentUrl (line 632) | public seedCurrentUrl(url: string | undefined | null): void {
method mainFrameId (line 643) | public mainFrameId(): string {
method mainFrame (line 647) | public mainFrame(): Frame {
method close (line 655) | public async close(): Promise<void> {
method getFullFrameTree (line 679) | public getFullFrameTree(): Protocol.Page.FrameTree {
method asProtocolFrameTree (line 683) | public asProtocolFrameTree(rootMainFrameId: string): Protocol.Page.Fra...
method applyExtraHTTPHeadersToSession (line 687) | private async applyExtraHTTPHeadersToSession(
method ensureOrdinal (line 697) | private ensureOrdinal(frameId: string): number {
method getOrdinal (line 706) | public getOrdinal(frameId: string): number {
method listAllFrameIds (line 710) | public listAllFrameIds(): string[] {
method ensureConsoleTaps (line 714) | private ensureConsoleTaps(): void {
method installConsoleTap (line 723) | private installConsoleTap(session: CDPSessionLike): void {
method sessionKey (line 741) | private sessionKey(session: CDPSessionLike): string {
method resolveSessionByKey (line 745) | private resolveSessionByKey(key: string): CDPSessionLike | undefined {
method teardownConsoleTap (line 755) | private teardownConsoleTap(key: string): void {
method removeAllConsoleTaps (line 764) | private removeAllConsoleTaps(): void {
method emitConsole (line 770) | private emitConsole(evt: Protocol.Runtime.ConsoleAPICalledEvent): void {
method goto (line 800) | async goto(
method reload (line 863) | async reload(options?: {
method goBack (line 910) | async goBack(options?: {
method goForward (line 965) | async goForward(options?: {
method url (line 1017) | url(): string {
method beginNavigationCommand (line 1021) | private beginNavigationCommand(): number {
method isCurrentNavigationCommand (line 1027) | public isCurrentNavigationCommand(id: number): boolean {
method title (line 1036) | async title(): Promise<string> {
method screenshot (line 1097) | async screenshot(options?: ScreenshotOptions): Promise<Buffer> {
method setExtraHTTPHeaders (line 1189) | async setExtraHTTPHeaders(headers: Record<string, string>): Promise<vo...
method locator (line 1232) | locator(selector: string): ReturnType<Frame["locator"]> {
method deepLocator (line 1242) | deepLocator(selector: string) {
method frameLocator (line 1250) | frameLocator(selector: string): FrameLocator {
method frames (line 1258) | frames(): Frame[] {
method waitForLoadState (line 1272) | async waitForLoadState(state: LoadState, timeoutMs?: number): Promise<...
method waitForTimeout (line 1281) | async waitForTimeout(ms: number): Promise<void> {
method waitForSelector (line 1302) | async waitForSelector(
method evaluate (line 1337) | async evaluate<R = unknown, Arg = unknown>(
method setViewportSize (line 1391) | async setViewportSize(
method click (line 1424) | async click(
method hover (line 1516) | async hover(
method scroll (line 1567) | async scroll(
method dragAndDrop (line 1612) | async dragAndDrop(
method type (line 1717) | async type(
method keyPress (line 1844) | async keyPress(key: string, options?: { delay?: number }): Promise<voi...
method snapshot (line 1896) | async snapshot(options?: PageSnapshotOptions): Promise<SnapshotResult> {
method keyDown (line 1918) | private async keyDown(key: string): Promise<void> {
method keyUp (line 1999) | private async keyUp(key: string): Promise<void> {
method normalizeModifierKey (line 2049) | private normalizeModifierKey(key: string): string {
method getNamedKeys (line 2120) | private getNamedKeys(): Record<
method describePrintableKey (line 2162) | private describePrintableKey(ch: string): {
method isMacOS (line 2199) | private isMacOS(): boolean {
method macCommandsFor (line 2211) | private macCommandsFor(code: string): string[] {
method mainWorldExecutionContextId (line 2238) | private async mainWorldExecutionContextId(): Promise<number> {
method isMainLoadStateReady (line 2246) | private async isMainLoadStateReady(
method waitForMainLoadState (line 2276) | async waitForMainLoadState(
FILE: packages/core/lib/v3/understudy/piercer.ts
function installV3PiercerIntoSession (line 7) | async function installV3PiercerIntoSession(
function tapPiercerConsole (line 51) | function tapPiercerConsole(
FILE: packages/core/lib/v3/understudy/response.ts
type ServerAddr (line 26) | type ServerAddr = { ipAddress: string; port: number };
function isSerializableResponse (line 28) | function isSerializableResponse(
type Deferred (line 46) | type Deferred<T> = {
function createDeferred (line 52) | function createDeferred<T>(): Deferred<T> {
function normaliseHeaderName (line 63) | function normaliseHeaderName(name: string): string {
function splitHeaderValues (line 68) | function splitHeaderValues(value: string): string[] {
function parseHeadersText (line 79) | function parseHeadersText(
class Response (line 101) | class Response {
method constructor (line 129) | constructor(params: {
method url (line 169) | url(): string {
method status (line 174) | status(): number {
method statusText (line 179) | statusText(): string {
method ok (line 184) | ok(): boolean {
method frame (line 190) | frame(): Frame | null {
method fromServiceWorker (line 200) | fromServiceWorker(): boolean {
method securityDetails (line 208) | async securityDetails(): Promise<Protocol.Network.SecurityDetails | nu...
method serverAddr (line 213) | async serverAddr(): Promise<ServerAddr | null> {
method headers (line 221) | headers(): Record<string, string> {
method allHeaders (line 230) | async allHeaders(): Promise<Record<string, string>> {
method headerValue (line 242) | async headerValue(name: string): Promise<string | null> {
method headerValues (line 249) | async headerValues(name: string): Promise<string[]> {
method headersArray (line 265) | async headersArray(): Promise<Array<{ name: string; value: string }>> {
method body (line 291) | async body(): Promise<Buffer> {
method text (line 308) | async text(): Promise<string> {
method json (line 314) | async json<T = unknown>(): Promise<T> {
method finished (line 328) | async finished(): Promise<null | Error> {
method applyExtraInfo (line 337) | public applyExtraInfo(
method fromSerializable (line 360) | public static fromSerializable(
method markFinished (line 390) | public markFinished(error: Error | null): void {
FILE: packages/core/lib/v3/understudy/screenshotUtils.ts
type ScreenshotCleanup (line 13) | type ScreenshotCleanup = () => Promise<void> | void;
function collectFramesForScreenshot (line 15) | function collectFramesForScreenshot(page: Page): Frame[] {
function normalizeScreenshotClip (line 25) | function normalizeScreenshotClip(clip: ScreenshotClip): ScreenshotClip {
function computeScreenshotScale (line 48) | async function computeScreenshotScale(
function setTransparentBackground (line 68) | async function setTransparentBackground(
function applyStyleToFrames (line 84) | async function applyStyleToFrames(
function disableAnimations (line 140) | async function disableAnimations(
function hideCaret (line 190) | async function hideCaret(frames: Frame[]): Promise<ScreenshotCleanup> {
function applyMaskOverlays (line 205) | async function applyMaskOverlays(
function resolveMaskRects (line 338) | async function resolveMaskRects(
function resolveMaskRectForObject (line 379) | async function resolveMaskRectForObject(
function runScreenshotCleanups (line 427) | async function runScreenshotCleanups(
FILE: packages/core/lib/v3/understudy/selectorResolver.ts
type SelectorQuery (line 11) | type SelectorQuery =
type ResolvedNode (line 16) | interface ResolvedNode {
type ResolveManyOptions (line 21) | interface ResolveManyOptions {
class FrameSelectorResolver (line 25) | class FrameSelectorResolver {
method constructor (line 26) | constructor(private readonly frame: Frame) {}
method parseSelector (line 28) | public static parseSelector(raw: string): SelectorQuery {
method resolveFirst (line 66) | public async resolveFirst(
method resolveAll (line 72) | public async resolveAll(
method count (line 89) | public async count(query: SelectorQuery): Promise<number> {
method resolveAtIndex (line 102) | public async resolveAtIndex(
method buildLocatorInvocation (line 111) | private buildLocatorInvocation(
method resolveCss (line 119) | private async resolveCss(
method resolveText (line 185) | private async resolveText(
method resolveXPath (line 212) | private async resolveXPath(
method countCss (line 239) | private async countCss(selector: string): Promise<number> {
method countText (line 268) | private async countText(value: string): Promise<number> {
method countXPath (line 328) | private async countXPath(value: string): Promise<number> {
method resolveFromObjectId (line 367) | private async resolveFromObjectId(
method evaluateCount (line 385) | private async evaluateCount(
method evaluateElement (line 415) | private async evaluateElement(
FILE: packages/core/lib/v3/v3.ts
constant DEFAULT_MODEL_NAME (line 94) | const DEFAULT_MODEL_NAME = "openai/gpt-4.1-mini";
constant DEFAULT_VIEWPORT (line 95) | const DEFAULT_VIEWPORT = { width: 1288, height: 711 };
constant DEFAULT_AGENT_TOOL_TIMEOUT_MS (line 96) | const DEFAULT_AGENT_TOOL_TIMEOUT_MS = 45000;
type ResolvedModelConfiguration (line 98) | type ResolvedModelConfiguration = {
function resolveModelConfiguration (line 103) | function resolveModelConfiguration(
class V3 (line 145) | class V3 {
method browserbaseSessionID (line 169) | public get browserbaseSessionID(): string | undefined {
method browserbaseSessionURL (line 172) | public get browserbaseSessionURL(): string | undefined {
method browserbaseDebugURL (line 175) | public get browserbaseDebugURL(): string | undefined {
method isBrowserbase (line 181) | public get isBrowserbase(): boolean {
method isCaptchaAutoSolveEnabled (line 189) | public get isCaptchaAutoSolveEnabled(): boolean {
method isAdvancedStealth (line 200) | public get isAdvancedStealth(): boolean {
method configuredViewport (line 211) | public get configuredViewport(): { width: number; height: number } {
method constructor (line 288) | constructor(opts: V3Options) {
method metrics (line 419) | public get metrics(): Promise<StagehandMetrics> {
method resolveLlmClient (line 436) | private resolveLlmClient(model?: ModelConfiguration): LLMClient {
method beginAgentReplayRecording (line 495) | private beginAgentReplayRecording(): void {
method endAgentReplayRecording (line 499) | private endAgentReplayRecording(): AgentReplayStep[] {
method discardAgentReplayRecording (line 503) | private discardAgentReplayRecording(): void {
method isAgentReplayRecording (line 507) | private isAgentReplayRecording(): boolean {
method isAgentReplayActive (line 511) | public isAgentReplayActive(): boolean {
method recordAgentReplayStep (line 515) | public recordAgentReplayStep(step: AgentReplayStep): void {
method history (line 523) | public get history(): Promise<ReadonlyArray<HistoryEntry>> {
method addToHistory (line 527) | public addToHistory(
method updateMetrics (line 540) | public updateMetrics(
method updateTotalMetrics (line 590) | private updateTotalMetrics(
method _immediateShutdown (line 604) | private async _immediateShutdown(reason: string): Promise<void> {
method startShutdownSupervisor (line 628) | private startShutdownSupervisor(
method stopShutdownSupervisor (line 656) | private stopShutdownSupervisor(): void {
method init (line 670) | async init(): Promise<void> {
method _applyPostConnectLocalOptions (line 1051) | private async _applyPostConnectLocalOptions(
method _ensureBrowserbaseDownloadsEnabled (line 1071) | private async _ensureBrowserbaseDownloadsEnabled(): Promise<void> {
method resetBrowserbaseSessionMetadata (line 1085) | private resetBrowserbaseSessionMetadata(): void {
method act (line 1104) | async act(input: string | Action, options?: ActOptions): Promise<ActRe...
method extract (line 1260) | async extract(
method observe (line 1356) | async observe(
method connectURL (line 1412) | connectURL(): string {
method context (line 1420) | public get context(): V3Context {
method close (line 1425) | async close(opts?: { force?: boolean }): Promise<void> {
method browserbaseApiKey (line 1514) | public get browserbaseApiKey(): string | undefined {
method requireBrowserbaseCreds (line 1519) | private requireBrowserbaseCreds(): {
method logger (line 1553) | public get logger(): (logLine: LogLine) => void {
method resolveTopFrameId (line 1567) | private async resolveTopFrameId(
method isPlaywrightPage (line 1599) | private isPlaywrightPage(p: unknown): p is PlaywrightPage {
method isPatchrightPage (line 1607) | private isPatchrightPage(p: unknown): p is PatchrightPage {
method isPuppeteerPage (line 1615) | private isPuppeteerPage(p: unknown): p is PuppeteerPage {
method resolvePage (line 1624) | private async resolvePage(page?: AnyPage): Promise<Page> {
method normalizeToV3Page (line 1635) | private async normalizeToV3Page(input: AnyPage): Promise<Page> {
method _logBrowserbaseSessionStatus (line 1669) | private async _logBrowserbaseSessionStatus(): Promise<void> {
method prepareAgentExecution (line 1700) | private async prepareAgentExecution(
method agent (line 1814) | agent(options?: AgentConfig): {
function isObserveResult (line 2155) | function isObserveResult(v: unknown): v is Action {
FILE: packages/core/lib/v3/zodCompat.ts
type StagehandZodSchema (line 9) | type StagehandZodSchema = Zod4TypeAny | z3.ZodTypeAny;
type StagehandZodObject (line 11) | type StagehandZodObject =
type InferStagehandSchema (line 15) | type InferStagehandSchema<T extends StagehandZodSchema> =
type JsonSchemaDocument (line 31) | type JsonSchemaDocument = Record<string, unknown>;
function toJsonSchema (line 33) | function toJsonSchema(schema: StagehandZodSchema): JsonSchemaDocument {
FILE: packages/core/lib/v3Evaluator.ts
class V3Evaluator (line 28) | class V3Evaluator {
method constructor (line 34) | constructor(
method getClient (line 49) | private getClient(): LLMClient {
method ask (line 55) | async ask(options: EvaluateOptions): Promise<EvaluationResult> {
method batchAsk (line 144) | async batchAsk(options: BatchAskOptions): Promise<EvaluationResult[]> {
method _evaluateWithMultipleScreenshots (line 224) | private async _evaluateWithMultipleScreenshots(options: {
FILE: packages/core/scripts/gen-version.ts
type PackageJson (line 4) | type PackageJson = { version: string };
FILE: packages/core/scripts/normalize-v8-coverage.ts
type CoverageRange (line 19) | type CoverageRange = {
type CoverageEntry (line 25) | type CoverageEntry = {
type CoverageFile (line 32) | type CoverageFile = {
type SourceMapPayload (line 49) | type SourceMapPayload = RawSourceMap | RawIndexMap;
type NormalizerOptions (line 113) | type NormalizerOptions = {
type SourceContext (line 118) | type SourceContext = {
type MappedPosition (line 124) | type MappedPosition = {
type OffsetMapping (line 130) | type OffsetMapping = {
FILE: packages/core/tests/cache-variables.test.ts
function createFakeStorage (line 10) | function createFakeStorage<T>(entry: T): CacheStorage {
FILE: packages/core/tests/integration/agent-cache-self-heal.spec.ts
function locateAgentCacheFile (line 77) | async function locateAgentCacheFile(cacheDir: string): Promise<string> {
function readCacheEntry (line 90) | async function readCacheEntry(cachePath: string): Promise<CachedAgentEnt...
type StepWithActions (line 95) | type StepWithActions = AgentReplayActStep | AgentReplayFillFormStep;
function findFirstActionStep (line 97) | function findFirstActionStep(
FILE: packages/core/tests/integration/connect-to-existing-browser.spec.ts
constant PAGE_TARGET_COUNT (line 6) | const PAGE_TARGET_COUNT = 5;
FILE: packages/core/tests/integration/context-addInitScript.spec.ts
constant POPUP_TIMEOUT_MS (line 7) | const POPUP_TIMEOUT_MS = 20_000;
function setPayload (line 118) | function setPayload() {
function setPayload (line 149) | function setPayload(): void {
function setPayload (line 179) | function setPayload(): void {
FILE: packages/core/tests/integration/context-extra-http-headers.spec.ts
constant TEST_URL (line 7) | const TEST_URL =
FILE: packages/core/tests/integration/cookies.spec.ts
constant BASE_URL (line 6) | const BASE_URL =
FILE: packages/core/tests/integration/flowLogger.spec.ts
function encodeHtml (line 16) | function encodeHtml(html: string): string {
function createRecordedFlowLoggerV3 (line 20) | function createRecordedFlowLoggerV3(
function listRecordedFlowEvents (line 35) | async function listRecordedFlowEvents(v3: V3): Promise<FlowEvent[]> {
function captureFlowEventBaseline (line 39) | async function captureFlowEventBaseline(v3: V3): Promise<Set<string>> {
function listRecordedFlowEventsSince (line 44) | async function listRecordedFlowEventsSince(
function eventsOfType (line 52) | function eventsOfType(events: FlowEvent[], eventType: string): FlowEvent...
function requireSingleEvent (line 56) | function requireSingleEvent(events: FlowEvent[], eventType: string): Flo...
function expectRootEvent (line 62) | function expectRootEvent(event: FlowEvent): void {
function expectDirectParent (line 66) | function expectDirectParent(child: FlowEvent, parent: FlowEvent): void {
function assertAllParentIdsResolve (line 73) | function assertAllParentIdsResolve(events: FlowEvent[]): void {
function assertSessionIds (line 86) | function assertSessionIds(events: FlowEvent[], sessionId: string): void {
function directChildrenOfType (line 92) | function directChildrenOfType(
function assertCompletedEnvelope (line 106) | function assertCompletedEnvelope(
function assertNoFloatingLlmEvents (line 117) | function assertNoFloatingLlmEvents(events: FlowEvent[]): void {
function assertNoFloatingCdpEvents (line 142) | function assertNoFloatingCdpEvents(events: FlowEvent[]): void {
function assertDirectRootCdpEvents (line 168) | function assertDirectRootCdpEvents(
function sortCountRecord (line 184) | function sortCountRecord(
function assertNonCdpEventCounts (line 192) | function assertNonCdpEventCounts(
FILE: packages/core/tests/integration/iframe-ctx-addInitScript-race.spec.ts
constant DEFAULT_INIT_SCRIPT_DELAY_MS (line 7) | const DEFAULT_INIT_SCRIPT_DELAY_MS = 250;
constant INIT_SCRIPT_DELAY_MS (line 8) | const INIT_SCRIPT_DELAY_MS = (() => {
constant POPUP_TIMEOUT_MS (line 17) | const POPUP_TIMEOUT_MS = 20_000;
constant RACE_INIT_SCRIPT_SENTINEL (line 18) | const RACE_INIT_SCRIPT_SENTINEL = "__stagehand_init_script_race_sentinel...
constant INIT_SCRIPT_MARKER_KEY (line 19) | const INIT_SCRIPT_MARKER_KEY = "__stagehand_init_script_loaded__";
constant POPUP_URL (line 20) | const POPUP_URL = "https://example.com/";
constant POPUP_IFRAME_URL (line 21) | const POPUP_IFRAME_URL = "https://example.org/";
constant INIT_SCRIPT_SOURCE (line 23) | const INIT_SCRIPT_SOURCE = `
type PatchedConn (line 30) | type PatchedConn = {
type SessionCommandRecord (line 38) | type SessionCommandRecord = {
type PopupTriggerCase (line 45) | type PopupTriggerCase = {
function closeAllPages (line 50) | async function closeAllPages(ctx: V3Context): Promise<void> {
function waitForPopupPage (line 55) | async function waitForPopupPage(
function waitForChildFrame (line 79) | async function waitForChildFrame(
function prepareTargetBlankPopupOpener (line 103) | async function prepareTargetBlankPopupOpener(opener: Page): Promise<void> {
function prepareWindowOpenPopupOpener (line 115) | async function prepareWindowOpenPopupOpener(opener: Page): Promise<void> {
constant POPUP_TRIGGER_CASES (line 128) | const POPUP_TRIGGER_CASES: PopupTriggerCase[] = [
FILE: packages/core/tests/integration/iframe-ctx-addInitScript.spec.ts
constant MIN_TIMEOUT_MS (line 10) | const MIN_TIMEOUT_MS = 3_000;
constant MAX_TIMEOUT_MS (line 11) | const MAX_TIMEOUT_MS = 120_000;
constant CHILD_FRAME_TIMEOUT_MS (line 22) | const CHILD_FRAME_TIMEOUT_MS = parseBoundedTimeoutMs(
constant POPUP_TIMEOUT_MS (line 26) | const POPUP_TIMEOUT_MS = parseBoundedTimeoutMs(
constant POPUP_URL_TIMEOUT_MS (line 30) | const POPUP_URL_TIMEOUT_MS = parseBoundedTimeoutMs(
constant DEBUG_INTERVAL_MS (line 34) | const DEBUG_INTERVAL_MS = 5_000;
constant TEST_VIEWPORT (line 36) | const TEST_VIEWPORT = { width: 1288, height: 711 };
type FrameTreeNode (line 38) | type FrameTreeNode = {
type ChildFrame (line 42) | type ChildFrame = ReturnType<Page["frames"]>[number];
type ChildFrameProbe (line 43) | type ChildFrameProbe = {
function debugLog (line 70) | function debugLog(
function collectFrameSnapshot (line 90) | async function collectFrameSnapshot(
function logPageDiagnostics (line 125) | async function logPageDiagnostics(
function closeAllPages (line 178) | async function closeAllPages(ctx: V3Context): Promise<void> {
function waitForChildFrame (line 187) | async function waitForChildFrame(
function waitForPageUrl (line 290) | async function waitForPageUrl(
function preparePopupForFrameAttach (line 325) | async function preparePopupForFrameAttach(
function ensurePopupViewport (line 357) | async function ensurePopupViewport(page: Page): Promise<void> {
function waitForPopupPage (line 362) | async function waitForPopupPage(
FILE: packages/core/tests/integration/keep-alive.child.ts
function main (line 3) | async function main(): Promise<void> {
FILE: packages/core/tests/integration/keep-alive.spec.ts
type EnvKind (line 9) | type EnvKind = "LOCAL" | "BROWSERBASE";
type ScenarioKind (line 10) | type ScenarioKind = "unhandled" | "close" | "sigterm" | "sigint";
type KeepAliveCase (line 12) | type KeepAliveCase = {
type ScenarioConfig (line 22) | type ScenarioConfig = {
type ChildInfo (line 33) | type ChildInfo = {
type ChildLogs (line 38) | type ChildLogs = {
type CheckResult (line 43) | type CheckResult = {
type Outcome (line 48) | type Outcome = {
constant DEBUG (line 68) | const DEBUG = process.env.KEEP_ALIVE_DEBUG === "1";
constant VIEW_MS (line 69) | const VIEW_MS = Number(process.env.KEEP_ALIVE_VIEW_MS ?? "0");
constant LOCAL_TIMEOUT_MS (line 70) | const LOCAL_TIMEOUT_MS = Number(
constant BB_TIMEOUT_MS (line 73) | const BB_TIMEOUT_MS = Number(process.env.KEEP_ALIVE_BB_TIMEOUT_MS ?? "30...
constant STAY_OPEN_MS (line 74) | const STAY_OPEN_MS = Number(process.env.KEEP_ALIVE_STAY_OPEN_MS ?? "6000");
constant ACTION_EXIT_TIMEOUT_MS (line 75) | const ACTION_EXIT_TIMEOUT_MS = Number(
constant LOCAL_INFO_TIMEOUT_MS (line 78) | const LOCAL_INFO_TIMEOUT_MS = Number(
constant BB_INFO_TIMEOUT_MS (line 81) | const BB_INFO_TIMEOUT_MS = Number(
function debugLog (line 89) | function debugLog(message: string): void {
function parseChildInfo (line 95) | function parseChildInfo(line: string): ChildInfo | null {
function runScenario (line 105) | async function runScenario(config: ScenarioConfig): Promise<{
function stopChild (line 216) | async function stopChild(child: ReturnType<typeof spawn>): Promise<void> {
function waitForChildExit (line 232) | async function waitForChildExit(
function checkLocalAlive (line 246) | async function checkLocalAlive(connectURL: string): Promise<CheckResult> {
function closeLocalBrowser (line 280) | async function closeLocalBrowser(connectURL: string): Promise<void> {
function checkBrowserbaseAlive (line 301) | async function checkBrowserbaseAlive(
function endBrowserbaseSession (line 326) | async function endBrowserbaseSession(
function assertStaysOpen (line 343) | async function assertStaysOpen(
function waitForClosed (line 366) | async function waitForClosed(
function assertBrowserState (line 385) | async function assertBrowserState(
function dumpLogs (line 454) | function dumpLogs(logs: ChildLogs): void {
function logCaseResult (line 469) | function logCaseResult(
function getKeepAliveEnvConfig (line 500) | function getKeepAliveEnvConfig(): {
function buildKeepAliveCases (line 519) | function buildKeepAliveCases(testEnv: EnvKind): KeepAliveCase[] {
function runKeepAliveCase (line 577) | async function runKeepAliveCase(
FILE: packages/core/tests/integration/keyboard.spec.ts
function dataUrl (line 6) | function dataUrl(html: string): string {
FILE: packages/core/tests/integration/locator-fill.spec.ts
method get (line 62) | get() {
method get (line 103) | get() {
FILE: packages/core/tests/integration/page-addInitScript.spec.ts
constant EXAMPLE_URL (line 6) | const EXAMPLE_URL = "https://example.com";
function setPayload (line 84) | function setPayload() {
FILE: packages/core/tests/integration/page-extra-http-headers.spec.ts
constant TEST_URL (line 7) | const TEST_URL =
FILE: packages/core/tests/integration/setinputfiles.spec.ts
constant FILE_UPLOAD_IFRAME_URL (line 10) | const FILE_UPLOAD_IFRAME_URL =
constant FILE_UPLOAD_V2_URL (line 12) | const FILE_UPLOAD_V2_URL =
constant RESUME_INPUT (line 15) | const RESUME_INPUT = "#resumeUpload";
constant RESUME_SUCCESS (line 16) | const RESUME_SUCCESS = "#resumeSuccess";
constant IMAGES_INPUT (line 17) | const IMAGES_INPUT = "#imagesUpload";
constant IMAGES_SUCCESS (line 18) | const IMAGES_SUCCESS = "#imagesSuccess";
constant AUDIO_INPUT (line 19) | const AUDIO_INPUT = "#audioUpload";
constant AUDIO_SUCCESS (line 20) | const AUDIO_SUCCESS = "#audioSuccess";
constant IFRAME_UPLOAD_INPUT (line 21) | const IFRAME_UPLOAD_INPUT = "/html/body/div/iframe/html/body/div/div[1]/...
constant IFRAME_SUCCESS (line 22) | const IFRAME_SUCCESS =
FILE: packages/core/tests/integration/shadow-iframe-oopif.spec.ts
type Case (line 17) | type Case = {
type Framework (line 24) | type Framework = "v3" | "puppeteer" | "playwright" | "patchright";
function runCase (line 26) | async function runCase(v3: V3, c: Case, framework: Framework): Promise<v...
FILE: packages/core/tests/integration/shadow-iframe-spif.spec.ts
type Case (line 17) | type Case = {
type Framework (line 24) | type Framework = "v3" | "puppeteer" | "playwright" | "patchright";
function runCase (line 26) | async function runCase(v3: V3, c: Case, framework: Framework): Promise<v...
FILE: packages/core/tests/integration/testUtils.ts
function raceTimeout (line 15) | function raceTimeout<T>(
constant CLOSE_TIMEOUT_MS (line 26) | const CLOSE_TIMEOUT_MS = 5_000;
function settleWithTimeout (line 28) | async function settleWithTimeout(
function closeV3 (line 43) | async function closeV3(v3?: V3 | null): Promise<void> {
type JsonResponseKey (line 60) | type JsonResponseKey =
type JsonResponseValue (line 67) | type JsonResponseValue =
type JsonResponseScript (line 71) | type JsonResponseScript = JsonResponseValue | JsonResponseValue[];
type GenerateResponseValue (line 73) | type GenerateResponseValue =
type ScriptedLanguageModel (line 85) | type ScriptedLanguageModel = LanguageModelV2 & {
type ScriptedGenerateResult (line 89) | type ScriptedGenerateResult = {
constant DEFAULT_USAGE (line 95) | const DEFAULT_USAGE: LanguageModelV2Usage = {
function consumeScriptValue (line 110) | function consumeScriptValue<T>(value: T | T[] | undefined, fallback: T):...
function resolveJsonResponseKey (line 122) | function resolveJsonResponseKey(
function promptToText (line 151) | function promptToText(
function findEncodedIds (line 167) | function findEncodedIds(options: LanguageModelV2CallOptions): string[] {
function findEncodedIdForText (line 173) | function findEncodedIdForText(
function findLastEncodedId (line 189) | function findLastEncodedId(options: LanguageModelV2CallOptions): string {
function toolCallResponse (line 198) | function toolCallResponse(
function doneToolResponse (line 221) | function doneToolResponse(
function createGenerateResult (line 233) | function createGenerateResult(result: ScriptedGenerateResult): {
function createScriptedAisdkTestLlmClient (line 247) | function createScriptedAisdkTestLlmClient(options?: {
FILE: packages/core/tests/integration/timeouts.spec.ts
type AgentToolNameWithTimeout (line 9) | type AgentToolNameWithTimeout =
type ToolTimeoutTestModel (line 25) | type ToolTimeoutTestModel = {
type ToolTimeoutTestLLMClient (line 44) | type ToolTimeoutTestLLMClient = LLMClient & {
function createToolTimeoutTestLlmClient (line 48) | function createToolTimeoutTestLlmClient(
function findToolOutput (line 144) | function findToolOutput(
function runAgentToolTimeoutScenario (line 163) | async function runAgentToolTimeoutScenario(
FILE: packages/core/tests/integration/v3.config.ts
function getV3TestConfig (line 9) | function getV3TestConfig(overrides: Partial<V3Options> = {}): V3Options {
FILE: packages/core/tests/integration/v3.dynamic.config.ts
function getV3DynamicTestConfig (line 51) | function getV3DynamicTestConfig(
FILE: packages/core/tests/unit/agent-captcha-hooks.test.ts
constant SOLVING_STARTED (line 6) | const SOLVING_STARTED = "browserbase-solving-started";
constant SOLVING_FINISHED (line 7) | const SOLVING_FINISHED = "browserbase-solving-finished";
constant SOLVING_ERRORED (line 8) | const SOLVING_ERRORED = "browserbase-solving-errored";
type ConsoleListener (line 10) | type ConsoleListener = (message: { text: () => string }) => void;
class MockPage (line 12) | class MockPage {
method on (line 21) | on(event: string, listener: ConsoleListener): void {
method off (line 27) | off(event: string, listener: ConsoleListener): void {
method emitConsole (line 33) | emitConsole(text: string): void {
method url (line 40) | url(): string {
method screenshot (line 44) | async screenshot(): Promise<Buffer> {
method evaluate (line 48) | async evaluate<T>(): Promise<T> {
method mainFrame (line 52) | mainFrame(): { evaluate: () => Promise<{ w: number; h: number }> } {
class FakeCuaClient (line 59) | class FakeCuaClient {
method setActionHandler (line 78) | setActionHandler(
method setPreStepHook (line 84) | setPreStepHook(handler: () => Promise<void>): void {
method addContextNote (line 88) | addContextNote(note: string): void {
method execute (line 92) | async execute(options: unknown): Promise<{
method constructor (line 106) | constructor(logger: unknown) {
method getClient (line 110) | getClient(): FakeCuaClient {
function collectUserMessages (line 118) | function collectUserMessages(
FILE: packages/core/tests/unit/agent-execution-model.test.ts
function createMockV3 (line 11) | function createMockV3() {
function resolveExecutionModel (line 142) | function resolveExecutionModel(options?: {
FILE: packages/core/tests/unit/browserbase-session-accessors.test.ts
constant MOCK_SESSION_ID (line 4) | const MOCK_SESSION_ID = "session-123";
constant MOCK_SESSION_URL (line 5) | const MOCK_SESSION_URL = `https://www.browserbase.com/sessions/${MOCK_SE...
constant MOCK_DEBUG_URL (line 6) | const MOCK_DEBUG_URL = `https://debug.browserbase.com/${MOCK_SESSION_ID}`;
class MockConnection (line 9) | class MockConnection {
class MockV3Context (line 15) | class MockV3Context {
method create (line 16) | static async create(): Promise<MockV3Context> {
method pages (line 22) | pages(): never[] {
method close (line 26) | async close(): Promise<void> {
FILE: packages/core/tests/unit/cache-llm-resolution.test.ts
function createFakeStorage (line 22) | function createFakeStorage<T>(entry: T): CacheStorage {
FILE: packages/core/tests/unit/captcha-solver.test.ts
constant SOLVING_STARTED (line 4) | const SOLVING_STARTED = "browserbase-solving-started";
constant SOLVING_FINISHED (line 5) | const SOLVING_FINISHED = "browserbase-solving-finished";
constant SOLVING_ERRORED (line 6) | const SOLVING_ERRORED = "browserbase-solving-errored";
type ConsoleListener (line 8) | type ConsoleListener = (message: { text: () => string }) => void;
class MockPage (line 10) | class MockPage {
method on (line 15) | on(event: string, listener: ConsoleListener): void {
method off (line 21) | off(event: string, listener: ConsoleListener): void {
method emitConsole (line 27) | emitConsole(text: string): void {
method listenerCount (line 34) | listenerCount(): number {
FILE: packages/core/tests/unit/cdp-connection-close.test.ts
function raceTimeout (line 10) | function raceTimeout<T>(
function createPair (line 25) | async function createPair(): Promise<{
FILE: packages/core/tests/unit/context-extra-http-headers.test.ts
type ContextStub (line 6) | type ContextStub = {
FILE: packages/core/tests/unit/cookies.test.ts
function makeCookie (line 11) | function makeCookie(overrides: Partial<Cookie> = {}): Cookie {
function toCdpCookie (line 26) | function toCdpCookie(c: Cookie) {
function makeContext (line 588) | function makeContext(
function getMockConn (line 602) | function getMockConn(ctx: V3Context): MockCDPSession {
FILE: packages/core/tests/unit/flowlogger-capturing-cdp.test.ts
function attachEventStoreToBus (line 9) | function attachEventStoreToBus(
class FakeSocket (line 25) | class FakeSocket extends EventEmitter {
method send (line 29) | send(payload: string): void {
method close (line 33) | close(): void {
function createConnection (line 39) | function createConnection(socket: FakeSocket): CdpConnection {
function requireEvent (line 48) | function requireEvent(
FILE: packages/core/tests/unit/flowlogger-eventstore.test.ts
function attachEventStoreToBus (line 6) | function attachEventStoreToBus(
function createVerboseStoreHarness (line 22) | function createVerboseStoreHarness(): {
FILE: packages/core/tests/unit/helpers/mockCDPSession.ts
type Handler (line 3) | type Handler = (params?: Record<string, unknown>) => Promise<unknown> | ...
class MockCDPSession (line 5) | class MockCDPSession implements CDPSessionLike {
method constructor (line 12) | constructor(
method send (line 19) | async send<R = unknown>(
method on (line 29) | on(): void {}
method off (line 30) | off(): void {}
method close (line 31) | async close(): Promise<void> {}
method callsFor (line 33) | callsFor(method: string): Array<{ params?: Record<string, unknown> }> {
FILE: packages/core/tests/unit/openai-cua-client.test.ts
function createClient (line 4) | function createClient() {
type ExecuteStepResult (line 94) | type ExecuteStepResult = {
FILE: packages/core/tests/unit/page-extra-http-headers.test.ts
type PageStub (line 6) | type PageStub = {
FILE: packages/core/tests/unit/public-api/export-surface.test.ts
type StagehandExports (line 59) | type StagehandExports = typeof Stagehand & {
type PublicAPI (line 63) | type PublicAPI = {
FILE: packages/core/tests/unit/public-api/llm-and-agents.test.ts
type AISdkClientInstance (line 21) | type AISdkClientInstance = InstanceType<typeof Stagehand.AISdkClient>;
type CtorParams (line 33) | type CtorParams = ConstructorParameters<typeof Stagehand.AISdkClient>;
type AgentProviderInstance (line 63) | type AgentProviderInstance = InstanceType<typeof Stagehand.AgentProvider>;
type ExpectedAnnotatedScreenshotText (line 83) | type ExpectedAnnotatedScreenshotText = string;
type ExpectedShape (line 93) | type ExpectedShape = {
type ConsoleMessageInstance (line 108) | type ConsoleMessageInstance = InstanceType<typeof Stagehand.ConsoleMessa...
type AgentProviderInstance (line 116) | type AgentProviderInstance = InstanceType<typeof Stagehand.AgentProvider>;
type GetClientReturn (line 117) | type GetClientReturn = ReturnType<AgentProviderInstance["getClient"]>;
type ExpectedShape (line 120) | type ExpectedShape = {
type ExpectedShape (line 139) | type ExpectedShape = {
type ExpectedCtorParams (line 147) | type ExpectedCtorParams = [Stagehand.AvailableModel, string?];
type ExpectedBasicOptions (line 149) | type ExpectedBasicOptions = {
type ExpectedWithResponseModel (line 160) | type ExpectedWithResponseModel = ExpectedBasicOptions & {
type LLMClientInstance (line 169) | type LLMClientInstance = InstanceType<typeof Stagehand.LLMClient>;
type Result (line 219) | type Result = { custom: string };
type ExpectedSignature (line 220) | type ExpectedSignature = (
type ExpectedModelToAgentProviderMap (line 263) | type ExpectedModelToAgentProviderMap = Record<
type ExpectedShape (line 276) | type ExpectedShape = {
type ResponseInstance (line 298) | type ResponseInstance = InstanceType<typeof Stagehand.Response>;
FILE: packages/core/tests/unit/public-api/public-error-types.test.ts
type ErrorClassType (line 79) | type ErrorClassType = typeof ErrorClass;
FILE: packages/core/tests/unit/public-api/public-types.test.ts
type ExpectedExportedTypes (line 9) | type ExpectedExportedTypes = {
type ExpectedAnyPage (line 111) | type ExpectedAnyPage =
type ExpectedActOptions (line 123) | type ExpectedActOptions = {
type ExpectedActResult (line 137) | type ExpectedActResult = {
type ExpectedExtractOptions (line 151) | type ExpectedExtractOptions = {
type ExpectedObserveOptions (line 165) | type ExpectedObserveOptions = {
type ExpectedAction (line 188) | type ExpectedAction = {
type TestAction (line 204) | type TestAction = { type: string } & Stagehand.AgentAction;
type ExpectedAgentExecuteOptions (line 210) | type ExpectedAgentExecuteOptions = {
type ExpectedAgentStreamExecuteOptions (line 231) | type ExpectedAgentStreamExecuteOptions = {
type ExpectedAgentExecutionOptions (line 252) | type ExpectedAgentExecutionOptions<T = Stagehand.AgentExecuteOptions> = {
type ExpectedAgentResult (line 268) | type ExpectedAgentResult = {
type ExpectedAgentConfig (line 291) | type ExpectedAgentConfig = {
type ExpectedAgentToolMode (line 308) | type ExpectedAgentToolMode = "dom" | "hybrid" | "cua";
type ExpectedHistoryEntry (line 316) | type ExpectedHistoryEntry = {
type ExpectedCookie (line 329) | type ExpectedCookie = {
type ExpectedCookieParam (line 346) | type ExpectedCookieParam = {
type ExpectedClearCookieOptions (line 364) | type ExpectedClearCookieOptions = {
FILE: packages/core/tests/unit/public-api/runtime-utils.test.ts
type ExpectedInjectUrlsParams (line 6) | type ExpectedInjectUrlsParams = [
type ExpectedIsRunningInBunParams (line 20) | type ExpectedIsRunningInBunParams = [];
type ExpectedLoadApiKeyFromEnvParams (line 30) | type ExpectedLoadApiKeyFromEnvParams = [
type ExpectedProviderEnvVarMap (line 43) | type ExpectedProviderEnvVarMap = Partial<
FILE: packages/core/tests/unit/public-api/schema-utils.test.ts
type ExpectedInferredType (line 6) | type ExpectedInferredType = { extraction: string };
type ExpectedGetZodTypeParams (line 16) | type ExpectedGetZodTypeParams = [Stagehand.StagehandZodSchema];
type ExpectedIsZod3SchemaParams (line 26) | type ExpectedIsZod3SchemaParams = [Stagehand.StagehandZodSchema];
type ExpectedIsZod4SchemaParams (line 36) | type ExpectedIsZod4SchemaParams = [Stagehand.StagehandZodSchema];
type ExpectedJsonSchemaToZodParams (line 46) | type ExpectedJsonSchemaToZodParams = [Stagehand.JsonSchema];
type ExpectedInferredType (line 56) | type ExpectedInferredType = { pageText: string };
type ExpectedToGeminiSchemaParams (line 66) | type ExpectedToGeminiSchemaParams = [Stagehand.StagehandZodSchema];
type ExpectedToJsonSchemaParams (line 76) | type ExpectedToJsonSchemaParams = [Stagehand.StagehandZodSchema];
type ExpectedTransformSchemaParams (line 86) | type ExpectedTransformSchemaParams = [
type ExpectedTrimTrailingTextNodeParams (line 99) | type ExpectedTrimTrailingTextNodeParams = [string | undefined];
type ExpectedValidateZodSchemaParams (line 109) | type ExpectedValidateZodSchemaParams = [
FILE: packages/core/tests/unit/public-api/v3-core.test.ts
type ExpectedShape (line 6) | type ExpectedShape = {
type StagehandInstance (line 36) | type StagehandInstance = InstanceType<typeof Stagehand.Stagehand>;
type AgentReturn (line 67) | type AgentReturn = ReturnType<StagehandInstance["agent"]>;
type ExpectedStagehandMetrics (line 77) | type ExpectedStagehandMetrics = {
type V3EvaluatorInstance (line 119) | type V3EvaluatorInstance = InstanceType<typeof Stagehand.V3Evaluator>;
type ExpectedServerConfig (line 155) | type ExpectedServerConfig =
type ExpectedLOG_LEVEL_NAMES (line 173) | type ExpectedLOG_LEVEL_NAMES = Record<Stagehand.LogLevel, string>;
FILE: packages/core/tests/unit/safety-confirmation.test.ts
type LoggerMock (line 10) | type LoggerMock = (message: LogLine) => void;
function createOpenAIClient (line 32) | function createOpenAIClient(): OpenAICUAClient {
function createGoogleClient (line 41) | function createGoogleClient(): GoogleCUAClient {
FILE: packages/core/tests/unit/snapshot-capture-orchestration.test.ts
type PageStub (line 32) | type PageStub = Pick<
method send (line 141) | async send<R = unknown>(
method on (line 149) | on() {}
method off (line 150) | off() {}
method close (line 151) | async close() {}
FILE: packages/core/tests/unit/snapshot-cbor.test.ts
type Handler (line 10) | type Handler = (params?: Record<string, unknown>) => Promise<unknown> | ...
function createFakePage (line 12) | function createFakePage(session: CDPSessionLike): Page {
function completeDomTree (line 37) | function completeDomTree(): Protocol.DOM.Node {
function truncatedDomTree (line 75) | function truncatedDomTree(): Protocol.DOM.Node {
function htmlWithChildren (line 95) | function htmlWithChildren(): Protocol.DOM.Node {
function simpleAxNodes (line 124) | function simpleAxNodes(): Protocol.Accessibility.AXNode[] {
function makeCborError (line 153) | function makeCborError(): Error {
FILE: packages/core/tests/unit/timeout-handlers.test.ts
type BuildActHandlerOptions (line 1015) | interface BuildActHandlerOptions {
function buildActHandler (line 1027) | function buildActHandler(options: BuildActHandlerOptions = {}): ActHandl...
type BuildExtractHandlerOptions (line 1049) | interface BuildExtractHandlerOptions {
function buildExtractHandler (line 1060) | function buildExtractHandler(
type BuildObserveHandlerOptions (line 1083) | interface BuildObserveHandlerOptions {
function buildObserveHandler (line 1094) | function buildObserveHandler(
FILE: packages/core/tests/unit/understudy-command-exception.test.ts
function deepFunction (line 50) | function deepFunction() {
FILE: packages/core/tests/unit/xpath-resolver.test.ts
type DomGlobals (line 8) | type DomGlobals = {
FILE: packages/docs/language-selector.js
function updateSDKReferenceVisibility (line 73) | function updateSDKReferenceVisibility() {
function getVersionSwitcher (line 102) | function getVersionSwitcher() {
function updateVersionSwitcherVisibility (line 115) | function updateVersionSwitcherVisibility() {
function getDropdownButton (line 135) | function getDropdownButton() {
function getDropdownMenu (line 146) | function getDropdownMenu() {
function updateButtonText (line 150) | function updateButtonText(newText) {
function updateDropdownCheckIndicator (line 160) | function updateDropdownCheckIndicator() {
function simulateClick (line 206) | function simulateClick(element) {
function getCodeBlockLanguageDropdown (line 222) | function getCodeBlockLanguageDropdown() {
function waitForCodeBlockMenuAndSelect (line 237) | function waitForCodeBlockMenuAndSelect(targetLanguage, attempts = 0) {
function selectCodeBlockLanguage (line 267) | function selectCodeBlockLanguage(targetLanguage) {
function syncCodeBlockLanguage (line 280) | function syncCodeBlockLanguage() {
function setupDropdownMenuObserver (line 291) | function setupDropdownMenuObserver() {
function setupMenuClickHandler (line 306) | function setupMenuClickHandler() {
function restoreLanguageSelection (line 359) | function restoreLanguageSelection() {
function setupPageChangeObserver (line 380) | function setupPageChangeObserver() {
function setupCodeBlockObserver (line 420) | function setupCodeBlockObserver() {
function init (line 446) | function init() {
FILE: packages/docs/scripts/runtimePaths.js
constant PACKAGE_SEGMENT (line 12) | const PACKAGE_SEGMENT = "/packages/docs/";
constant EVAL_FRAMES (line 13) | const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]);
constant INTERNAL_FRAME_NAMES (line 14) | const INTERNAL_FRAME_NAMES = new Set([
FILE: packages/docs/scripts/sync-sdk-docs.js
constant SDK_REPOS (line 20) | const SDK_REPOS = {
function fetchUrl (line 50) | function fetchUrl(url) {
function processReadmeContent (line 79) | function processReadmeContent(content, config) {
function generateFrontmatter (line 140) | function generateFrontmatter(config) {
function syncSdk (line 156) | async function syncSdk(language, config) {
function main (line 188) | async function main() {
FILE: packages/evals/args.ts
constant HELP_REGEX (line 6) | const HELP_REGEX = /^(?:--?)?(?:h|help)$/i;
constant MAN_REGEX (line 7) | const MAN_REGEX = /^(?:--?)?man$/i;
constant DEFAULT_EVAL_CATEGORIES (line 82) | const DEFAULT_EVAL_CATEGORIES = process.env.EVAL_CATEGORIES
function buildUsage (line 100) | function buildUsage(detailed = false): string {
FILE: packages/evals/browserbaseCleanup.ts
constant CLOSE_TIMEOUT_MS (line 3) | const CLOSE_TIMEOUT_MS = 5_000;
function settleWithTimeout (line 5) | async function settleWithTimeout(
function endBrowserbaseSession (line 20) | async function endBrowserbaseSession(v3?: V3 | null): Promise<void> {
FILE: packages/evals/cli.ts
constant CONFIG_PATH (line 9) | const CONFIG_PATH = path.join(moduleDir, "evals.config.json");
type Config (line 11) | interface Config {
function loadConfig (line 31) | function loadConfig(): Config {
function saveConfig (line 35) | function saveConfig(config: Config): void {
function printHelp (line 39) | function printHelp(): void {
function handleConfig (line 108) | function handleConfig(args: string[]): void {
function handleList (line 210) | function handleList(args: string[]): void {
function parseArgs (line 263) | function parseArgs(rawArgs: string[]): {
function handleRun (line 324) | function handleRun(args: string[]): void {
function main (line 543) | function main(): void {
FILE: packages/evals/index.eval.ts
constant MAX_CONCURRENCY (line 64) | const MAX_CONCURRENCY = process.env.EVAL_MAX_CONCURRENCY
constant TRIAL_COUNT (line 68) | const TRIAL_COUNT = process.env.EVAL_TRIAL_COUNT
constant USE_API (line 72) | const USE_API: boolean = (process.env.USE_API ?? "").toLowerCase() === "...
FILE: packages/evals/initV3.ts
type InitV3Args (line 26) | type InitV3Args = {
type V3InitResult (line 47) | type V3InitResult = {
function initV3 (line 56) | async function initV3({
FILE: packages/evals/lib/AISdkClientWrapped.ts
class AISdkClientWrapped (line 27) | class AISdkClientWrapped extends LLMClient {
method constructor (line 32) | constructor({
method getLanguageModel (line 44) | public getLanguageModel(): LanguageModelV2 {
method createChatCompletion (line 48) | async createChatCompletion<T = ChatCompletion>({
FILE: packages/evals/logger.ts
function parseLogLine (line 25) | function parseLogLine(logLine: LogLine): LogLineEval {
class EvalLogger (line 68) | class EvalLogger {
method constructor (line 72) | constructor() {
method init (line 81) | init(stagehand?: V3) {
method log (line 91) | log(logLine: LogLine) {
method error (line 101) | error(logLine: LogLine) {
method warn (line 111) | warn(logLine: LogLine) {
method getLogs (line 121) | getLogs(): LogLineEval[] {
method clear (line 130) | clear(): void {
FILE: packages/evals/runtimePaths.ts
constant PACKAGE_SEGMENT (line 13) | const PACKAGE_SEGMENT = "/packages/evals/";
constant EVAL_FRAMES (line 14) | const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]);
constant INTERNAL_FRAME_NAMES (line 15) | const INTERNAL_FRAME_NAMES = new Set([
type CallSiteWithScriptName (line 44) | type CallSiteWithScriptName = NodeJS.CallSite & {
FILE: packages/evals/scoring.ts
function formatTaskOutput (line 7) | function formatTaskOutput(output: unknown): string {
function exactMatch (line 48) | function exactMatch(
function errorMatch (line 83) | function errorMatch(
FILE: packages/evals/scripts/test-evals.ts
type Runtime (line 15) | type Runtime = "source" | "dist-esm";
type EvalSummaryEntry (line 17) | type EvalSummaryEntry = {
type EvalSummary (line 23) | type EvalSummary = {
FILE: packages/evals/suites/gaia.ts
type GaiaRow (line 29) | type GaiaRow = {
function isGaiaRow (line 37) | function isGaiaRow(parsed: unknown): parsed is GaiaRow {
FILE: packages/evals/suites/onlineMind2Web.ts
type Mind2WebRow (line 30) | type Mind2WebRow = {
function isMind2WebRow (line 39) | function isMind2WebRow(parsed: unknown): parsed is Mind2WebRow {
FILE: packages/evals/suites/webtailbench.ts
type WebTailBenchRow (line 24) | type WebTailBenchRow = {
function isWebTailBenchRow (line 32) | function isWebTailBenchRow(parsed: unknown): parsed is WebTailBenchRow {
FILE: packages/evals/suites/webvoyager.ts
type VoyagerRow (line 30) | type VoyagerRow = {
function isVoyagerRow (line 38) | function isVoyagerRow(parsed: unknown): parsed is VoyagerRow {
FILE: packages/evals/taskConfig.ts
constant ALL_EVAL_MODELS (line 20) | const ALL_EVAL_MODELS = [
type TaskConfig (line 73) | type TaskConfig = {
constant DEFAULT_EVAL_MODELS (line 101) | const DEFAULT_EVAL_MODELS = process.env.EVAL_MODELS
constant AGENT_MODELS (line 110) | const AGENT_MODELS = process.env.EVAL_AGENT_MODELS
constant AGENT_MODELS_CUA (line 115) | const AGENT_MODELS_CUA = process.env.EVAL_AGENT_MODELS_CUA
constant AGENT_MODEL_ENTRIES (line 123) | const AGENT_MODEL_ENTRIES: AgentModelEntry[] = [
constant DEFAULT_AGENT_MODELS (line 128) | const DEFAULT_AGENT_MODELS = AGENT_MODEL_ENTRIES.map((e) => e.modelName);
constant MODELS (line 180) | const MODELS: AvailableModel[] = getModelList().map((model) => {
FILE: packages/evals/tasks/extract_press_releases.ts
type PressRelease (line 22) | type PressRelease = z.infer<typeof schema>["items"][number];
FILE: packages/evals/types/evals.ts
type StagehandInitResult (line 9) | type StagehandInitResult = {
type EvalFunction (line 19) | type EvalFunction = (
type EvalCategory (line 43) | type EvalCategory = z.infer<typeof EvalCategorySchema>;
type EvalInput (line 44) | interface EvalInput {
type Testcase (line 52) | interface Testcase
type SummaryResult (line 84) | interface SummaryResult {
type EvalArgs (line 91) | interface EvalArgs<TInput, TOutput, TExpected> {
type EvalResult (line 98) | interface EvalResult {
type LogLineEval (line 103) | type LogLineEval = LogLine & {
type AgentModelEntry (line 107) | type AgentModelEntry = {
FILE: packages/evals/types/screenshotCollector.ts
type ScreenshotCollectorOptions (line 1) | interface ScreenshotCollectorOptions {
type ScreenshotCapablePage (line 12) | type ScreenshotCapablePage = {
FILE: packages/evals/utils.ts
function normalizeString (line 27) | function normalizeString(str: string): string {
function compareStrings (line 54) | function compareStrings(
function generateTimestamp (line 75) | function generateTimestamp(): string {
function generateExperimentName (line 89) | function generateExperimentName({
function logLineToString (line 108) | function logLineToString(logLine: LogLine): string {
function dedent (line 126) | function dedent(
function sampleUniform (line 148) | function sampleUniform<T>(arr: T[], k: number): T[] {
function readJsonlFile (line 161) | function readJsonlFile(filePath: string): string[] {
function parseJsonlRows (line 175) | function parseJsonlRows<T>(
function applySampling (line 193) | function applySampling<T>(
FILE: packages/evals/utils/ScreenshotCollector.ts
class ScreenshotCollector (line 5) | class ScreenshotCollector {
method constructor (line 17) | constructor(v3: V3, options: ScreenshotCollectorOptions = {}) {
method start (line 28) | start(): void {
method stop (line 51) | async stop(): Promise<Buffer[]> {
method captureScreenshot (line 79) | private async captureScreenshot(trigger: string): Promise<void> {
method getScreenshots (line 134) | getScreenshots(): Buffer[] {
method getScreenshotCount (line 138) | getScreenshotCount(): number {
method clear (line 142) | clear(): void {
method addScreenshot (line 150) | async addScreenshot(screenshot: Buffer): Promise<void> {
method calculateMSE (line 195) | private async calculateMSE(img1: Buffer, img2: Buffer): Promise<number> {
method calculateSSIM (line 217) | private async calculateSSIM(img1: Buffer, img2: Buffer): Promise<numbe...
FILE: packages/evals/utils/imageResize.ts
function imageResize (line 3) | async function imageResize(
FILE: packages/server-v3/scripts/gen-openapi.ts
constant OUTPUT_PATH (line 28) | const OUTPUT_PATH = path.resolve(getCurrentDirPath(), "../openapi.v3.yam...
function main (line 30) | async function main() {
FILE: packages/server-v3/scripts/runtimePaths.ts
constant PACKAGE_SEGMENT (line 12) | const PACKAGE_SEGMENT = "/packages/server-v3/";
constant EVAL_FRAMES (line 13) | const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]);
constant INTERNAL_FRAME_NAMES (line 14) | const INTERNAL_FRAME_NAMES = new Set([
type CallSiteWithScriptName (line 43) | type CallSiteWithScriptName = NodeJS.CallSite & {
FILE: packages/server-v3/src/lib/InMemorySessionStore.ts
constant DEFAULT_MAX_CAPACITY (line 12) | const DEFAULT_MAX_CAPACITY = 100;
constant DEFAULT_TTL_MS (line 13) | const DEFAULT_TTL_MS = 0;
type LruNode (line 18) | interface LruNode {
class InMemorySessionStore (line 41) | class InMemorySessionStore implements SessionStore {
method constructor (line 49) | constructor(config?: SessionCacheConfig) {
method startCleanupInterval (line 58) | private startCleanupInterval(): void {
method cleanupExpired (line 70) | private async cleanupExpired(): Promise<void> {
method bumpNode (line 88) | private bumpNode(node: LruNode): void {
method evictLru (line 115) | private async evictLru(): Promise<void> {
method startSession (line 122) | async startSession(params: CreateSessionParams): Promise<SessionStartR...
method endSession (line 136) | async endSession(sessionId: string): Promise<void> {
method hasSession (line 140) | async hasSession(sessionId: string): Promise<boolean> {
method getOrCreateStagehand (line 153) | async getOrCreateStagehand(
method buildV3Options (line 202) | private buildV3Options(
method createSession (line 247) | async createSession(
method deleteSession (line 280) | async deleteSession(sessionId: string): Promise<void> {
method getSessionConfig (line 307) | async getSessionConfig(sessionId: string): Promise<CreateSessionParams> {
method updateCacheConfig (line 318) | updateCacheConfig(config: SessionCacheConfig): void {
method getCacheConfig (line 341) | getCacheConfig(): SessionCacheConfig {
method destroy (line 348) | async destroy(): Promise<void> {
method size (line 363) | get size(): number {
FILE: packages/server-v3/src/lib/SessionStore.ts
type SessionStartResult (line 11) | type SessionStartResult = Api.SessionStartResult;
type CreateSessionParams (line 21) | interface CreateSessionParams {
type RequestContext (line 67) | interface RequestContext {
type SessionCacheConfig (line 77) | interface SessionCacheConfig {
type SessionStore (line 98) | interface SessionStore {
FILE: packages/server-v3/src/lib/errorHandler.ts
class AppError (line 10) | class AppError extends Error {
method constructor (line 14) | constructor(
method getClientMessage (line 31) | getClientMessage(): string {
function withErrorHandling (line 46) | function withErrorHandling<
FILE: packages/server-v3/src/lib/header.ts
function getModelName (line 46) | function getModelName(request: FastifyRequest): string | undefined {
function getModelApiKey (line 67) | function getModelApiKey(request: FastifyRequest): string | undefined {
function shouldRespondWithSSE (line 84) | function shouldRespondWithSSE(request: FastifyRequest): boolean {
FILE: packages/server-v3/src/lib/response.ts
type SuccessResponse (line 4) | interface SuccessResponse<T> {
type ErrorResponse (line 9) | interface ErrorResponse {
type ApiResponse (line 14) | type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
function success (line 16) | function success<T>(
function error (line 27) | function error(
function isSuccessResponse (line 38) | function isSuccessResponse<T>(
function isErrorResponse (line 44) | function isErrorResponse(
FILE: packages/server-v3/src/lib/sessionStoreManager.ts
function initializeSessionStore (line 6) | function initializeSessionStore(
function getSessionStore (line 15) | function getSessionStore(): SessionStore {
function destroySessionStore (line 22) | async function destroySessionStore(): Promise<void> {
FILE: packages/server-v3/src/lib/stream.ts
type StreamingResponseOptions (line 18) | interface StreamingResponseOptions<TV3> {
function createStreamingResponse (line 30) | async function createStreamingResponse<TV3>({
FILE: packages/server-v3/src/lib/utils.ts
type JSONSchema (line 8) | interface JSONSchema {
function jsonSchemaToZod (line 28) | function jsonSchemaToZod(schema: JSONSchema): ZodTypeAny {
function mapModelToProvider (line 184) | function mapModelToProvider(model: LegacyModel): LegacyProvider {
FILE: packages/server-v3/src/server.ts
constant READY_WAIT_PERIOD (line 36) | const READY_WAIT_PERIOD = 10_000;
constant GRACEFUL_SHUTDOWN_PERIOD (line 37) | const GRACEFUL_SHUTDOWN_PERIOD = 30_000;
method level (line 50) | level(label: string) {
FILE: packages/server-v3/src/types/error.ts
class UnknownModelError (line 5) | class UnknownModelError extends AppError {
method constructor (line 6) | constructor(model: string) {
class InvalidProviderError (line 10) | class InvalidProviderError extends AppError {
method constructor (line 11) | constructor(provider: string) {
class InvalidModelError (line 16) | class InvalidModelError extends AppError {
method constructor (line 17) | constructor(model: string) {
class UnauthorizedError (line 22) | class UnauthorizedError extends AppError {
method constructor (line 23) | constructor() {
class MissingHeaderError (line 28) | class MissingHeaderError extends AppError {
method constructor (line 29) | constructor(header: string) {
class InvalidAPIKeyError (line 34) | class InvalidAPIKeyError extends AppError {
method constructor (line 35) | constructor(provider: string) {
class AttemptedCloseOnNonActiveSessionError (line 40) | class AttemptedCloseOnNonActiveSessionError extends AppError {
method constructor (line 41) | constructor() {
type BrowserbaseError (line 49) | interface BrowserbaseError {
class BrowserbaseSDKError (line 61) | class BrowserbaseSDKError extends AppError {
method constructor (line 62) | constructor(error: unknown, defaultMessage: string) {
FILE: packages/server-v3/src/types/fastify.d.ts
type FastifyRequest (line 4) | interface FastifyRequest {
FILE: packages/server-v3/src/types/model.ts
constant AISDK_PROVIDERS (line 1) | const AISDK_PROVIDERS = [
type AISDKProvider (line 17) | type AISDKProvider = (typeof AISDK_PROVIDERS)[number];
type LegacyModel (line 19) | type LegacyModel =
type LegacyProvider (line 40) | type LegacyProvider = "openai" | "anthropic" | "google";
FILE: packages/server-v3/src/types/rrweb.ts
type Node (line 1) | interface Node {
type Event (line 10) | interface Event {
FILE: packages/server-v3/test/integration/api-server-cache.test.ts
function extractUrl (line 37) | function extractUrl() {
function extractBody (line 41) | function extractBody(instruction = "extract the page title") {
FILE: packages/server-v3/test/integration/utils.ts
constant HTTP_OK (line 9) | const HTTP_OK = 200;
constant HTTP_BAD_REQUEST (line 10) | const HTTP_BAD_REQUEST = 400;
constant HTTP_NOT_FOUND (line 11) | const HTTP_NOT_FOUND = 404;
constant HTTP_GONE (line 12) | const HTTP_GONE = 410;
constant HTTP_UNPROCESSABLE_ENTITY (line 13) | const HTTP_UNPROCESSABLE_ENTITY = 422;
constant HTTP_INTERNAL_SERVER_ERROR (line 14) | const HTTP_INTERNAL_SERVER_ERROR = 500;
constant SESSION_CLOSE_WAIT_MS (line 20) | const SESSION_CLOSE_WAIT_MS = 2000;
function requireEnv (line 37) | function requireEnv(name: string, value: string | undefined): string {
function getBaseUrl (line 44) | function getBaseUrl(): string {
function getHeaders (line 52) | function getHeaders(
type StartSessionResponse (line 68) | interface StartSessionResponse {
constant SESSION_READY_DELAY_MS (line 78) | const SESSION_READY_DELAY_MS = 250;
constant LOCAL_CONNECT_TIMEOUT_MS (line 79) | const LOCAL_CONNECT_TIMEOUT_MS = (() => {
type SessionInfo (line 84) | interface SessionInfo {
function createLocalBrowserBody (line 89) | function createLocalBrowserBody() {
constant LOCAL_BROWSER_BODY (line 122) | const LOCAL_BROWSER_BODY = createLocalBrowserBody();
function readLaunchDiagnostics (line 124) | function readLaunchDiagnostics(launchOptions?: {
function createSession (line 182) | async function createSession(
function createSessionWithCdp (line 189) | async function createSessionWithCdp(
function endSession (line 242) | async function endSession(
function navigateSession (line 259) | async function navigateSession(
function getMainFrameId (line 276) | async function getMainFrameId(cdpUrl: string): Promise<string> {
type SSEEvent (line 305) | interface SSEEvent {
function readSSEStream (line 311) | async function readSSEStream(response: Response): Promise<SSEEvent[]> {
type TypedSSEEvent (line 363) | interface TypedSSEEvent<TResult = unknown> {
function readSSEStreamRaw (line 377) | async function readSSEStreamRaw(response: Response): Promise<string> {
function parseTypedSSEEvents (line 398) | function parseTypedSSEEvents<TResult = unknown>(
type SSEStreamResult (line 416) | interface SSEStreamResult<TResult = unknown> {
function readTypedSSEStream (line 432) | async function readTypedSSEStream<TResult = unknown>(
function readTypedSSEStreamWithContext (line 443) | async function readTypedSSEStreamWithContext<TResult = unknown>(
function assertWithContext (line 481) | function assertWithContext(
function assertEventExists (line 494) | function assertEventExists<TResult>(
function assertHttpStatus (line 511) | function assertHttpStatus(
type FetchResult (line 530) | interface FetchResult<T = unknown> {
function fetchWithContext (line 551) | async function fetchWithContext<T = unknown>(
function assertFetchOk (line 624) | function assertFetchOk<T>(
function assertFetchStatus (line 637) | function assertFetchStatus<T>(
class TestSession (line 653) | class TestSession {
method constructor (line 657) | constructor(headers: Record<string, string>) {
method start (line 661) | async start(): Promise<string> {
method navigate (line 666) | async navigate(targetUrl: string): Promise<Response> {
method end (line 673) | async end(): Promise<void> {
method getSessionId (line 684) | getSessionId(): string {
FILE: packages/server-v3/test/integration/v3/act.test.ts
type ActResponse (line 25) | interface ActResponse {
type ActResult (line 34) | interface ActResult {
FILE: packages/server-v3/test/integration/v3/extract.test.ts
type ExtractResult (line 23) | type ExtractResult = Record<string, unknown>;
type ExtractResponse (line 52) | interface ExtractResponse {
type ExtractResponse (line 96) | interface ExtractResponse {
type ExtractResponse (line 136) | interface ExtractResponse {
type ExtractResponse (line 177) | interface ExtractResponse {
type ExtractResponse (line 222) | interface ExtractResponse {
type ExtractResponse (line 253) | interface ExtractResponse {
type ExtractResponse (line 291) | interface ExtractResponse {
FILE: packages/server-v3/test/integration/v3/multiRegion.test.ts
type StartSuccessResponse (line 18) | interface StartSuccessResponse {
type StartErrorResponse (line 27) | interface StartErrorResponse {
type StartResponse (line 32) | type StartResponse = StartSuccessResponse | StartErrorResponse;
function isSuccessResponse (line 34) | function isSuccessResponse(
FILE: packages/server-v3/test/integration/v3/observe.test.ts
type ObserveResult (line 23) | type ObserveResult = unknown[];
type ObserveResponse (line 53) | interface ObserveResponse {
type ObserveResponse (line 88) | interface ObserveResponse {
type ObserveResponse (line 125) | interface ObserveResponse {
type ObserveResponse (line 162) | interface ObserveResponse {
type ObserveResponse (line 203) | interface ObserveResponse {
FILE: packages/server-v3/test/integration/v3/start.test.ts
type StartSuccessResponse (line 28) | interface StartSuccessResponse {
type StartUnavailableResponse (line 37) | interface StartUnavailableResponse {
type StartErrorResponse (line 45) | interface StartErrorResponse {
type StartResponse (line 50) | type StartResponse =
function isSuccessResponse (line 55) | function isSuccessResponse(
type SeaHandle (line 61) | type SeaHandle = {
type SupervisorInfo (line 67) | type SupervisorInfo = {
function sleep (line 97) | function sleep(ms: number): Promise<void> {
function getFreePort (line 101) | async function getFreePort(): Promise<number> {
function listProcesses (line 123) | function listProcesses(): Array<{ pid: number; args: string }> {
function parseSupervisorConfigArg (line 144) | function parseSupervisorConfigArg(args: string): {
function findLocalSupervisorByParentPid (line 165) | function findLocalSupervisorByParentPid(
function isPidAlive (line 192) | function isPidAlive(pid: number): boolean {
function waitForValue (line 203) | async function waitForValue<T>(
function waitForPidState (line 217) | async function waitForPidState(
function waitForServerReady (line 234) | async function waitForServerReady(baseUrl: string, timeoutMs = 30_000) {
function waitForProcessExit (line 250) | async function waitForProcessExit(
function startSeaServer (line 266) | async function startSeaServer(
function stopSeaServer (line 319) | async function stopSeaServer(handle: SeaHandle): Promise<void> {
function forceKillSeaServer (line 338) | async function forceKillSeaServer(handle: SeaHandle): Promise<void> {
function startKeepAliveFalseLocalSession (line 349) | async function startKeepAliveFalseLocalSession(baseUrl: string): Promise<{
function startKeepAliveFalseBrowserbaseSession (line 384) | async function startKeepAliveFalseBrowserbaseSession(
function closeLocalBrowserViaCdp (line 439) | async function closeLocalBrowserViaCdp(cdpUrl: string): Promise<void> {
function waitForBrowserbaseNotRunning (line 454) | async function waitForBrowserbaseNotRunning(
function requestBrowserbaseReleaseBestEffort (line 482) | async function requestBrowserbaseReleaseBestEffort(sessionId: string) {
FILE: packages/server-v4/scripts/gen-openapi.ts
constant OUTPUT_PATH (line 24) | const OUTPUT_PATH = path.resolve(getCurrentDirPath(), "../openapi.v4.yam...
function main (line 26) | async function main() {
FILE: packages/server-v4/scripts/runtimePaths.ts
constant PACKAGE_SEGMENT (line 12) | const PACKAGE_SEGMENT = "/packages/server-v4/";
constant EVAL_FRAMES (line 13) | const EVAL_FRAMES = new Set(["[eval]", "[eval]-wrapper"]);
constant INTERNAL_FRAME_NAMES (line 14) | const INTERNAL_FRAME_NAMES = new Set([
type CallSiteWithScriptName (line 43) | type CallSiteWithScriptName = NodeJS.CallSite & {
FILE: packages/server-v4/src/routes/v4/browsersession/shared.ts
function buildBrowserSession (line 18) | function buildBrowserSession(input: {
type BrowserSessionRequestBody (line 65) | type BrowserSessionRequestBody<TAction extends BrowserSessionAction> = {
type BrowserSessionActionHandlerContext (line 70) | type BrowserSessionActionHandlerContext<TAction extends BrowserSessionAc...
type BrowserSessionActionExecutionResult (line 78) | type BrowserSessionActionExecutionResult<TAction extends BrowserSessionA...
function buildBrowserSessionPage (line 84) | function buildBrowserSessionPage(page: {
function buildStubBrowserSessionPage (line 98) | function buildStubBrowserSessionPage(
function buildStubBrowserSessionCookie (line 112) | function buildStubBrowserSessionCookie() {
function buildStubViewport (line 125) | function buildStubViewport() {
function getInitialPageId (line 133) | function getInitialPageId(params: unknown): string | undefined {
function toStringOrRegExp (line 146) | function toStringOrRegExp(
function createBrowserSessionActionHandler (line 165) | function createBrowserSessionActionHandler<
FILE: packages/server-v4/src/routes/v4/page/shared.ts
type PageRequestBody (line 24) | type PageRequestBody<TAction extends PageAction> = {
type PageRequestQuery (line 29) | type PageRequestQuery<TAction extends PageAction> = {
type PageActionHandlerContext (line 34) | type PageActionHandlerContext<TAction extends PageAction> = {
function normalizeXPath (line 42) | function normalizeXPath(xpath: string): string {
function getPageId (line 48) | function getPageId(params: unknown): string | undefined {
function buildStubPageFrame (line 61) | function buildStubPageFrame(pageId = "page_stub") {
function buildStubNavigationResult (line 70) | function buildStubNavigationResult(url = "https://stub.invalid") {
function extractPageParams (line 83) | function extractPageParams<TAction extends PageAction>(
function createPageActionHandler (line 96) | function createPageActionHandler<TAction extends PageAction>(options: {
FILE: packages/server-v4/src/routes/v4/pluginUtils.ts
type TaggedRouteSchema (line 5) | type TaggedRouteSchema = NonNullable<RouteOptions["schema"]> & {
type ValidationLikeError (line 9) | type ValidationLikeError = {
function isValidationLikeError (line 13) | function isValidationLikeError(error: unknown): error is ValidationLikeE...
function getErrorStatusCode (line 22) | function getErrorStatusCode(error: unknown): number {
function withTag (line 35) | function withTag(route: RouteOptions, tag: string): RouteOptions {
function normalizePluginError (line 52) | function normalizePluginError(error: unknown): {
FILE: packages/server-v4/src/schemas/v4/browserSession.ts
function createBrowserSessionRequestSchema (line 261) | function createBrowserSessionRequestSchema<T extends z.ZodTypeAny>(
function createBrowserSessionActionSchema (line 268) | function createBrowserSessionActionSchema<
function createBrowserSessionResponseSchema (line 280) | function createBrowserSessionResponseSchema<T extends z.ZodTypeAny>(
type BrowserSessionCreateRequest (line 1172) | type BrowserSessionCreateRequest = z.infer<
type BrowserSessionIdParams (line 1175) | type BrowserSessionIdParams = z.infer<
type BrowserSession (line 1178) | type BrowserSession = z.infer<typeof BrowserSessionSchema>;
type BrowserSessionActionMethod (line 1179) | type BrowserSessionActionMethod = z.infer<
type BrowserSessionAction (line 1182) | type BrowserSessionAction = z.infer<typeof BrowserSessionActionSchema>;
type BrowserSessionActionDetailsQuery (line 1183) | type BrowserSessionActionDetailsQuery = z.infer<
type BrowserSessionActionListQuery (line 1186) | type BrowserSessionActionListQuery = z.infer<
type BrowserSessionPage (line 1189) | type BrowserSessionPage = z.infer<typeof BrowserSessionPageSchema>;
function buildBrowserSessionErrorResponse (line 1191) | function buildBrowserSessionErrorResponse(input: {
FILE: packages/server-v4/src/schemas/v4/page.ts
function createPageRequestSchema (line 240) | function createPageRequestSchema<T extends z.ZodTypeAny>(
function createPageActionSchema (line 247) | function createPageActionSchema<
function createPageResponseSchema (line 259) | function createPageResponseSchema<T extends z.ZodTypeAny>(
type PageActionMethod (line 1546) | type PageActionMethod = z.infer<typeof PageActionMethodSchema>;
type PageActionStatus (line 1547) | type PageActionStatus = z.infer<typeof PageActionStatusSchema>;
type PageAction (line 1548) | type PageAction = z.infer<typeof PageActionSchema>;
type PageActionDetailsQuery (line 1549) | type PageActionDetailsQuery = z.infer<
type PageActionListQuery (line 1552) | type PageActionListQuery = z.infer<typeof PageActionListQuerySchema>;
function buildErrorResponse (line 1554) | function buildErrorResponse(input: {
FILE: packages/server-v4/src/types/error.ts
class AppError (line 3) | class AppError extends Error {
method constructor (line 7) | constructor(
class UnknownModelError (line 19) | class UnknownModelError extends AppError {
method constructor (line 20) | constructor(model
Condensed preview — 799 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,491K chars).
[
{
"path": ".changeset/config.json",
"chars": 437,
"preview": "{\n \"$schema\": \"https://unpkg.com/@changesets/config@2.1.1/schema.json\",\n \"commit\": false,\n \"fixed\": [],\n \"linked\": ["
},
{
"path": ".changeset/crazy-nights-prove.md",
"chars": 125,
"preview": "---\n\"@browserbasehq/stagehand\": patch\n---\n\napply user defined toolTimeout to all agent tools (other than wait & think to"
},
{
"path": ".cursorrules",
"chars": 6656,
"preview": "# Stagehand Project\n\nThis is a project that uses Stagehand V3, a browser automation framework with AI-powered `act`, `ex"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 1322,
"preview": "---\nname: Bug report\nabout: Detailed descriptions help us resolve faster\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Befo"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 681,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
},
{
"path": ".github/actions/select-browserbase-region/action.yml",
"chars": 2124,
"preview": "name: Select Browserbase region\ndescription: Select a Browserbase region based on a weighted distribution.\ninputs:\n dis"
},
{
"path": ".github/actions/setup-node-pnpm-turbo/action.yml",
"chars": 1775,
"preview": "name: Setup Node, pnpm, and Turbo cache\ndescription: Configure pnpm and Node.js with caching, restore Turbo cache, and i"
},
{
"path": ".github/actions/upload-ctrf-report/action.yml",
"chars": 966,
"preview": "name: Upload CTRF report\ndescription: Upload CTRF report artifact.\ninputs:\n name:\n description: Report path (used as"
},
{
"path": ".github/actions/upload-v8-coverage/action.yml",
"chars": 935,
"preview": "name: Upload V8 coverage\ndescription: Upload V8 coverage artifacts.\ninputs:\n name:\n description: Artifact name.\n "
},
{
"path": ".github/actions/verify-chromium-launch/action.yml",
"chars": 8721,
"preview": "name: Verify Chromium launch\ndescription: Validate that Chromium can start, connect to CDP, and read the page title.\ninp"
},
{
"path": ".github/pull_request_template",
"chars": 35,
"preview": "# why\n\n# what changed\n\n# test plan\n"
},
{
"path": ".github/workflows/ci.yml",
"chars": 30042,
"preview": "name: Tests\n\non:\n pull_request:\n types:\n - opened\n - synchronize\n - labeled\n - unlabeled\n pat"
},
{
"path": ".github/workflows/claude.yml",
"chars": 2935,
"preview": "name: Claude Code\n\non:\n issue_comment:\n types: [created]\n pull_request_review_comment:\n types: [created]\n issue"
},
{
"path": ".github/workflows/external-contributor-pr-approval-handoff.yml",
"chars": 1232,
"preview": "name: External Contributor PR Approval Handoff\n\non:\n pull_request_review:\n types:\n - submitted\n\npermissions:\n "
},
{
"path": ".github/workflows/external-contributor-pr.yml",
"chars": 27390,
"preview": "name: External Contributor PR\n\non:\n pull_request_target:\n types:\n - opened\n - reopened\n - synchronize"
},
{
"path": ".github/workflows/feature-parity.yml",
"chars": 5736,
"preview": "name: Feature Parity\n\non:\n pull_request:\n types:\n - opened\n - synchronize\n - labeled\n - unlabele"
},
{
"path": ".github/workflows/release.yml",
"chars": 1298,
"preview": "name: Release\n\non:\n push:\n branches:\n - main\n\npermissions:\n contents: write\n pull-requests: write\n id-token:"
},
{
"path": ".github/workflows/stagehand-server-v3-release.yml",
"chars": 6724,
"preview": "name: Release stagehand/server-v3\n\non:\n push:\n branches:\n - main\n paths:\n - .changeset/**\n workflow_di"
},
{
"path": ".github/workflows/stagehand-server-v3-sea-build.yml",
"chars": 6948,
"preview": "name: Stagehand Server v3 SEA Build\n\non:\n workflow_call:\n inputs:\n matrix:\n description: \"JSON matrix in"
},
{
"path": ".github/workflows/stagehand-server-v4-release.yml",
"chars": 6724,
"preview": "name: Release stagehand/server-v4\n\non:\n push:\n branches:\n - main\n paths:\n - .changeset/**\n workflow_di"
},
{
"path": ".github/workflows/stagehand-server-v4-sea-build.yml",
"chars": 6948,
"preview": "name: Stagehand Server v4 SEA Build\n\non:\n workflow_call:\n inputs:\n matrix:\n description: \"JSON matrix in"
},
{
"path": ".github/workflows/stainless.yml",
"chars": 1689,
"preview": "name: Build SDKs for pull request\n\non:\n pull_request:\n types:\n - opened\n - synchronize\n - reopened\n "
},
{
"path": ".gitignore",
"chars": 530,
"preview": "node_modules/\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\nscreenshot.png\n.DS_STORE\n.cache/\n.env"
},
{
"path": ".prettierignore",
"chars": 343,
"preview": "pnpm-lock.yaml\nREADME.md\n**/*.json\ndocs/\n.github/\ndist/\nnode_modules/\nlib/dom/build/\nlib/v3/dom/build/\npackages/core/dis"
},
{
"path": ".prettierrc",
"chars": 3,
"preview": "{}\n"
},
{
"path": ".vscode/settings.json",
"chars": 89,
"preview": "{\n \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n \"editor.formatOnSave\": true\n}\n"
},
{
"path": "CHANGELOG.md",
"chars": 61877,
"preview": "# @browserbasehq/stagehand\n\n## 3.0.0\n\n### Major Changes\n\n- Removes internal Playwright dependency\n- A generous 20-40% sp"
},
{
"path": "LICENSE",
"chars": 1073,
"preview": "MIT License\n\nCopyright (c) 2024 Browserbase Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.md",
"chars": 6554,
"preview": "<div id=\"toc\" align=\"center\" style=\"margin-bottom: 0;\">\n <ul style=\"list-style: none; margin: 0; padding: 0;\">\n <a h"
},
{
"path": "claude.md",
"chars": 7767,
"preview": "# Stagehand Project\n\nThis is a project that uses Stagehand V3, a browser automation framework with AI-powered `act`, `ex"
},
{
"path": "eslint.config.mjs",
"chars": 2489,
"preview": "import globals from \"globals\";\nimport pluginJs from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\nimport secur"
},
{
"path": "package.json",
"chars": 3132,
"preview": "{\n \"name\": \"stagehand-workspace\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"description\": \"Stagehand monorepo workspa"
},
{
"path": "packages/README.md",
"chars": 278,
"preview": "# Stagehand Packages\n\nThis directory contains the Stagehand monorepo packages:\n\n- **core** - The main Stagehand package\n"
},
{
"path": "packages/cli/CHANGELOG.md",
"chars": 2476,
"preview": "# @browserbasehq/browse-cli\n\n## 0.2.0\n\n### Minor Changes\n\n- [#1816](https://github.com/browserbase/stagehand/pull/1816) "
},
{
"path": "packages/cli/README.md",
"chars": 8172,
"preview": "# Browse CLI\n\nBrowser automation CLI for AI agents. Built on [Stagehand](https://github.com/browserbase/stagehand), prov"
},
{
"path": "packages/cli/package.json",
"chars": 1768,
"preview": "{\n \"name\": \"@browserbasehq/browse-cli\",\n \"version\": \"0.2.0\",\n \"description\": \"Browser automation CLI for AI agents, b"
},
{
"path": "packages/cli/src/index.ts",
"chars": 64990,
"preview": "/**\n * Browse CLI - Browser automation for AI agents\n *\n * Usage:\n * browse [options] <command> [args...]\n *\n * The CL"
},
{
"path": "packages/cli/tests/cli.test.ts",
"chars": 17989,
"preview": "/**\n * Browse CLI Tests\n *\n * Comprehensive test suite covering:\n * - Daemon lifecycle\n * - Navigation commands\n * - Act"
},
{
"path": "packages/cli/tests/mode.test.ts",
"chars": 2720,
"preview": "import { describe, it, expect, afterEach } from \"vitest\";\nimport { exec } from \"child_process\";\nimport { promises as fs "
},
{
"path": "packages/cli/tsconfig.json",
"chars": 273,
"preview": "{\n \"extends\": \"../../tsconfig.base.json\",\n \"compilerOptions\": {\n \"moduleResolution\": \"bundler\",\n \"strict\": true,"
},
{
"path": "packages/cli/tsup.config.ts",
"chars": 594,
"preview": "import { defineConfig } from \"tsup\";\n\nexport default defineConfig({\n entry: [\"src/index.ts\"],\n format: [\"cjs\"],\n targ"
},
{
"path": "packages/cli/vitest.config.ts",
"chars": 356,
"preview": "import { defineConfig } from \"vitest/config\";\n\nexport default defineConfig({\n test: {\n globals: true,\n testTimeou"
},
{
"path": "packages/core/CHANGELOG.md",
"chars": 42276,
"preview": "# @browserbasehq/stagehand\n\n## 3.2.0\n\n### Minor Changes\n\n- [#1779](https://github.com/browserbase/stagehand/pull/1779) ["
},
{
"path": "packages/core/README.md",
"chars": 6595,
"preview": "<div id=\"toc\" align=\"center\" style=\"margin-bottom: 0;\">\n <ul style=\"list-style: none; margin: 0; padding: 0;\">\n <a h"
},
{
"path": "packages/core/examples/2048.ts",
"chars": 3468,
"preview": "import { Stagehand } from \"../lib/v3/index.js\";\nimport { z } from \"zod\";\n\nasync function example() {\n console.log(\"🎮 St"
},
{
"path": "packages/core/examples/CHANGELOG.md",
"chars": 6820,
"preview": "# @browserbasehq/stagehand-examples\n\n## 1.0.9\n\n### Patch Changes\n\n- Updated dependencies [[`09b5e1e`](https://github.com"
},
{
"path": "packages/core/examples/actionable_observe_example.ts",
"chars": 2595,
"preview": "/**\n * This example shows how to use actionable observe()\n *\n * You can use observe to get a cache-able Playwright actio"
},
{
"path": "packages/core/examples/agent-custom-tools.ts",
"chars": 3329,
"preview": "/**\n * This example shows how to pass custom tools to stagehand agent (both CUA and non-CUA)\n */\nimport { z } from \"zod\""
},
{
"path": "packages/core/examples/agent_stream_example.ts",
"chars": 1357,
"preview": "import { Stagehand } from \"../lib/v3/index.js\";\nimport chalk from \"chalk\";\n\n// Load environment variables\nasync function"
},
{
"path": "packages/core/examples/cua-example.ts",
"chars": 2330,
"preview": "/**\n * This example shows how to use a computer use agent (CUA) to navigate a web page and extract data.\n *\n * To learn "
},
{
"path": "packages/core/examples/custom_client_aisdk.ts",
"chars": 1085,
"preview": "/**\n * This example shows how to use the Vercel AI SDK to power the Stagehand LLM Client.\n *\n * You will need to referen"
},
{
"path": "packages/core/examples/custom_client_langchain.ts",
"chars": 1037,
"preview": "/**\n * This example shows how to use the Langchain client with Stagehand.\n *\n * You will need to reference the Langchain"
},
{
"path": "packages/core/examples/custom_client_openai.ts",
"chars": 1276,
"preview": "/**\n * This example shows how to use a custom OpenAI client with Stagehand.\n *\n * The OpenAI API provides a simple, type"
},
{
"path": "packages/core/examples/example.ts",
"chars": 1426,
"preview": "import { Stagehand } from \"../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n /**\n * Add your code"
},
{
"path": "packages/core/examples/external_clients/aisdk.ts",
"chars": 70,
"preview": "export { AISdkClient } from \"../../lib/v3/external_clients/aisdk.js\";\n"
},
{
"path": "packages/core/examples/external_clients/customOpenAI.ts",
"chars": 84,
"preview": "export { CustomOpenAIClient } from \"../../lib/v3/external_clients/customOpenAI.js\";\n"
},
{
"path": "packages/core/examples/external_clients/langchain.ts",
"chars": 2666,
"preview": "import { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport {\n CreateChatCompletionOptions,\n L"
},
{
"path": "packages/core/examples/form_filling_sensible.ts",
"chars": 2905,
"preview": "/**\n * This example shows you how to use observe() to get a cacheable Playwright action as JSON, then pass that JSON to "
},
{
"path": "packages/core/examples/google_enter.ts",
"chars": 650,
"preview": "/**\n * This example shows how to use the Stagehand agent to navigate to Google and search for \"Browserbase\".\n *\n * It's "
},
{
"path": "packages/core/examples/instructions.ts",
"chars": 727,
"preview": "/**\n * This example shows how to use custom system prompts with Stagehand.\n */\nimport { Stagehand } from \"../lib/v3/inde"
},
{
"path": "packages/core/examples/integrations/exa.ts",
"chars": 1322,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n const page = stageh"
},
{
"path": "packages/core/examples/integrations/supabase.ts",
"chars": 1023,
"preview": "import { connectToMCPServer, Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n "
},
{
"path": "packages/core/examples/mcp.ts",
"chars": 2523,
"preview": "// import { Stagehand } from \"../lib/v3\";\n// import StagehandConfig from \"@/stagehand.config\";\n// import chalk from \"cha"
},
{
"path": "packages/core/examples/operator-example.ts",
"chars": 1331,
"preview": "/**\n * This example shows how to use the Stagehand operator to do simple autonomous tasks.\n *\n * This is built off of ou"
},
{
"path": "packages/core/examples/oss-cua-example.ts",
"chars": 2819,
"preview": "/**\n * This example shows how to use a computer use agent (CUA) to navigate a web page and extract data.\n *\n * To learn "
},
{
"path": "packages/core/examples/parameterizeApiKey.ts",
"chars": 1049,
"preview": "import { Stagehand } from \"../lib/v3/index.js\";\nimport { z } from \"zod\";\n\n/**\n * This example shows how to parameterize "
},
{
"path": "packages/core/examples/persist_logs_example.ts",
"chars": 941,
"preview": "/**\n * Example: Run a Stagehand agent and persist structured logging events to a user-specified dir.\n */\nimport path fro"
},
{
"path": "packages/core/examples/tsconfig.json",
"chars": 90,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"include\": [\"*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\n"
},
{
"path": "packages/core/examples/v3/cuaReplay.ts",
"chars": 2644,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\nimport { v3Logger } from \"../../lib/v3/logger.js\";\n\nasync function ru"
},
{
"path": "packages/core/examples/v3/deepLocator.ts",
"chars": 816,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n const page = stageh"
},
{
"path": "packages/core/examples/v3/dropdown.ts",
"chars": 772,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n const page = stageh"
},
{
"path": "packages/core/examples/v3/highlight.ts",
"chars": 665,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n const page = stageh"
},
{
"path": "packages/core/examples/v3/patchright.ts",
"chars": 867,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\nimport { chromium } from \"patchright-core\";\nimport { z } from \"zod\";\n"
},
{
"path": "packages/core/examples/v3/playwright.ts",
"chars": 1156,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\nimport { chromium } from \"playwright-core\";\nimport { z } from \"zod\";\n"
},
{
"path": "packages/core/examples/v3/puppeteer.ts",
"chars": 708,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\nimport puppeteer from \"puppeteer-core\";\n\nasync function example(stage"
},
{
"path": "packages/core/examples/v3/recordVideo.ts",
"chars": 1777,
"preview": "import path from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport { Stagehand } from \"../../lib/v3/index.js"
},
{
"path": "packages/core/examples/v3/returnXpath.ts",
"chars": 625,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n const page = stageh"
},
{
"path": "packages/core/examples/v3/shadowRoot.ts",
"chars": 811,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\n\nasync function example(stagehand: Stagehand) {\n const page = stageh"
},
{
"path": "packages/core/examples/v3/targetedExtract.ts",
"chars": 965,
"preview": "import { Stagehand } from \"../../lib/v3/index.js\";\nimport { z } from \"zod\";\n\nasync function example(stagehand: Stagehand"
},
{
"path": "packages/core/examples/v3/v3_agent.ts",
"chars": 1276,
"preview": "import chalk from \"chalk\";\nimport { V3 } from \"../../lib/v3/index.js\";\n\nconst INSTRUCTION = \"scroll down and click on th"
},
{
"path": "packages/core/examples/v3_example.ts",
"chars": 965,
"preview": "import { V3 } from \"../lib/v3/index.js\";\nimport { z } from \"zod\";\n\nasync function example(v3: V3) {\n const page = v3.co"
},
{
"path": "packages/core/examples/wordle.ts",
"chars": 670,
"preview": "import { Stagehand } from \"../lib/v3/index.js\";\n\nasync function example() {\n const stagehand = new Stagehand({\n env:"
},
{
"path": "packages/core/lib/CHANGELOG.md",
"chars": 5886,
"preview": "# @browserbasehq/stagehand-lib\n\n## 2.4.1\n\n### Patch Changes\n\n- [#1027](https://github.com/browserbase/stagehand/pull/102"
},
{
"path": "packages/core/lib/inference.ts",
"chars": 15352,
"preview": "import { z } from \"zod\";\nimport { LogLine } from \"./v3/types/public/logs.js\";\nimport { ChatMessage, LLMClient } from \"./"
},
{
"path": "packages/core/lib/inferenceLogUtils.ts",
"chars": 3264,
"preview": "import fs from \"fs\";\nimport path from \"path\";\n\n/**\n * Create (or ensure) a parent directory named \"inference_summary\".\n "
},
{
"path": "packages/core/lib/logger.ts",
"chars": 10821,
"preview": "import pino from \"pino\";\nimport { LogLine } from \"./v3/types/public/logs.js\";\n\n// Map our existing levels to Pino's stan"
},
{
"path": "packages/core/lib/modelUtils.ts",
"chars": 2031,
"preview": "import { ClientOptions, ModelConfiguration } from \"./v3/types/public/model.js\";\nimport {\n AVAILABLE_CUA_MODELS,\n Avail"
},
{
"path": "packages/core/lib/prompt.ts",
"chars": 13127,
"preview": "import { ChatMessage } from \"./v3/llm/LLMClient.js\";\nimport type { Variables } from \"./v3/types/public/agent.js\";\n\nexpor"
},
{
"path": "packages/core/lib/utils.ts",
"chars": 23708,
"preview": "import { ZodSchemaValidationError } from \"./v3/types/public/sdkErrors.js\";\nimport { Schema, Type } from \"@google/genai\";"
},
{
"path": "packages/core/lib/v3/agent/AgentClient.ts",
"chars": 1602,
"preview": "import {\n AgentAction,\n AgentResult,\n AgentType,\n AgentExecutionOptions,\n} from \"../types/public/agent.js\";\nimport {"
},
{
"path": "packages/core/lib/v3/agent/AgentProvider.ts",
"chars": 3813,
"preview": "import { ToolSet } from \"ai/dist\";\nimport { AgentProviderType } from \"../types/public/agent.js\";\nimport { LogLine } from"
},
{
"path": "packages/core/lib/v3/agent/AnthropicCUAClient.ts",
"chars": 30158,
"preview": "import {\n AgentAction,\n AgentResult,\n AgentType,\n AnthropicContentBlock,\n AnthropicMessage,\n AnthropicTextBlock,\n "
},
{
"path": "packages/core/lib/v3/agent/GoogleCUAClient.ts",
"chars": 30120,
"preview": "import {\n GoogleGenAI,\n Content,\n Part,\n GenerateContentResponse,\n FunctionCall,\n GenerateContentConfig,\n Tool,\n "
},
{
"path": "packages/core/lib/v3/agent/MicrosoftCUAClient.ts",
"chars": 29771,
"preview": "import OpenAI from \"openai\";\nimport { LogLine } from \"../types/public/logs.js\";\nimport {\n AgentAction,\n AgentResult,\n "
},
{
"path": "packages/core/lib/v3/agent/OpenAICUAClient.ts",
"chars": 27208,
"preview": "import OpenAI from \"openai\";\nimport { LogLine } from \"../types/public/logs.js\";\nimport {\n AgentAction,\n AgentResult,\n "
},
{
"path": "packages/core/lib/v3/agent/prompts/agentSystemPrompt.ts",
"chars": 11868,
"preview": "import type { AgentToolMode, Variables } from \"../../types/public/agent.js\";\nimport { CAPTCHA_SYSTEM_PROMPT_NOTE } from "
},
{
"path": "packages/core/lib/v3/agent/tools/README.md",
"chars": 214,
"preview": "This folder provides v3-native agent tools for the AISDK-based agent flow.\nThey mirror the v2 tools but operate on the V"
},
{
"path": "packages/core/lib/v3/agent/tools/act.ts",
"chars": 2607,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/ariaTree.ts",
"chars": 2020,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport { TimeoutError } from "
},
{
"path": "packages/core/lib/v3/agent/tools/braveSearch.ts",
"chars": 2930,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\n\nexport interface BraveSearch"
},
{
"path": "packages/core/lib/v3/agent/tools/browserbaseSearch.ts",
"chars": 2647,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\n\nexport interface SearchResul"
},
{
"path": "packages/core/lib/v3/agent/tools/click.ts",
"chars": 3673,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/clickAndHold.ts",
"chars": 2810,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/dragAndDrop.ts",
"chars": 4069,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/extract.ts",
"chars": 3738,
"preview": "import { tool } from \"ai\";\nimport { z, ZodTypeAny } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Age"
},
{
"path": "packages/core/lib/v3/agent/tools/fillFormVision.ts",
"chars": 6263,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/fillform.ts",
"chars": 3209,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/goto.ts",
"chars": 929,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\n\nexport const gotoTool = (v3:"
},
{
"path": "packages/core/lib/v3/agent/tools/index.ts",
"chars": 8586,
"preview": "import { gotoTool } from \"./goto.js\";\nimport { actTool } from \"./act.js\";\nimport { screenshotTool } from \"./screenshot.j"
},
{
"path": "packages/core/lib/v3/agent/tools/keys.ts",
"chars": 2360,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\n\nexport const keysTool = (v3:"
},
{
"path": "packages/core/lib/v3/agent/tools/navback.ts",
"chars": 713,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\n\nexport const navBackTool = ("
},
{
"path": "packages/core/lib/v3/agent/tools/screenshot.ts",
"chars": 1309,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\n\nexport const screenshotTool "
},
{
"path": "packages/core/lib/v3/agent/tools/scroll.ts",
"chars": 5889,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type {\n ScrollToolRes"
},
{
"path": "packages/core/lib/v3/agent/tools/think.ts",
"chars": 840,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\n\nexport const thinkTool = () =>\n tool({\n description: `Use this "
},
{
"path": "packages/core/lib/v3/agent/tools/type.ts",
"chars": 4451,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type { Action } from \""
},
{
"path": "packages/core/lib/v3/agent/tools/wait.ts",
"chars": 2043,
"preview": "import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport type { V3 } from \"../../v3.js\";\nimport type {\n AgentToolMode"
},
{
"path": "packages/core/lib/v3/agent/utils/actionMapping.ts",
"chars": 4054,
"preview": "import { AgentAction } from \"../../types/public/agent.js\";\nimport { ActionMappingOptions } from \"../../types/private/age"
},
{
"path": "packages/core/lib/v3/agent/utils/captchaSolver.ts",
"chars": 7389,
"preview": "import type { Page } from \"../../understudy/page.js\";\nimport type { ConsoleMessage } from \"../../understudy/consoleMessa"
},
{
"path": "packages/core/lib/v3/agent/utils/coordinateNormalization.ts",
"chars": 1194,
"preview": "import type { V3 } from \"../../v3.js\";\n\n// Default viewport for advancedStealth mode\nconst STEALTH_VIEWPORT = { width: 1"
},
{
"path": "packages/core/lib/v3/agent/utils/cuaKeyMapping.ts",
"chars": 1560,
"preview": "/**\n * Universal key mapping utility for converting various key representations\n * to Playwright-compatible key names. U"
},
{
"path": "packages/core/lib/v3/agent/utils/googleCustomToolHandler.ts",
"chars": 5244,
"preview": "import { Part, FunctionCall, FunctionDeclaration, Type } from \"@google/genai\";\nimport { ToolSet } from \"ai\";\nimport { Lo"
},
{
"path": "packages/core/lib/v3/agent/utils/handleDoneToolCall.ts",
"chars": 4532,
"preview": "import { generateText, ModelMessage, LanguageModel, ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport { tool } from \""
},
{
"path": "packages/core/lib/v3/agent/utils/imageCompression.ts",
"chars": 9191,
"preview": "import {\n AnthropicMessage,\n AnthropicContentBlock,\n AnthropicToolResult,\n ResponseInputItem as OpenAIResponseInputI"
},
{
"path": "packages/core/lib/v3/agent/utils/messageProcessing.ts",
"chars": 6500,
"preview": "import type { ModelMessage } from \"ai\";\n\n// Vision action tools that include screenshots in their results\nconst VISION_A"
},
{
"path": "packages/core/lib/v3/agent/utils/screenshotHandler.ts",
"chars": 924,
"preview": "import type { Page } from \"../../understudy/page.js\";\n\n/**\n * Default delay in milliseconds to wait after vision actions"
},
{
"path": "packages/core/lib/v3/agent/utils/validateExperimentalFeatures.ts",
"chars": 4391,
"preview": "import {\n ExperimentalNotConfiguredError,\n StagehandInvalidArgumentError,\n} from \"../../types/public/sdkErrors.js\";\nim"
},
{
"path": "packages/core/lib/v3/agent/utils/variables.ts",
"chars": 1681,
"preview": "import type { Variables, VariableValue } from \"../../types/public/agent.js\";\n\n/**\n * Resolves a VariableValue to its pri"
},
{
"path": "packages/core/lib/v3/agent/utils/xpath.ts",
"chars": 555,
"preview": "/**\n * Utility functions for XPath handling in agent tools.\n */\n\n/**\n * Ensures a value is properly formatted as an XPat"
},
{
"path": "packages/core/lib/v3/api.ts",
"chars": 28788,
"preview": "import makeFetchCookie from \"fetch-cookie\";\nimport { loadApiKeyFromEnv } from \"../utils.js\";\nimport { STAGEHAND_VERSION "
},
{
"path": "packages/core/lib/v3/cache/ActCache.ts",
"chars": 10010,
"preview": "import { createHash } from \"crypto\";\nimport type { ActHandler } from \"../handlers/actHandler.js\";\nimport type { LLMClien"
},
{
"path": "packages/core/lib/v3/cache/AgentCache.ts",
"chars": 26161,
"preview": "import { createHash } from \"crypto\";\nimport type { ActHandler } from \"../handlers/actHandler.js\";\nimport type { LLMClien"
},
{
"path": "packages/core/lib/v3/cache/CacheStorage.ts",
"chars": 2957,
"preview": "import fs from \"fs\";\nimport path from \"path\";\nimport type { Logger } from \"../types/public/index.js\";\nimport { ReadJsonR"
},
{
"path": "packages/core/lib/v3/cache/serverAgentCache.ts",
"chars": 2702,
"preview": "import { AgentCache } from \"./AgentCache.js\";\nimport { CacheStorage } from \"./CacheStorage.js\";\nimport type { V3 } from "
},
{
"path": "packages/core/lib/v3/cache/utils.ts",
"chars": 1277,
"preview": "import type { Logger } from \"../types/public/index.js\";\nimport { Page } from \"../understudy/page.js\";\n\nconst DEFAULT_WAI"
},
{
"path": "packages/core/lib/v3/cli.js",
"chars": 457,
"preview": "#!/usr/bin/env node\n\nimport process from \"node:process\";\nimport { maybeRunShutdownSupervisorFromArgv } from \"./shutdown/"
},
{
"path": "packages/core/lib/v3/dom/a11yScripts/index.ts",
"chars": 3231,
"preview": "export function getScrollOffsets(): { sx: number; sy: number } {\n try {\n const sx =\n window.scrollX ??\n wi"
},
{
"path": "packages/core/lib/v3/dom/genA11yScripts.ts",
"chars": 2506,
"preview": "import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport esbuild from \"e"
},
{
"path": "packages/core/lib/v3/dom/genDomScripts.ts",
"chars": 1445,
"preview": "/**\n * Build the v3 DOM script into a single JS file and then export its contents\n * as a string constant (`v3ScriptCont"
},
{
"path": "packages/core/lib/v3/dom/genLocatorScripts.ts",
"chars": 2573,
"preview": "import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport esbuild from \"e"
},
{
"path": "packages/core/lib/v3/dom/genScreenshotScripts.ts",
"chars": 1702,
"preview": "import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport esbuild from \"e"
},
{
"path": "packages/core/lib/v3/dom/global.d.ts",
"chars": 410,
"preview": "export interface StagehandV3Backdoor {\n /** Closed shadow-root accessors */\n getClosedRoot(host: Element): ShadowRoot "
},
{
"path": "packages/core/lib/v3/dom/index.ts",
"chars": 38,
"preview": "export * from \"./piercer.runtime.js\";\n"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/counts.ts",
"chars": 7377,
"preview": "import { countXPathMatches } from \"./xpathResolver.js\";\n\nexport interface TextMatchSample {\n tag: string;\n id: string;"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/index.ts",
"chars": 129,
"preview": "export * from \"./scripts.js\";\nexport * from \"./selectors.js\";\nexport * from \"./counts.js\";\nexport * from \"./waitForSelec"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/scripts.ts",
"chars": 14488,
"preview": "/*\n * DOM-side helpers used by Locator Runtime.callFunctionOn invocations.\n *\n * NOTE: These functions run inside the pa"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/selectors.ts",
"chars": 8137,
"preview": "import { resolveXPathAtIndex } from \"./xpathResolver.js\";\n\nconst parseTargetIndex = (value: unknown): number => {\n cons"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/waitForSelector.ts",
"chars": 9241,
"preview": "/**\n * waitForSelector - Waits for an element matching a selector to reach a specific state.\n * Supports both CSS select"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/xpathParser.ts",
"chars": 12717,
"preview": "export type XPathPredicate =\n | { type: \"index\"; index: number }\n | { type: \"attrEquals\"; name: string; value: string;"
},
{
"path": "packages/core/lib/v3/dom/locatorScripts/xpathResolver.ts",
"chars": 6672,
"preview": "import {\n applyPredicates,\n parseXPathSteps,\n type XPathStep,\n} from \"./xpathParser.js\";\n\ntype ClosedRootGetter = (ho"
},
{
"path": "packages/core/lib/v3/dom/piercer.entry.ts",
"chars": 125,
"preview": "import { installV3ShadowPiercer } from \"./piercer.runtime.js\";\n\ninstallV3ShadowPiercer({ debug: true, tagExisting: false"
},
{
"path": "packages/core/lib/v3/dom/piercer.runtime.ts",
"chars": 3622,
"preview": "export interface V3ShadowPatchOptions {\n debug?: boolean;\n tagExisting?: boolean;\n}\n\nexport interface StagehandV3Backd"
},
{
"path": "packages/core/lib/v3/dom/rerenderMissingShadows.entry.ts",
"chars": 113,
"preview": "import { rerenderMissingShadowHosts } from \"./rerenderMissingShadows.runtime.js\";\n\nrerenderMissingShadowHosts();\n"
},
{
"path": "packages/core/lib/v3/dom/rerenderMissingShadows.runtime.ts",
"chars": 1173,
"preview": "export function rerenderMissingShadowHosts(): void {\n try {\n const piercer = window.__stagehandV3__;\n if (!pierce"
},
{
"path": "packages/core/lib/v3/dom/screenshotScripts/index.ts",
"chars": 56,
"preview": "export { resolveMaskRect } from \"./resolveMaskRect.js\";\n"
},
{
"path": "packages/core/lib/v3/dom/screenshotScripts/resolveMaskRect.ts",
"chars": 2385,
"preview": "export type MaskRect = {\n x: number;\n y: number;\n width: number;\n height: number;\n rootToken?: string | null;\n};\n\ne"
},
{
"path": "packages/core/lib/v3/external_clients/aisdk.ts",
"chars": 3787,
"preview": "import {\n CoreAssistantMessage,\n ModelMessage,\n CoreSystemMessage,\n Tool,\n CoreUserMessage,\n generateObject,\n gen"
},
{
"path": "packages/core/lib/v3/external_clients/customOpenAI.ts",
"chars": 8120,
"preview": "/**\n * Welcome to the Stagehand custom OpenAI client!\n *\n * This is a client for models that are compatible with the Ope"
},
{
"path": "packages/core/lib/v3/flowlogger/EventEmitter.ts",
"chars": 1024,
"preview": "import { EventEmitter } from \"node:events\";\n\ntype WildcardEventListener = (...args: unknown[]) => void;\n\nexport class Ev"
},
{
"path": "packages/core/lib/v3/flowlogger/EventSink.ts",
"chars": 8549,
"preview": "import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { FlowEvent } from \"./FlowLogger.js\";\nimport type { Event"
},
{
"path": "packages/core/lib/v3/flowlogger/EventStore.ts",
"chars": 6767,
"preview": "import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { V3Options } from \"../types/public/index.js\";\nimpor"
},
{
"path": "packages/core/lib/v3/flowlogger/FlowLogger.ts",
"chars": 29748,
"preview": "import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport type { LanguageModelMi"
},
{
"path": "packages/core/lib/v3/flowlogger/prettify.ts",
"chars": 18006,
"preview": "import { toTitleCase } from \"../../utils.js\";\nimport { FlowEvent } from \"./FlowLogger.js\";\nimport type { EventStoreApi }"
},
{
"path": "packages/core/lib/v3/handlers/actHandler.ts",
"chars": 16241,
"preview": "// lib/v3/handlers/actHandler.ts\nimport { act as actInference } from \"../../inference.js\";\nimport { buildActPrompt, buil"
},
{
"path": "packages/core/lib/v3/handlers/extractHandler.ts",
"chars": 8407,
"preview": "// lib/v3/handlers/extractHandler.ts\nimport { extract as runExtract } from \"../../inference.js\";\nimport {\n getZFactory,"
},
{
"path": "packages/core/lib/v3/handlers/handlerUtils/actHandlerUtils.ts",
"chars": 20645,
"preview": "// lib/v3/handlers/handlerUtils/actHandlerUtils.ts\nimport { Protocol } from \"devtools-protocol\";\nimport { Frame } from \""
},
{
"path": "packages/core/lib/v3/handlers/handlerUtils/timeoutGuard.ts",
"chars": 515,
"preview": "import { TimeoutError } from \"../../types/public/sdkErrors.js\";\n\nexport type TimeoutGuard = () => void;\n\nexport function"
},
{
"path": "packages/core/lib/v3/handlers/observeHandler.ts",
"chars": 8037,
"preview": "// lib/v3/handlers/observeHandler.ts\nimport { observe as runObserve } from \"../../inference.js\";\nimport { trimTrailingTe"
},
{
"path": "packages/core/lib/v3/handlers/v3AgentHandler.ts",
"chars": 22059,
"preview": "import { createAgentTools } from \"../agent/tools/index.js\";\nimport { buildAgentSystemPrompt } from \"../agent/prompts/age"
},
{
"path": "packages/core/lib/v3/handlers/v3CuaAgentHandler.ts",
"chars": 24709,
"preview": "import { computeActiveElementXpath } from \"../understudy/a11y/snapshot/index.js\";\nimport { V3 } from \"../v3.js\";\nimport "
},
{
"path": "packages/core/lib/v3/index.ts",
"chars": 3161,
"preview": "import * as PublicApi from \"./types/public/index.js\";\nimport { V3 } from \"./v3.js\";\nimport { AnnotatedScreenshotText, LL"
},
{
"path": "packages/core/lib/v3/launch/browserbase.ts",
"chars": 2452,
"preview": "import Browserbase from \"@browserbasehq/sdk\";\nimport {\n BrowserbaseSessionNotFoundError,\n StagehandInitError,\n} from \""
},
{
"path": "packages/core/lib/v3/launch/local.ts",
"chars": 3691,
"preview": "import { launch, LaunchedChrome } from \"chrome-launcher\";\nimport WebSocket from \"ws\";\nimport { ConnectionTimeoutError } "
},
{
"path": "packages/core/lib/v3/llm/AnthropicClient.ts",
"chars": 8196,
"preview": "import Anthropic, { ClientOptions } from \"@anthropic-ai/sdk\";\nimport {\n ImageBlockParam,\n MessageParam,\n TextBlockPar"
},
{
"path": "packages/core/lib/v3/llm/CerebrasClient.ts",
"chars": 8254,
"preview": "import OpenAI from \"openai\";\nimport type { ClientOptions } from \"openai\";\nimport { LogLine } from \"../types/public/logs."
},
{
"path": "packages/core/lib/v3/llm/GoogleClient.ts",
"chars": 13977,
"preview": "import {\n GoogleGenAI,\n HarmCategory,\n HarmBlockThreshold,\n Content,\n Part,\n Tool,\n FunctionCall,\n Schema,\n Typ"
},
{
"path": "packages/core/lib/v3/llm/GroqClient.ts",
"chars": 8241,
"preview": "import type { ClientOptions } from \"openai\";\nimport OpenAI from \"openai\";\nimport { LogLine } from \"../types/public/logs."
},
{
"path": "packages/core/lib/v3/llm/LLMClient.ts",
"chars": 4056,
"preview": "import { LLMTool } from \"../types/public/model.js\";\nimport {\n embed,\n embedMany,\n experimental_generateImage,\n exper"
},
{
"path": "packages/core/lib/v3/llm/LLMProvider.ts",
"chars": 7118,
"preview": "import {\n ExperimentalNotConfiguredError,\n UnsupportedAISDKModelProviderError,\n UnsupportedModelError,\n UnsupportedM"
},
{
"path": "packages/core/lib/v3/llm/OpenAIClient.ts",
"chars": 11899,
"preview": "import OpenAI, { ClientOptions } from \"openai\";\nimport {\n ChatCompletionAssistantMessageParam,\n ChatCompletionContentP"
},
{
"path": "packages/core/lib/v3/llm/aisdk.ts",
"chars": 12595,
"preview": "import {\n CoreAssistantMessage,\n ModelMessage,\n CoreSystemMessage,\n CoreUserMessage,\n generateObject,\n generateTex"
},
{
"path": "packages/core/lib/v3/logger.ts",
"chars": 3476,
"preview": "import type { LogLine } from \"./types/public/logs.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Sta"
},
{
"path": "packages/core/lib/v3/mcp/connection.ts",
"chars": 2363,
"preview": "import {\n Client,\n ClientOptions,\n} from \"@modelcontextprotocol/sdk/client/index.js\";\nimport {\n StreamableHTTPClientT"
},
{
"path": "packages/core/lib/v3/mcp/utils.ts",
"chars": 1262,
"preview": "import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { ToolSet } from \"ai\";\nimport { JsonSchema, j"
},
{
"path": "packages/core/lib/v3/runtimePaths.ts",
"chars": 3902,
"preview": "/**\n * Keep this file in sync with:\n * - /packages/core/lib/v3/runtimePaths.ts\n * - /packages/server-v3/scripts/runtimeP"
},
{
"path": "packages/core/lib/v3/shutdown/cleanupLocal.ts",
"chars": 909,
"preview": "import fs from \"node:fs\";\n\n/**\n * Shared cleanup logic for locally launched Chrome.\n *\n * Used by both `V3.close()` (nor"
},
{
"path": "packages/core/lib/v3/shutdown/supervisor.ts",
"chars": 6100,
"preview": "/**\n * Shutdown supervisor process.\n *\n * This process watches a stdin lifeline. When the parent dies, stdin closes\n * a"
},
{
"path": "packages/core/lib/v3/shutdown/supervisorClient.ts",
"chars": 3519,
"preview": "/**\n * Parent-side helper for spawning the shutdown supervisor process.\n *\n * The supervisor runs out-of-process and wat"
},
{
"path": "packages/core/lib/v3/timeoutConfig.ts",
"chars": 986,
"preview": "import { TimeoutError } from \"./types/public/sdkErrors.js\";\n\nexport function getEnvTimeoutMs(name: string): number | und"
},
{
"path": "packages/core/lib/v3/types/private/agent.ts",
"chars": 144,
"preview": "export interface ActionMappingOptions {\n toolCallName: string;\n toolResult: unknown;\n args: Record<string, unknown>;\n"
},
{
"path": "packages/core/lib/v3/types/private/api.ts",
"chars": 346,
"preview": "import type { Protocol } from \"devtools-protocol\";\n\nexport interface SerializableResponse {\n requestId: string;\n frame"
},
{
"path": "packages/core/lib/v3/types/private/cache.ts",
"chars": 3492,
"preview": "import type {\n ActOptions,\n ActResult,\n AvailableModel,\n Logger,\n AgentResult,\n Action,\n LoadState,\n} from \"../pu"
},
{
"path": "packages/core/lib/v3/types/private/evaluator.ts",
"chars": 1272,
"preview": "export type EvaluateOptions = {\n /** The question to ask about the task state */\n question: string;\n /** The answer t"
},
{
"path": "packages/core/lib/v3/types/private/handlers.ts",
"chars": 1139,
"preview": "import { Page } from \"../../understudy/page.js\";\nimport { ModelConfiguration } from \"../public/model.js\";\nimport type { "
},
{
"path": "packages/core/lib/v3/types/private/index.ts",
"chars": 207,
"preview": "export * from \"./api.js\";\nexport * from \"./handlers.js\";\nexport * from \"./internal.js\";\nexport * from \"./evaluator.js\";\n"
},
{
"path": "packages/core/lib/v3/types/private/internal.ts",
"chars": 1150,
"preview": "import Browserbase from \"@browserbasehq/sdk\";\nimport { LaunchedChrome } from \"chrome-launcher\";\n\nexport type InitState ="
},
{
"path": "packages/core/lib/v3/types/private/locator.ts",
"chars": 251,
"preview": "import { Buffer } from \"buffer\";\n\nexport interface NormalizedFilePayload {\n name: string;\n mimeType: string;\n buffer:"
},
{
"path": "packages/core/lib/v3/types/private/network.ts",
"chars": 1182,
"preview": "import { Protocol } from \"devtools-protocol\";\n\n/** Metadata tracked for each network request currently in-flight. */\nexp"
},
{
"path": "packages/core/lib/v3/types/private/shutdown.ts",
"chars": 503,
"preview": "/**\n * Internal-only types for the shutdown supervisor process.\n */\n\nexport type ShutdownSupervisorConfig =\n | {\n "
},
{
"path": "packages/core/lib/v3/types/private/shutdownErrors.ts",
"chars": 589,
"preview": "/**\n * Internal-only errors for the shutdown supervisor.\n */\n\nexport class ShutdownSupervisorError extends Error {\n con"
},
{
"path": "packages/core/lib/v3/types/private/snapshot.ts",
"chars": 3503,
"preview": "/**\n * Options that control how hybrid snapshots and targeted scopes are captured.\n */\nexport type SnapshotOptions = {\n "
}
]
// ... and 599 more files (download for full content)
About this extraction
This page contains the full source code of the browserbase/stagehand GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 799 files (4.9 MB), approximately 1.3M tokens, and a symbol index with 2353 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.