diff --git a/lib/index.ts b/lib/index.ts index 5502e8528..d5e97cd86 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -76,6 +76,7 @@ async function getBrowser( browserbaseSessionCreateParams?: Browserbase.Sessions.SessionCreateParams, browserbaseSessionID?: string, localBrowserLaunchOptions?: LocalBrowserLaunchOptions, + attachToLocalBrowser?: BrowserContext, ): Promise { if (env === "BROWSERBASE") { if (!apiKey) { @@ -95,7 +96,6 @@ async function getBrowser( let sessionUrl: string | undefined = undefined; let sessionId: string; let connectUrl: string; - const browserbase = new Browserbase({ apiKey, }); @@ -226,6 +226,16 @@ async function getBrowser( return { browser, context, debugUrl, sessionUrl, sessionId, env }; } else { + if (attachToLocalBrowser) { + logger({ + category: "init", + message: "attaching to existing local browser context", + level: 1, + }); + const context = attachToLocalBrowser; + const browser = context.browser(); + return { browser, context, env }; + } if (localBrowserLaunchOptions?.cdpUrl) { if (!localBrowserLaunchOptions.cdpUrl.includes("connect.connect")) { logger({ @@ -240,7 +250,6 @@ async function getBrowser( }, }); } - const browser = await chromium.connectOverCDP( localBrowserLaunchOptions.cdpUrl, ); @@ -387,6 +396,7 @@ export class Stagehand { public apiClient: StagehandAPI | undefined; public readonly waitForCaptchaSolves: boolean; private localBrowserLaunchOptions?: LocalBrowserLaunchOptions; + private attachToLocalBrowser?: BrowserContext; public readonly selfHeal: boolean; private cleanupCalled = false; public readonly actTimeoutMs: number; @@ -528,6 +538,7 @@ export class Stagehand { systemPrompt, useAPI = true, localBrowserLaunchOptions, + attachToLocalBrowser, waitForCaptchaSolves = false, logInferenceToFile = false, selfHeal = false, @@ -616,8 +627,7 @@ export class Stagehand { this.llmClient = llmClient; this.logger({ category: "init", - message: - "Custom LLM clients are currently not supported in API mode", + message: "Custom LLM clients are currently not supported in API mode", level: 1, }); this.usingAPI = false; @@ -660,7 +670,7 @@ export class Stagehand { } this.waitForCaptchaSolves = waitForCaptchaSolves; this.localBrowserLaunchOptions = localBrowserLaunchOptions; - + this.attachToLocalBrowser = attachToLocalBrowser; if (this.usingAPI) { this.registerSignalHandlers(); } @@ -786,6 +796,7 @@ export class Stagehand { this.browserbaseSessionCreateParams, this.browserbaseSessionID, this.localBrowserLaunchOptions, + this.attachToLocalBrowser, ).catch((e) => { this.stagehandLogger.error("Error in init:", { error: String(e) }); const br: BrowserResult = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b81dabcd6..035dfa4dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -204,6 +204,9 @@ importers: specifier: workspace:* version: link:.. devDependencies: + jszip: + specifier: ^3.10.1 + version: 3.10.1 tsx: specifier: ^4.10.5 version: 4.19.4 @@ -3153,6 +3156,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} @@ -3464,6 +3470,9 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + jwa@2.0.0: resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} @@ -3504,6 +3513,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -4109,6 +4121,9 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4560,6 +4575,9 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -8825,6 +8843,8 @@ snapshots: ignore@5.3.2: {} + immediate@3.0.6: {} + immer@9.0.21: {} import-fresh@3.3.1: @@ -9111,6 +9131,13 @@ snapshots: jsonpointer@5.0.1: {} + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + jwa@2.0.0: dependencies: buffer-equal-constant-time: 1.0.1 @@ -9157,6 +9184,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lilconfig@3.1.3: {} linear-sum-assignment@1.0.7: @@ -10068,6 +10099,8 @@ snapshots: dependencies: quansync: 0.2.10 + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -10694,6 +10727,8 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 + setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} sharp@0.33.5: diff --git a/types/stagehand.ts b/types/stagehand.ts index 706a45a3b..14e24ed3d 100644 --- a/types/stagehand.ts +++ b/types/stagehand.ts @@ -4,7 +4,7 @@ import { LLMProvider } from "../lib/llm/LLMProvider"; import { LogLine } from "./log"; import { AvailableModel, ClientOptions } from "./model"; import { LLMClient } from "../lib/llm/LLMClient"; -import { Cookie } from "playwright"; +import { Cookie, BrowserContext } from "playwright"; import { AgentProviderType } from "./agent"; export interface ConstructorParams { @@ -87,6 +87,10 @@ export interface ConstructorParams { * The parameters to use for launching a local browser */ localBrowserLaunchOptions?: LocalBrowserLaunchOptions; + /** + * Attach to an existing Playwright browser context instead of creating a new one + */ + attachToLocalBrowser?: BrowserContext; /** * Log the inference to a file */