Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"description": "Example scripts for Stagehand",
"main": "./",
"type": "module",
"scripts": {
"build": "pnpm --filter @browserbasehq/stagehand run build",
"start": "pnpm run build && sh -c 'if [ -n \"$1\" ]; then tsx \"$1.ts\"; else tsx example.ts; fi' --"
Expand Down
53 changes: 25 additions & 28 deletions examples/v3_example.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
import { V3 } from "../lib/v3/v3";
import puppeteer from "puppeteer-core";

async function example(v3: V3) {
const puppeteerBrowser = await puppeteer.connect({
browserWSEndpoint: v3.connectURL(),
});
const puppeteerPages = await puppeteerBrowser.pages();
const v3 = new V3({
env: "LOCAL",
headless: false,
verbose: 0,
});
await v3.init();
const puppeteerBrowser = await puppeteer.connect({
browserWSEndpoint: v3.connectURL(),
});
const puppeteerPages = await puppeteerBrowser.pages();

const page = puppeteerPages[0];
const page = puppeteerPages[0];

await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/closed-shadow-root-in-oopif/",
);
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/closed-shadow-root-in-oopif/",
);

const observeResult = {
selector:
"xpath=/html/body/main/section/iframe/html/body/shadow-demo//div/button",
method: "click",
description: "nunya",
arguments: [""],
};
const observeResult = {
selector:
"xpath=/html/body/main/section/iframe/html/body/shadow-demo//div/button",
method: "click",
description: "nunya",
arguments: [""],
};

await new Promise((resolve) => setTimeout(resolve, 200));
await v3.act(observeResult, page);
}
await new Promise((resolve) => setTimeout(resolve, 200));
await v3.act(observeResult, page);

(async () => {
const v3 = new V3({
env: "LOCAL",
headless: false,
verbose: 0,
});
await v3.init();
await example(v3);
})();
await v3.close();
await puppeteerBrowser.close();
5 changes: 4 additions & 1 deletion lib/dom/genDomScripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
* We can't rely on the normal build process for stagehand, because we need our script content as a string so that the import *just works*
*/
import fs from "fs";
import path from "path";
import path, { dirname } from "path";
import { fileURLToPath } from "url";
import esbuild from "esbuild";

const __dirname = dirname(fileURLToPath(import.meta.url));

fs.mkdirSync(path.join(__dirname, "./build"), { recursive: true });

