@crawlee/stagehand 3.17.1-beta.55 → 3.17.1-beta.56

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.
@@ -30,6 +30,20 @@ export declare class StagehandController extends BrowserController<BrowserType,
30
30
  * We use Playwright's browser API directly since we connected via CDP.
31
31
  */
32
32
  protected _newPage(_contextOptions?: unknown): Promise<Page>;
33
+ /**
34
+ * Waits until Stagehand knows about the page, so that `act()`/`extract()`/`observe()` can resolve it.
35
+ *
36
+ * Stagehand only learns about pages from CDP `Target.attachedToTarget` events on its own connection,
37
+ * and it maps them by main frame id. We create pages through a separate `connectOverCDP()` handle, so
38
+ * `context.newPage()` resolves before Stagehand has processed that event — the page is unresolvable for
39
+ * a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
40
+ * Stagehand's own `newPage()` polls for the same reason.
41
+ */
42
+ private waitForStagehandToRegisterPage;
43
+ /**
44
+ * Reads the page's main frame id, which is the key Stagehand resolves pages by.
45
+ */
46
+ private getMainFrameId;
33
47
  /**
34
48
  * Normalizes proxy options for Playwright.
35
49
  */
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StagehandController = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const browser_pool_1 = require("@crawlee/browser-pool");
6
+ const utils_1 = require("@crawlee/utils");
6
7
  const log_1 = tslib_1.__importDefault(require("@apify/log"));
7
8
  /**
8
9
  * StagehandController manages the lifecycle of a Stagehand-controlled browser for Crawlee's BrowserPool.
@@ -63,6 +64,13 @@ class StagehandController extends browser_pool_1.BrowserController {
63
64
  page.once('close', () => {
64
65
  this.activePages--;
65
66
  });
67
+ try {
68
+ await this.waitForStagehandToRegisterPage(page);
69
+ }
70
+ catch (error) {
71
+ await page.close().catch(() => { });
72
+ throw error;
73
+ }
66
74
  return page;
67
75
  }
68
76
  catch (error) {
@@ -71,6 +79,42 @@ class StagehandController extends browser_pool_1.BrowserController {
71
79
  });
72
80
  }
73
81
  }
82
+ /**
83
+ * Waits until Stagehand knows about the page, so that `act()`/`extract()`/`observe()` can resolve it.
84
+ *
85
+ * Stagehand only learns about pages from CDP `Target.attachedToTarget` events on its own connection,
86
+ * and it maps them by main frame id. We create pages through a separate `connectOverCDP()` handle, so
87
+ * `context.newPage()` resolves before Stagehand has processed that event — the page is unresolvable for
88
+ * a short window, and the AI methods fail with 'Failed to resolve V3 Page from Playwright page'.
89
+ * Stagehand's own `newPage()` polls for the same reason.
90
+ */
91
+ async waitForStagehandToRegisterPage(page, timeoutMs = 10000) {
92
+ const stagehand = this.getStagehand();
93
+ const mainFrameId = await this.getMainFrameId(page);
94
+ const deadline = Date.now() + timeoutMs;
95
+ while (Date.now() < deadline) {
96
+ if (stagehand.context.resolvePageByMainFrameId(mainFrameId)) {
97
+ return;
98
+ }
99
+ await (0, utils_1.sleep)(25);
100
+ }
101
+ // Stagehand skips registration entirely when it cannot install its helper script into the page's CDP
102
+ // session, so this is not always just a slow attach - it can never resolve.
103
+ throw new Error(`Stagehand did not register the page within ${timeoutMs}ms`);
104
+ }
105
+ /**
106
+ * Reads the page's main frame id, which is the key Stagehand resolves pages by.
107
+ */
108
+ async getMainFrameId(page) {
109
+ const cdpSession = await page.context().newCDPSession(page);
110
+ try {
111
+ const { frameTree } = await cdpSession.send('Page.getFrameTree');
112
+ return frameTree.frame.id;
113
+ }
114
+ finally {
115
+ await cdpSession.detach().catch(() => { });
116
+ }
117
+ }
74
118
  /**
75
119
  * Normalizes proxy options for Playwright.
76
120
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlee/stagehand",
3
- "version": "3.17.1-beta.55",
3
+ "version": "3.17.1-beta.56",
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": ">=16.0.0"
@@ -58,11 +58,11 @@
58
58
  "dependencies": {
59
59
  "@apify/log": "^2.4.0",
60
60
  "@apify/timeout": "^0.3.1",
61
- "@crawlee/browser": "3.17.1-beta.55",
62
- "@crawlee/browser-pool": "3.17.1-beta.55",
63
- "@crawlee/core": "3.17.1-beta.55",
64
- "@crawlee/types": "3.17.1-beta.55",
65
- "@crawlee/utils": "3.17.1-beta.55",
61
+ "@crawlee/browser": "3.17.1-beta.56",
62
+ "@crawlee/browser-pool": "3.17.1-beta.56",
63
+ "@crawlee/core": "3.17.1-beta.56",
64
+ "@crawlee/types": "3.17.1-beta.56",
65
+ "@crawlee/utils": "3.17.1-beta.56",
66
66
  "ow": "^0.28.1",
67
67
  "tslib": "^2.4.0"
68
68
  },
@@ -94,5 +94,5 @@
94
94
  }
95
95
  }
96
96
  },
97
- "gitHead": "93d29e305f01ca6ca9bb79264a5ca553b19766ef"
97
+ "gitHead": "aaf56f1d6905d06fe18a93bbd2d7695a581d57cf"
98
98
  }