@crawlee/stagehand 4.0.0-beta.210 → 4.0.0-beta.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/internals/stagehand-controller.d.ts +0 -14
- package/internals/stagehand-controller.js +4 -4
- package/internals/stagehand-crawler.d.ts +0 -14
- package/internals/stagehand-crawler.js +4 -4
- package/internals/stagehand-plugin.d.ts +0 -8
- package/internals/stagehand-plugin.js +4 -4
- package/package.json +7 -7
|
@@ -29,20 +29,6 @@ export declare class StagehandController extends BrowserController<BrowserType,
|
|
|
29
29
|
* We use Playwright's browser API directly since we connected via CDP.
|
|
30
30
|
*/
|
|
31
31
|
protected _newPage(_contextOptions?: unknown): Promise<Page>;
|
|
32
|
-
/**
|
|
33
|
-
* Waits until Stagehand knows about the page, so that `act()`/`extract()`/`observe()` can resolve it.
|
|
34
|
-
*
|
|
35
|
-
* Stagehand only learns about pages from CDP `Target.attachedToTarget` events on its own connection,
|
|
36
|
-
* and it maps them by main frame id. We create pages through a separate `connectOverCDP()` handle, so
|
|
37
|
-
* `context.newPage()` resolves before Stagehand has processed that event — the page is unresolvable for
|
|
38
|
-
* a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
|
|
39
|
-
* Stagehand's own `newPage()` polls for the same reason.
|
|
40
|
-
*/
|
|
41
|
-
private waitForStagehandToRegisterPage;
|
|
42
|
-
/**
|
|
43
|
-
* Reads the page's main frame id, which is the key Stagehand resolves pages by.
|
|
44
|
-
*/
|
|
45
|
-
private getMainFrameId;
|
|
46
32
|
/**
|
|
47
33
|
* Normalizes proxy options for Playwright.
|
|
48
34
|
*/
|
|
@@ -54,7 +54,7 @@ class StagehandController extends browser_pool_1.BrowserController {
|
|
|
54
54
|
this.registerPageClosed(page);
|
|
55
55
|
});
|
|
56
56
|
try {
|
|
57
|
-
await this
|
|
57
|
+
await this.#waitForStagehandToRegisterPage(page);
|
|
58
58
|
}
|
|
59
59
|
catch (error) {
|
|
60
60
|
await page.close().catch(() => { });
|
|
@@ -77,9 +77,9 @@ class StagehandController extends browser_pool_1.BrowserController {
|
|
|
77
77
|
* a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
|
|
78
78
|
* Stagehand's own `newPage()` polls for the same reason.
|
|
79
79
|
*/
|
|
80
|
-
async waitForStagehandToRegisterPage(page, timeoutMs = 10_000) {
|
|
80
|
+
async #waitForStagehandToRegisterPage(page, timeoutMs = 10_000) {
|
|
81
81
|
const stagehand = this.getStagehand();
|
|
82
|
-
const mainFrameId = await this
|
|
82
|
+
const mainFrameId = await this.#getMainFrameId(page);
|
|
83
83
|
const deadline = Date.now() + timeoutMs;
|
|
84
84
|
while (Date.now() < deadline) {
|
|
85
85
|
if (stagehand.context.resolvePageByMainFrameId(mainFrameId)) {
|
|
@@ -94,7 +94,7 @@ class StagehandController extends browser_pool_1.BrowserController {
|
|
|
94
94
|
/**
|
|
95
95
|
* Reads the page's main frame id, which is the key Stagehand resolves pages by.
|
|
96
96
|
*/
|
|
97
|
-
async getMainFrameId(page) {
|
|
97
|
+
async #getMainFrameId(page) {
|
|
98
98
|
const cdpSession = await page.context().newCDPSession(page);
|
|
99
99
|
try {
|
|
100
100
|
const { frameTree } = await cdpSession.send('Page.getFrameTree');
|
|
@@ -440,20 +440,6 @@ export declare class StagehandCrawler<ContextExtension = Dictionary<never>, Exte
|
|
|
440
440
|
* @param options - Crawler configuration options
|
|
441
441
|
*/
|
|
442
442
|
constructor(options?: StagehandCrawlerOptions<ContextExtension, ExtendedContext, Routes, StatisticStateExtension>);
|
|
443
|
-
/**
|
|
444
|
-
* Resolves the {@link StagehandController} that owns the given page, or
|
|
445
|
-
* `undefined` when the pool does not expose controllers (e.g. a custom
|
|
446
|
-
* {@link IBrowserPool} implementation).
|
|
447
|
-
*
|
|
448
|
-
* Stagehand needs direct controller access to reach the `Stagehand`
|
|
449
|
-
* instance bound to the page's browser, which is why it reaches past the
|
|
450
|
-
* {@link IBrowserPool} abstraction here.
|
|
451
|
-
*/
|
|
452
|
-
private getBrowserControllerByPage;
|
|
453
|
-
/**
|
|
454
|
-
* Enhance the page with Stagehand AI methods.
|
|
455
|
-
*/
|
|
456
|
-
private setUpStagehand;
|
|
457
443
|
/**
|
|
458
444
|
* Navigation handler for Stagehand crawler.
|
|
459
445
|
* Uses standard Playwright navigation.
|
|
@@ -107,7 +107,7 @@ class StagehandCrawler extends browser_1.BrowserCrawler {
|
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
#buildContextPipeline() {
|
|
110
|
-
return this.buildContextPipeline().compose(this
|
|
110
|
+
return this.buildContextPipeline().compose(this.#setUpStagehand.bind(this));
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
113
|
* Resolves the {@link StagehandController} that owns the given page, or
|
|
@@ -118,7 +118,7 @@ class StagehandCrawler extends browser_1.BrowserCrawler {
|
|
|
118
118
|
* instance bound to the page's browser, which is why it reaches past the
|
|
119
119
|
* {@link IBrowserPool} abstraction here.
|
|
120
120
|
*/
|
|
121
|
-
getBrowserControllerByPage(page) {
|
|
121
|
+
#getBrowserControllerByPage(page) {
|
|
122
122
|
if ('getBrowserControllerByPage' in this.browserPool) {
|
|
123
123
|
return this.browserPool.getBrowserControllerByPage(page);
|
|
124
124
|
}
|
|
@@ -127,8 +127,8 @@ class StagehandCrawler extends browser_1.BrowserCrawler {
|
|
|
127
127
|
/**
|
|
128
128
|
* Enhance the page with Stagehand AI methods.
|
|
129
129
|
*/
|
|
130
|
-
async setUpStagehand(crawlingContext) {
|
|
131
|
-
const controller = this
|
|
130
|
+
async #setUpStagehand(crawlingContext) {
|
|
131
|
+
const controller = this.#getBrowserControllerByPage(crawlingContext.page);
|
|
132
132
|
if (!controller) {
|
|
133
133
|
throw new Error('Could not resolve StagehandController for page — is the browser pool configured correctly?');
|
|
134
134
|
}
|
|
@@ -32,10 +32,6 @@ export declare class StagehandPlugin extends BrowserPlugin<BrowserType, LaunchOp
|
|
|
32
32
|
* Launches a browser using Stagehand and connects Playwright to it via CDP.
|
|
33
33
|
*/
|
|
34
34
|
protected _launch(launchContext: LaunchContext<BrowserType>): Promise<PlaywrightBrowser>;
|
|
35
|
-
/**
|
|
36
|
-
* Cleans up Stagehand instance when browser disconnects.
|
|
37
|
-
*/
|
|
38
|
-
private cleanupStagehand;
|
|
39
35
|
/**
|
|
40
36
|
* Creates a controller for the Stagehand browser.
|
|
41
37
|
*/
|
|
@@ -48,8 +44,4 @@ export declare class StagehandPlugin extends BrowserPlugin<BrowserType, LaunchOp
|
|
|
48
44
|
* Determines if this is a Chromium-based browser.
|
|
49
45
|
*/
|
|
50
46
|
protected isChromiumBasedBrowser(): boolean;
|
|
51
|
-
/**
|
|
52
|
-
* Augments launch errors with helpful context.
|
|
53
|
-
*/
|
|
54
|
-
private augmentLaunchError;
|
|
55
47
|
}
|
|
@@ -79,7 +79,7 @@ class StagehandPlugin extends browser_pool_1.BrowserPlugin {
|
|
|
79
79
|
this.#stagehandInstances.set(browser, stagehand);
|
|
80
80
|
// Handle browser disconnection - cleanup both Stagehand and anonymized proxy
|
|
81
81
|
browser.on('disconnected', async () => {
|
|
82
|
-
await this
|
|
82
|
+
await this.#cleanupStagehand(browser);
|
|
83
83
|
await closeAnonymizedProxy();
|
|
84
84
|
});
|
|
85
85
|
return browser;
|
|
@@ -88,7 +88,7 @@ class StagehandPlugin extends browser_pool_1.BrowserPlugin {
|
|
|
88
88
|
// Clean up on failure
|
|
89
89
|
await stagehand.close().catch(() => { });
|
|
90
90
|
await closeAnonymizedProxy();
|
|
91
|
-
const augmentedError = this
|
|
91
|
+
const augmentedError = this.#augmentLaunchError(error, launchContext);
|
|
92
92
|
core_1.serviceLocator.getLogger().error('Stagehand browser launch failed', { message: augmentedError.message });
|
|
93
93
|
throw augmentedError;
|
|
94
94
|
}
|
|
@@ -96,7 +96,7 @@ class StagehandPlugin extends browser_pool_1.BrowserPlugin {
|
|
|
96
96
|
/**
|
|
97
97
|
* Cleans up Stagehand instance when browser disconnects.
|
|
98
98
|
*/
|
|
99
|
-
async cleanupStagehand(browser) {
|
|
99
|
+
async #cleanupStagehand(browser) {
|
|
100
100
|
const stagehand = this.#stagehandInstances.get(browser);
|
|
101
101
|
if (stagehand) {
|
|
102
102
|
try {
|
|
@@ -139,7 +139,7 @@ class StagehandPlugin extends browser_pool_1.BrowserPlugin {
|
|
|
139
139
|
/**
|
|
140
140
|
* Augments launch errors with helpful context.
|
|
141
141
|
*/
|
|
142
|
-
augmentLaunchError(error, launchContext) {
|
|
142
|
+
#augmentLaunchError(error, launchContext) {
|
|
143
143
|
const message = error instanceof Error ? error.message : String(error);
|
|
144
144
|
const model = this.#stagehandOptions.model;
|
|
145
145
|
let helpText = '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/stagehand",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.212",
|
|
4
4
|
"description": "AI-powered web crawling with Stagehand integration for Crawlee - enables natural language browser automation with act(), extract(), and observe() methods.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@apify/timeout": "^1.0.1",
|
|
60
|
-
"@crawlee/browser": "4.0.0-beta.
|
|
61
|
-
"@crawlee/browser-pool": "4.0.0-beta.
|
|
62
|
-
"@crawlee/core": "4.0.0-beta.
|
|
63
|
-
"@crawlee/types": "4.0.0-beta.
|
|
64
|
-
"@crawlee/utils": "4.0.0-beta.
|
|
60
|
+
"@crawlee/browser": "4.0.0-beta.212",
|
|
61
|
+
"@crawlee/browser-pool": "4.0.0-beta.212",
|
|
62
|
+
"@crawlee/core": "4.0.0-beta.212",
|
|
63
|
+
"@crawlee/types": "4.0.0-beta.212",
|
|
64
|
+
"@crawlee/utils": "4.0.0-beta.212",
|
|
65
65
|
"tslib": "^2.8.1",
|
|
66
66
|
"zod": "^4.5.4"
|
|
67
67
|
},
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "171a63a5d7f2a6d74cbce58479204ac20d30b87e"
|
|
92
92
|
}
|