esbuild.buildSync({
Expand Down
1 change: 1 addition & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1028,4 +1028,5 @@ export * from "../types/stagehand";
export * from "../types/stagehandApiErrors";
export * from "../types/stagehandErrors";
export * from "./llm/LLMClient";
export * from "./v3/v3";
export { connectToMCPServer };
1 change: 0 additions & 1 deletion lib/llm/AnthropicClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export class AnthropicClient extends LLMClient {
private client: Anthropic;
private cache: LLMCache | undefined;
private enableCaching: boolean;
public clientOptions: ClientOptions;

constructor({
enableCaching = false,
Expand Down
1 change: 0 additions & 1 deletion lib/llm/CerebrasClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export class CerebrasClient extends LLMClient {
private client: OpenAI;
private cache: LLMCache | undefined;
private enableCaching: boolean;
public clientOptions: ClientOptions;
public hasVision = false;

constructor({
Expand Down
2 changes: 0 additions & 2 deletions lib/llm/GoogleClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ export class GoogleClient extends LLMClient {
private client: GoogleGenAI;
private cache: LLMCache | undefined;
private enableCaching: boolean;
public clientOptions: ClientOptions;
public hasVision: boolean;
private logger: (message: LogLine) => void;

constructor({
Expand Down
1 change: 0 additions & 1 deletion lib/llm/GroqClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export class GroqClient extends LLMClient {
private client: OpenAI;
private cache: LLMCache | undefined;
private enableCaching: boolean;
public clientOptions: ClientOptions;
public hasVision = false;

constructor({
Expand Down
1 change: 0 additions & 1 deletion lib/llm/OpenAIClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export class OpenAIClient extends LLMClient {
private client: OpenAI;
private cache: LLMCache | undefined;
private enableCaching: boolean;
public clientOptions: ClientOptions;

constructor({
enableCaching = false,
Expand Down
1 change: 1 addition & 0 deletions lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "@browserbasehq/stagehand-lib",
"version": "2.4.1",
"private": true,
"type": "module",
"description": "Core Stagehand library sources",
"main": "../dist/index.js",
"module": "../dist/index.js",
Expand Down
1 change: 1 addition & 0 deletions lib/v3/dom/build/scriptV3Content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const v3ScriptContent = "(()=>{function b(_={}){let S=n=>{let{hostToRoot:l}=n,m=t=>{let o=[];if(t instanceof Document)return t.documentElement&&o.push(t.documentElement),o;if(t instanceof ShadowRoot||t instanceof DocumentFragment)return o.push(...Array.from(t.children)),o;if(t instanceof Element){o.push(...Array.from(t.children));let a=t.shadowRoot;a&&o.push(...Array.from(a.children));let r=l.get(t);return r&&o.push(...Array.from(r.children)),o}return o},v=t=>{let o=[],a=[...m(t)];for(;a.length;){let r=a.shift();o.push(r),a.push(...m(r))}return o},y=t=>{let o=String(t||\"\").trim();if(!o)return null;let a=o.replace(/^xpath=/i,\"\"),r=[];{let e=0;for(;e<a.length;){let d=\"child\";a.startsWith(\"//\",e)?(d=\"desc\",e+=2):a[e]===\"/\"&&(d=\"child\",e+=1);let h=e;for(;e<a.length&&a[e]!==\"/\";)e++;let u=a.slice(h,e).trim();if(!u)continue;let p=u.match(/^(.*?)(\\[(\\d+)\\])?$/u),i=(p?.[1]??u).trim(),c=p?.[3]?Math.max(1,Number(p[3])):null,R=i===\"\"?\"*\":i.toLowerCase();r.push({axis:d,raw:u,tag:R,index:c})}}n.debug&&console.info(\"[v3-piercer][resolve] start\",{url:location.href,steps:r.map(e=>({axis:e.axis,raw:e.raw,tag:e.tag,index:e.index}))});let g=[document];for(let e of r){let d=e.index,h=null;for(let u of g){let p=e.axis===\"child\"?m(u):v(u),i=[];for(let c of p)(e.tag===\"*\"||c.localName===e.tag)&&i.push(c);if(n.debug&&console.info(\"[v3-piercer][resolve] step\",{axis:e.axis,tag:e.tag,index:d,poolCount:p.length,matchesCount:i.length}),!!i.length){if(d!=null){let c=d-1;h=c>=0&&c<i.length?i[c]:null}else h=i[0];if(h)break}}if(!h)return n.debug&&console.info(\"[v3-piercer][resolve] no-match\",{step:e.raw}),null;g=[h]}let E=g.length?g[0]:null;return n.debug&&console.info(\"[v3-piercer][resolve] done\",{found:!!E,tag:E?.localName??\"\"}),E};window.__stagehandV3__={getClosedRoot:t=>l.get(t),stats:()=>({installed:!0,url:location.href,isTop:window.top===window,open:n.openCount,closed:n.closedCount}),resolveSimpleXPath:y}},f=Element.prototype.attachShadow;if(f.__v3Patched&&f.__v3State){f.__v3State.debug=!0,S(f.__v3State);return}let s={hostToRoot:new WeakMap,openCount:0,closedCount:0,debug:!0},x=f,w=function(n){let l=n?.mode??\"open\",m=x.call(this,n);try{s.hostToRoot.set(this,m),l===\"closed\"?s.closedCount++:s.openCount++,s.debug&&console.info(\"[v3-piercer] attachShadow\",{tag:this.tagName?.toLowerCase()??\"\",mode:l,url:location.href})}catch{}return m};if(w.__v3Patched=!0,w.__v3State=s,Object.defineProperty(Element.prototype,\"attachShadow\",{configurable:!0,writable:!0,value:w}),_.tagExisting)try{let n=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT);for(;n.nextNode();){let l=n.currentNode;l.shadowRoot&&(s.hostToRoot.set(l,l.shadowRoot),s.openCount++)}}catch{}window.__stagehandV3Injected=!0,S(s),s.debug&&console.info(\"[v3-piercer] installed\",{url:location.href,isTop:window.top===window,readyState:document.readyState})}b({debug:!0,tagExisting:!1});})();\n";
1 change: 1 addition & 0 deletions lib/v3/dom/build/v3-index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion lib/v3/dom/genDomScripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
* as a string constant (`v3ScriptContent`) for CDP injection (document-start).
*/
import fs from "node:fs";
import path from "node:path";
import path, { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import esbuild from "esbuild";

const __dirname = dirname(fileURLToPath(import.meta.url));
const here = __dirname;
const outDir = path.join(here, "./build");
fs.mkdirSync(outDir, { recursive: true });
Expand Down
12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
{
"name": "@browserbasehq/stagehand",
"version": "2.5.0",
"type": "module",
"description": "An AI web browsing framework focused on simplicity and extensibility.",
"main": "./dist/index.js",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"bin": {
"evals": "./dist/evals/cli.js"
},
Expand All @@ -24,7 +32,7 @@
"build-v3-dom-scripts": "tsx lib/v3/dom/genDomScripts.ts",
"build-dom-scripts": "tsx lib/dom/genDomScripts.ts",
"build-types": "tsc --emitDeclarationOnly --outDir dist",
"build-js": "tsup lib/index.ts --dts",
"build-js": "tsup lib/index.ts --format esm,cjs --dts --target es2022",
"build:cli": "tsup evals/cli.ts --outDir dist/evals --format cjs && cp evals/evals.config.json dist/evals/ && chmod +x dist/evals/cli.js && npm link",
"build": "pnpm run lint && pnpm run gen-version && pnpm run build-dom-scripts && pnpm run build-v3-dom-scripts && pnpm run build-js && pnpm run build-types",
"gen-version": "tsx scripts/gen-version.ts",
Expand Down
4 changes: 3 additions & 1 deletion scripts/gen-version.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";

type PackageJson = { version: string };

const __dirname = dirname(fileURLToPath(import.meta.url));
const pkgPath = join(__dirname, "..", "package.json");
const pkg: PackageJson = JSON.parse(readFileSync(pkgPath, "utf8"));

Expand Down
31 changes: 31 additions & 0 deletions tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"target": "ES2022",
"moduleResolution": "bundler",
"outDir": "dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"allowImportingTsExtensions": false,
"noEmit": true
},
"include": [
"lib/**/*",
"types/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.test.ts",
"**/*.spec.ts",
"evals/**/*",
"examples/**/*"
]
}
6 changes: 3 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"compilerOptions": {
"module": "commonjs",
"module": "ES2022",
"moduleResolution": "Node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "es6",
"target": "ES2022",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
Expand Down
Loading