@browserbasehq/stagehand
Advanced tools
Comparing version 1.12.1-alpha-8a89d7d0f618d4bbad992d07db022dc73ffb4eb0 to 1.12.1-alpha-e10282adf695ca8d12c1aa9839b0103afc8c89e4
@@ -209,2 +209,3 @@ import { z, ZodType } from 'zod'; | ||
useAccessibilityTree?: boolean; | ||
drawOverlay?: boolean; | ||
} | ||
@@ -211,0 +212,0 @@ interface ObserveResult { |
@@ -18,3 +18,3 @@ import { LogLine } from "../../types/log"; | ||
private _recordObservation; | ||
observe({ instruction, llmClient, requestId, returnAction, onlyVisible, }: { | ||
observe({ instruction, llmClient, requestId, returnAction, onlyVisible, drawOverlay, }: { | ||
instruction: string; | ||
@@ -26,2 +26,3 @@ llmClient: LLMClient; | ||
onlyVisible?: boolean; | ||
drawOverlay?: boolean; | ||
}): Promise<({ | ||
@@ -28,0 +29,0 @@ selector: string; |
@@ -23,4 +23,4 @@ import { z } from "zod"; | ||
metadata: { | ||
completed?: boolean; | ||
progress?: string; | ||
completed?: boolean; | ||
}; | ||
@@ -27,0 +27,0 @@ }>; |
@@ -0,4 +1,5 @@ | ||
import { z } from "zod"; | ||
import { ObserveResult, Page } from "."; | ||
import { LogLine } from "../types/log"; | ||
import { TextAnnotation } from "../types/textannotation"; | ||
import { z } from "zod"; | ||
export declare function generateId(operation: string): string; | ||
@@ -23,1 +24,3 @@ /** | ||
export declare function validateZodSchema(schema: z.ZodTypeAny, data: unknown): boolean; | ||
export declare function drawObserveOverlay(page: Page, results: ObserveResult[]): Promise<void>; | ||
export declare function clearOverlays(page: Page): Promise<void>; |
@@ -86,2 +86,3 @@ import Browserbase from "@browserbasehq/sdk"; | ||
useAccessibilityTree?: boolean; | ||
drawOverlay?: boolean; | ||
} | ||
@@ -88,0 +89,0 @@ export interface ObserveResult { |
@@ -6,3 +6,3 @@ import { LogLine } from "../../types/log"; | ||
import { StagehandPage } from "../StagehandPage"; | ||
import { generateId } from "../utils"; | ||
import { generateId, drawObserveOverlay } from "../utils"; | ||
import { | ||
@@ -59,2 +59,3 @@ getAccessibilityTree, | ||
onlyVisible, | ||
drawOverlay, | ||
}: { | ||
@@ -67,2 +68,3 @@ instruction: string; | ||
onlyVisible?: boolean; | ||
drawOverlay?: boolean; | ||
}) { | ||
@@ -72,2 +74,3 @@ if (!instruction) { | ||
} | ||
this.logger({ | ||
@@ -115,3 +118,2 @@ category: "observation", | ||
}); | ||
const elementsWithSelectors = await Promise.all( | ||
@@ -190,2 +192,6 @@ observationResponse.elements.map(async (element) => { | ||
if (drawOverlay) { | ||
await drawObserveOverlay(this.stagehandPage.page, elementsWithSelectors); | ||
} | ||
await this._recordObservation(instruction, elementsWithSelectors); | ||
@@ -192,0 +198,0 @@ return elementsWithSelectors; |
@@ -20,2 +20,3 @@ import type { | ||
import { StagehandObserveHandler } from "./handlers/observeHandler"; | ||
import { clearOverlays } from "./utils"; | ||
@@ -296,2 +297,4 @@ export class StagehandPage { | ||
await clearOverlays(this.page); | ||
// If actionOrOptions is an ObserveResult, we call actFromObserveResult. | ||
@@ -413,2 +416,4 @@ // We need to ensure there is both a selector and a method in the ObserveResult. | ||
await clearOverlays(this.page); | ||
const options: ExtractOptions<T> = | ||
@@ -497,2 +502,4 @@ typeof instructionOrOptions === "string" | ||
await clearOverlays(this.page); | ||
const options: ObserveOptions = | ||
@@ -512,2 +519,3 @@ typeof instructionOrOptions === "string" | ||
useAccessibilityTree, | ||
drawOverlay, | ||
} = options; | ||
@@ -576,2 +584,3 @@ | ||
onlyVisible, | ||
drawOverlay, | ||
}) | ||
@@ -578,0 +587,0 @@ .catch((e) => { |
import crypto from "crypto"; | ||
import { z } from "zod"; | ||
import { ObserveResult, Page } from "."; | ||
import { LogLine } from "../types/log"; | ||
import { TextAnnotation } from "../types/textannotation"; | ||
import { z } from "zod"; | ||
@@ -377,1 +378,56 @@ // This is a heuristic for the width of a character in pixels. It seems to work | ||
} | ||
export async function drawObserveOverlay(page: Page, results: ObserveResult[]) { | ||
// Convert single xpath to array for consistent handling | ||
const xpathList = results.map((result) => result.selector); | ||
// Filter out empty xpaths | ||
const validXpaths = xpathList.filter((xpath) => xpath !== "xpath="); | ||
await page.evaluate((selectors) => { | ||
selectors.forEach((selector) => { | ||
let element; | ||
if (selector.startsWith("xpath=")) { | ||
const xpath = selector.substring(6); | ||
element = document.evaluate( | ||
xpath, | ||
document, | ||
null, | ||
XPathResult.FIRST_ORDERED_NODE_TYPE, | ||
null, | ||
).singleNodeValue; | ||
} else { | ||
element = document.querySelector(selector); | ||
} | ||
if (element instanceof HTMLElement) { | ||
const overlay = document.createElement("div"); | ||
overlay.setAttribute("stagehandObserve", "true"); | ||
const rect = element.getBoundingClientRect(); | ||
overlay.style.position = "absolute"; | ||
overlay.style.left = rect.left + "px"; | ||
overlay.style.top = rect.top + "px"; | ||
overlay.style.width = rect.width + "px"; | ||
overlay.style.height = rect.height + "px"; | ||
overlay.style.backgroundColor = "rgba(255, 255, 0, 0.3)"; | ||
overlay.style.pointerEvents = "none"; | ||
overlay.style.zIndex = "10000"; | ||
document.body.appendChild(overlay); | ||
} | ||
}); | ||
}, validXpaths); | ||
} | ||
export async function clearOverlays(page: Page) { | ||
// remove existing stagehandObserve attributes | ||
await page.evaluate(() => { | ||
const elements = document.querySelectorAll('[stagehandObserve="true"]'); | ||
elements.forEach((el) => { | ||
const parent = el.parentNode; | ||
while (el.firstChild) { | ||
parent?.insertBefore(el.firstChild, el); | ||
} | ||
parent?.removeChild(el); | ||
}); | ||
}); | ||
} |
{ | ||
"name": "@browserbasehq/stagehand", | ||
"version": "1.12.1-alpha-8a89d7d0f618d4bbad992d07db022dc73ffb4eb0", | ||
"version": "1.12.1-alpha-e10282adf695ca8d12c1aa9839b0103afc8c89e4", | ||
"description": "An AI web browsing framework focused on simplicity and extensibility.", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
@@ -58,2 +58,5 @@ <div id="toc" align="center"> | ||
> [!WARNING] | ||
> We highly recommend using the Node.js runtime environment to run Stagehand scripts, as opposed to newer alternatives like Bun. This is solely due to the fact that [Bun's runtime is not yet fully compatible with Playwright](https://github.com/microsoft/playwright/issues/27139). | ||
## Why? | ||
@@ -60,0 +63,0 @@ **Stagehand adds determinism to otherwise unpredictable agents.** |
Sorry, the diff of this file is too big to display
612654
16033
144