@browserbasehq/orca 3.2.1-preview.2 → 3.4.0-preview-1

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.
Files changed (223) hide show
  1. package/dist/cjs/lib/inference.js +2 -9
  2. package/dist/cjs/lib/inference.js.map +1 -1
  3. package/dist/cjs/lib/prompt.js +3 -1
  4. package/dist/cjs/lib/prompt.js.map +1 -1
  5. package/dist/cjs/lib/v3/agent/AgentProvider.js +3 -0
  6. package/dist/cjs/lib/v3/agent/AgentProvider.js.map +1 -1
  7. package/dist/cjs/lib/v3/agent/tools/fillFormVision.js +16 -12
  8. package/dist/cjs/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  9. package/dist/cjs/lib/v3/agent/utils/validateExperimentalFeatures.js +0 -4
  10. package/dist/cjs/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -1
  11. package/dist/cjs/lib/v3/api.d.ts +1 -0
  12. package/dist/cjs/lib/v3/api.js +15 -3
  13. package/dist/cjs/lib/v3/api.js.map +1 -1
  14. package/dist/cjs/lib/v3/dom/build/a11yScripts.generated.js +1 -1
  15. package/dist/cjs/lib/v3/dom/build/a11yScripts.generated.js.map +1 -1
  16. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js +1 -1
  17. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
  18. package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -1
  19. package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.js +1 -1
  20. package/dist/cjs/lib/v3/dom/build/reRenderScriptContent.js.map +1 -1
  21. package/dist/cjs/lib/v3/dom/build/screenshotScripts.generated.js +1 -1
  22. package/dist/cjs/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -1
  23. package/dist/cjs/lib/v3/dom/build/scriptV3Content.d.ts +1 -1
  24. package/dist/cjs/lib/v3/dom/build/scriptV3Content.js +1 -1
  25. package/dist/cjs/lib/v3/dom/build/scriptV3Content.js.map +1 -1
  26. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
  27. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js +31 -0
  28. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
  29. package/dist/cjs/lib/v3/handlers/extractHandler.js +3 -1
  30. package/dist/cjs/lib/v3/handlers/extractHandler.js.map +1 -1
  31. package/dist/cjs/lib/v3/handlers/observeHandler.js +2 -1
  32. package/dist/cjs/lib/v3/handlers/observeHandler.js.map +1 -1
  33. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +3 -5
  34. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  35. package/dist/cjs/lib/v3/index.d.ts +1 -1
  36. package/dist/cjs/lib/v3/llm/CerebrasClient.js +1 -1
  37. package/dist/cjs/lib/v3/llm/CerebrasClient.js.map +1 -1
  38. package/dist/cjs/lib/v3/llm/GroqClient.js +1 -1
  39. package/dist/cjs/lib/v3/llm/GroqClient.js.map +1 -1
  40. package/dist/cjs/lib/v3/types/private/agent.d.ts +5 -0
  41. package/dist/cjs/lib/v3/types/private/agent.js +11 -0
  42. package/dist/cjs/lib/v3/types/private/agent.js.map +1 -1
  43. package/dist/cjs/lib/v3/types/private/handlers.d.ts +2 -0
  44. package/dist/cjs/lib/v3/types/private/handlers.js.map +1 -1
  45. package/dist/cjs/lib/v3/types/private/snapshot.d.ts +8 -0
  46. package/dist/cjs/lib/v3/types/private/snapshot.js.map +1 -1
  47. package/dist/cjs/lib/v3/types/public/agent.d.ts +2 -3
  48. package/dist/cjs/lib/v3/types/public/agent.js +3 -0
  49. package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
  50. package/dist/cjs/lib/v3/types/public/api.d.ts +7 -1
  51. package/dist/cjs/lib/v3/types/public/api.js +22 -2
  52. package/dist/cjs/lib/v3/types/public/api.js.map +1 -1
  53. package/dist/cjs/lib/v3/types/public/methods.d.ts +2 -0
  54. package/dist/cjs/lib/v3/types/public/methods.js.map +1 -1
  55. package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js +21 -12
  56. package/dist/cjs/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
  57. package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.d.ts +11 -2
  58. package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.js +268 -21
  59. package/dist/cjs/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -1
  60. package/dist/cjs/lib/v3/understudy/a11y/snapshot/domTree.js +60 -7
  61. package/dist/cjs/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -1
  62. package/dist/cjs/lib/v3/understudy/frameRegistry.js +16 -5
  63. package/dist/cjs/lib/v3/understudy/frameRegistry.js.map +1 -1
  64. package/dist/cjs/lib/v3/v3.d.ts +1 -0
  65. package/dist/cjs/lib/v3/v3.js +18 -14
  66. package/dist/cjs/lib/v3/v3.js.map +1 -1
  67. package/dist/cjs/lib/version.d.ts +1 -1
  68. package/dist/cjs/lib/version.js +1 -1
  69. package/dist/cjs/lib/version.js.map +1 -1
  70. package/dist/cjs/tests/integration/observe-element-id-format.spec.js +130 -0
  71. package/dist/cjs/tests/integration/observe-element-id-format.spec.js.map +1 -0
  72. package/dist/cjs/tests/unit/agent-mode-routing.test.js +88 -0
  73. package/dist/cjs/tests/unit/agent-mode-routing.test.js.map +1 -0
  74. package/dist/cjs/tests/unit/agent-temperature.test.d.ts +1 -0
  75. package/dist/cjs/tests/unit/agent-temperature.test.js +191 -0
  76. package/dist/cjs/tests/unit/agent-temperature.test.js.map +1 -0
  77. package/dist/cjs/tests/unit/agent-variables-validation.test.d.ts +1 -0
  78. package/dist/cjs/tests/unit/agent-variables-validation.test.js +43 -0
  79. package/dist/cjs/tests/unit/agent-variables-validation.test.js.map +1 -0
  80. package/dist/cjs/tests/unit/api-client-observe-variables.test.js +49 -0
  81. package/dist/cjs/tests/unit/api-client-observe-variables.test.js.map +1 -1
  82. package/dist/cjs/tests/unit/api-optional-model-api-key.test.js +60 -0
  83. package/dist/cjs/tests/unit/api-optional-model-api-key.test.js.map +1 -1
  84. package/dist/cjs/tests/unit/api-variables-schema.test.js +32 -0
  85. package/dist/cjs/tests/unit/api-variables-schema.test.js.map +1 -1
  86. package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.d.ts +1 -0
  87. package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.js +60 -0
  88. package/dist/cjs/tests/unit/frame-registry-oopif-adoption.test.js.map +1 -0
  89. package/dist/cjs/tests/unit/inference-temperature.test.d.ts +1 -0
  90. package/dist/cjs/tests/unit/inference-temperature.test.js +65 -0
  91. package/dist/cjs/tests/unit/inference-temperature.test.js.map +1 -0
  92. package/dist/cjs/tests/unit/openai-compatible-temperature.test.d.ts +1 -0
  93. package/dist/cjs/tests/unit/openai-compatible-temperature.test.js +84 -0
  94. package/dist/cjs/tests/unit/openai-compatible-temperature.test.js.map +1 -0
  95. package/dist/cjs/tests/unit/prompt-observe-variables.test.js +6 -0
  96. package/dist/cjs/tests/unit/prompt-observe-variables.test.js.map +1 -1
  97. package/dist/cjs/tests/unit/public-api/llm-and-agents.test.js +3 -0
  98. package/dist/cjs/tests/unit/public-api/llm-and-agents.test.js.map +1 -1
  99. package/dist/cjs/tests/unit/public-api/public-types.test.js.map +1 -1
  100. package/dist/cjs/tests/unit/snapshot-a11y-resolvers.test.js +106 -5
  101. package/dist/cjs/tests/unit/snapshot-a11y-resolvers.test.js.map +1 -1
  102. package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js +20 -0
  103. package/dist/cjs/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
  104. package/dist/cjs/tests/unit/snapshot-capture-orchestration.test.js +119 -9
  105. package/dist/cjs/tests/unit/snapshot-capture-orchestration.test.js.map +1 -1
  106. package/dist/cjs/tests/unit/timeout-handlers.test.js +36 -0
  107. package/dist/cjs/tests/unit/timeout-handlers.test.js.map +1 -1
  108. package/dist/esm/lib/inference.js +2 -9
  109. package/dist/esm/lib/inference.js.map +1 -1
  110. package/dist/esm/lib/prompt.js +3 -1
  111. package/dist/esm/lib/prompt.js.map +1 -1
  112. package/dist/esm/lib/v3/agent/AgentProvider.js +3 -0
  113. package/dist/esm/lib/v3/agent/AgentProvider.js.map +1 -1
  114. package/dist/esm/lib/v3/agent/tools/fillFormVision.js +16 -12
  115. package/dist/esm/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  116. package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js +0 -4
  117. package/dist/esm/lib/v3/agent/utils/validateExperimentalFeatures.js.map +1 -1
  118. package/dist/esm/lib/v3/api.d.ts +1 -0
  119. package/dist/esm/lib/v3/api.js +15 -3
  120. package/dist/esm/lib/v3/api.js.map +1 -1
  121. package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js +1 -1
  122. package/dist/esm/lib/v3/dom/build/a11yScripts.generated.js.map +1 -1
  123. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js +1 -1
  124. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
  125. package/dist/esm/lib/v3/dom/build/reRenderScriptContent.d.ts +1 -1
  126. package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js +1 -1
  127. package/dist/esm/lib/v3/dom/build/reRenderScriptContent.js.map +1 -1
  128. package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js +1 -1
  129. package/dist/esm/lib/v3/dom/build/screenshotScripts.generated.js.map +1 -1
  130. package/dist/esm/lib/v3/dom/build/scriptV3Content.d.ts +1 -1
  131. package/dist/esm/lib/v3/dom/build/scriptV3Content.js +1 -1
  132. package/dist/esm/lib/v3/dom/build/scriptV3Content.js.map +1 -1
  133. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
  134. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js +28 -0
  135. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
  136. package/dist/esm/lib/v3/handlers/extractHandler.js +3 -1
  137. package/dist/esm/lib/v3/handlers/extractHandler.js.map +1 -1
  138. package/dist/esm/lib/v3/handlers/observeHandler.js +2 -1
  139. package/dist/esm/lib/v3/handlers/observeHandler.js.map +1 -1
  140. package/dist/esm/lib/v3/handlers/v3AgentHandler.js +3 -5
  141. package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  142. package/dist/esm/lib/v3/index.d.ts +1 -1
  143. package/dist/esm/lib/v3/llm/CerebrasClient.js +1 -1
  144. package/dist/esm/lib/v3/llm/CerebrasClient.js.map +1 -1
  145. package/dist/esm/lib/v3/llm/GroqClient.js +1 -1
  146. package/dist/esm/lib/v3/llm/GroqClient.js.map +1 -1
  147. package/dist/esm/lib/v3/types/private/agent.d.ts +5 -0
  148. package/dist/esm/lib/v3/types/private/agent.js +10 -1
  149. package/dist/esm/lib/v3/types/private/agent.js.map +1 -1
  150. package/dist/esm/lib/v3/types/private/handlers.d.ts +2 -0
  151. package/dist/esm/lib/v3/types/private/handlers.js.map +1 -1
  152. package/dist/esm/lib/v3/types/private/snapshot.d.ts +8 -0
  153. package/dist/esm/lib/v3/types/private/snapshot.js.map +1 -1
  154. package/dist/esm/lib/v3/types/public/agent.d.ts +2 -3
  155. package/dist/esm/lib/v3/types/public/agent.js +3 -0
  156. package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
  157. package/dist/esm/lib/v3/types/public/api.d.ts +7 -1
  158. package/dist/esm/lib/v3/types/public/api.js +22 -2
  159. package/dist/esm/lib/v3/types/public/api.js.map +1 -1
  160. package/dist/esm/lib/v3/types/public/methods.d.ts +2 -0
  161. package/dist/esm/lib/v3/types/public/methods.js.map +1 -1
  162. package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js +21 -12
  163. package/dist/esm/lib/v3/understudy/a11y/snapshot/a11yTree.js.map +1 -1
  164. package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.d.ts +11 -2
  165. package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js +267 -22
  166. package/dist/esm/lib/v3/understudy/a11y/snapshot/capture.js.map +1 -1
  167. package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js +60 -7
  168. package/dist/esm/lib/v3/understudy/a11y/snapshot/domTree.js.map +1 -1
  169. package/dist/esm/lib/v3/understudy/frameRegistry.js +16 -5
  170. package/dist/esm/lib/v3/understudy/frameRegistry.js.map +1 -1
  171. package/dist/esm/lib/v3/v3.d.ts +1 -0
  172. package/dist/esm/lib/v3/v3.js +18 -14
  173. package/dist/esm/lib/v3/v3.js.map +1 -1
  174. package/dist/esm/lib/version.d.ts +1 -1
  175. package/dist/esm/lib/version.js +1 -1
  176. package/dist/esm/lib/version.js.map +1 -1
  177. package/dist/esm/tests/integration/observe-element-id-format.spec.d.ts +1 -0
  178. package/dist/esm/tests/integration/observe-element-id-format.spec.js +128 -0
  179. package/dist/esm/tests/integration/observe-element-id-format.spec.js.map +1 -0
  180. package/dist/esm/tests/unit/agent-mode-routing.test.d.ts +1 -0
  181. package/dist/esm/tests/unit/agent-mode-routing.test.js +86 -0
  182. package/dist/esm/tests/unit/agent-mode-routing.test.js.map +1 -0
  183. package/dist/esm/tests/unit/agent-temperature.test.d.ts +1 -0
  184. package/dist/esm/tests/unit/agent-temperature.test.js +189 -0
  185. package/dist/esm/tests/unit/agent-temperature.test.js.map +1 -0
  186. package/dist/esm/tests/unit/agent-variables-validation.test.d.ts +1 -0
  187. package/dist/esm/tests/unit/agent-variables-validation.test.js +41 -0
  188. package/dist/esm/tests/unit/agent-variables-validation.test.js.map +1 -0
  189. package/dist/esm/tests/unit/api-client-observe-variables.test.js +49 -0
  190. package/dist/esm/tests/unit/api-client-observe-variables.test.js.map +1 -1
  191. package/dist/esm/tests/unit/api-optional-model-api-key.test.js +60 -0
  192. package/dist/esm/tests/unit/api-optional-model-api-key.test.js.map +1 -1
  193. package/dist/esm/tests/unit/api-variables-schema.test.js +32 -0
  194. package/dist/esm/tests/unit/api-variables-schema.test.js.map +1 -1
  195. package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.d.ts +1 -0
  196. package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.js +58 -0
  197. package/dist/esm/tests/unit/frame-registry-oopif-adoption.test.js.map +1 -0
  198. package/dist/esm/tests/unit/inference-temperature.test.d.ts +1 -0
  199. package/dist/esm/tests/unit/inference-temperature.test.js +63 -0
  200. package/dist/esm/tests/unit/inference-temperature.test.js.map +1 -0
  201. package/dist/esm/tests/unit/openai-compatible-temperature.test.d.ts +1 -0
  202. package/dist/esm/tests/unit/openai-compatible-temperature.test.js +82 -0
  203. package/dist/esm/tests/unit/openai-compatible-temperature.test.js.map +1 -0
  204. package/dist/esm/tests/unit/prompt-observe-variables.test.js +6 -0
  205. package/dist/esm/tests/unit/prompt-observe-variables.test.js.map +1 -1
  206. package/dist/esm/tests/unit/public-api/llm-and-agents.test.js +3 -0
  207. package/dist/esm/tests/unit/public-api/llm-and-agents.test.js.map +1 -1
  208. package/dist/esm/tests/unit/public-api/public-types.test.js.map +1 -1
  209. package/dist/esm/tests/unit/snapshot-a11y-resolvers.test.js +106 -5
  210. package/dist/esm/tests/unit/snapshot-a11y-resolvers.test.js.map +1 -1
  211. package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js +20 -0
  212. package/dist/esm/tests/unit/snapshot-a11y-tree-utils.test.js.map +1 -1
  213. package/dist/esm/tests/unit/snapshot-capture-orchestration.test.js +119 -9
  214. package/dist/esm/tests/unit/snapshot-capture-orchestration.test.js.map +1 -1
  215. package/dist/esm/tests/unit/timeout-handlers.test.js +36 -0
  216. package/dist/esm/tests/unit/timeout-handlers.test.js.map +1 -1
  217. package/package.json +3 -3
  218. package/dist/cjs/tests/integration/agent-captcha-autosolve.spec.js +0 -56
  219. package/dist/cjs/tests/integration/agent-captcha-autosolve.spec.js.map +0 -1
  220. package/dist/esm/tests/integration/agent-captcha-autosolve.spec.js +0 -54
  221. package/dist/esm/tests/integration/agent-captcha-autosolve.spec.js.map +0 -1
  222. /package/dist/cjs/tests/integration/{agent-captcha-autosolve.spec.d.ts → observe-element-id-format.spec.d.ts} +0 -0
  223. /package/dist/{esm/tests/integration/agent-captcha-autosolve.spec.d.ts → cjs/tests/unit/agent-mode-routing.test.d.ts} +0 -0
@@ -2,4 +2,4 @@
2
2
  * AUTO-GENERATED — DO NOT EDIT BY HAND
3
3
  * Run `pnpm run gen-version` to refresh.
4
4
  */
5
- export declare const STAGEHAND_VERSION: "3.2.0";
5
+ export declare const STAGEHAND_VERSION: "3.3.0";
@@ -5,5 +5,5 @@ exports.STAGEHAND_VERSION = void 0;
5
5
  * AUTO-GENERATED — DO NOT EDIT BY HAND
6
6
  * Run `pnpm run gen-version` to refresh.
7
7
  */
8
- exports.STAGEHAND_VERSION = "3.2.0";
8
+ exports.STAGEHAND_VERSION = "3.3.0";
9
9
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../lib/version.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,iBAAiB,GAAG,OAAgB,CAAC","sourcesContent":["/**\n * AUTO-GENERATED — DO NOT EDIT BY HAND\n * Run `pnpm run gen-version` to refresh.\n */\nexport const STAGEHAND_VERSION = \"3.2.0\" as const;\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../lib/version.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,iBAAiB,GAAG,OAAgB,CAAC","sourcesContent":["/**\n * AUTO-GENERATED — DO NOT EDIT BY HAND\n * Run `pnpm run gen-version` to refresh.\n */\nexport const STAGEHAND_VERSION = \"3.3.0\" as const;\n"]}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const test_1 = require("@playwright/test");
4
+ const v3_js_1 = require("../../lib/v3/v3.js");
5
+ const v3_config_js_1 = require("./v3.config.js");
6
+ const testUtils_js_1 = require("./testUtils.js");
7
+ const encodedIdPattern = /^\d+-\d+$/;
8
+ const mainFrameEncodedIdPattern = /^0-\d+$/;
9
+ function encodeHtml(html) {
10
+ return `data:text/html,${encodeURIComponent(html)}`;
11
+ }
12
+ const filler = Array.from({ length: 80 }, (_, index) => `<span hidden data-filler="${index}">filler ${index}</span>`).join("");
13
+ const cases = [
14
+ {
15
+ name: "button after hidden filler nodes",
16
+ instruction: "Find the Target Checkout button",
17
+ targetText: "Target Checkout",
18
+ marker: "checkout",
19
+ html: `
20
+ <!doctype html>
21
+ <html>
22
+ <body>
23
+ ${filler}
24
+ <main>
25
+ <button onclick="document.body.dataset.clicked = 'checkout'">
26
+ Target Checkout
27
+ </button>
28
+ </main>
29
+ </body>
30
+ </html>
31
+ `,
32
+ },
33
+ {
34
+ name: "navigation link",
35
+ instruction: "Find the Pricing Plans link",
36
+ targetText: "Pricing Plans",
37
+ marker: "pricing",
38
+ html: `
39
+ <!doctype html>
40
+ <html>
41
+ <body>
42
+ <nav>
43
+ <a href="#pricing" onclick="document.body.dataset.clicked = 'pricing'">
44
+ Pricing Plans
45
+ </a>
46
+ </nav>
47
+ </body>
48
+ </html>
49
+ `,
50
+ },
51
+ {
52
+ name: "form input",
53
+ instruction: "Find the Company Email input",
54
+ targetText: "Company Email",
55
+ marker: "email",
56
+ html: `
57
+ <!doctype html>
58
+ <html>
59
+ <body>
60
+ <form>
61
+ <label>
62
+ Company Email
63
+ <input
64
+ type="email"
65
+ onclick="document.body.dataset.clicked = 'email'"
66
+ />
67
+ </label>
68
+ </form>
69
+ </body>
70
+ </html>
71
+ `,
72
+ },
73
+ ];
74
+ function observeResponseForTarget(testCase, onElementId) {
75
+ return (options) => {
76
+ const promptText = (0, testUtils_js_1.promptToText)(options.prompt);
77
+ (0, test_1.expect)(promptText).toContain("Always copy the complete ID exactly as shown inside the brackets into elementId");
78
+ (0, test_1.expect)(promptText).toContain('return elementId "0-18372"');
79
+ (0, test_1.expect)(promptText).toContain(testCase.targetText);
80
+ const elementId = (0, testUtils_js_1.findLastEncodedId)(options);
81
+ (0, test_1.expect)(elementId).toMatch(encodedIdPattern);
82
+ (0, test_1.expect)(elementId).toMatch(mainFrameEncodedIdPattern);
83
+ onElementId(elementId, options);
84
+ return {
85
+ elements: [
86
+ {
87
+ elementId,
88
+ description: testCase.targetText,
89
+ method: "click",
90
+ arguments: [],
91
+ },
92
+ ],
93
+ };
94
+ };
95
+ }
96
+ test_1.test.describe("observe main frame element IDs", () => {
97
+ for (const testCase of cases) {
98
+ (0, test_1.test)(`keeps complete 0-ordinal element IDs for ${testCase.name}`, async () => {
99
+ let observedElementId;
100
+ const llmClient = (0, testUtils_js_1.createScriptedAisdkTestLlmClient)({
101
+ modelId: "mock/observe-main-frame-element-id-format",
102
+ jsonResponses: {
103
+ Observation: observeResponseForTarget(testCase, (elementId) => {
104
+ observedElementId = elementId;
105
+ }),
106
+ },
107
+ });
108
+ const v3 = new v3_js_1.V3((0, v3_config_js_1.getV3TestConfig)({
109
+ llmClient,
110
+ }));
111
+ await v3.init();
112
+ try {
113
+ const page = v3.context.pages()[0];
114
+ await page.goto(encodeHtml(testCase.html));
115
+ const observed = await v3.observe(testCase.instruction);
116
+ (0, test_1.expect)(observedElementId).toMatch(mainFrameEncodedIdPattern);
117
+ (0, test_1.expect)(observed).toHaveLength(1);
118
+ (0, test_1.expect)(observed[0].selector).toMatch(/^xpath=/);
119
+ const actResult = await v3.act(observed[0]);
120
+ (0, test_1.expect)(actResult.success).toBe(true);
121
+ const clicked = await page.evaluate(() => document.body.dataset.clicked);
122
+ (0, test_1.expect)(clicked).toBe(testCase.marker);
123
+ }
124
+ finally {
125
+ await (0, testUtils_js_1.closeV3)(v3);
126
+ }
127
+ });
128
+ }
129
+ });
130
+ //# sourceMappingURL=observe-element-id-format.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe-element-id-format.spec.js","sourceRoot":"","sources":["../../../../tests/integration/observe-element-id-format.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, test } from \"@playwright/test\";\nimport type { LanguageModelV2CallOptions } from \"@ai-sdk/provider\";\nimport { V3 } from \"../../lib/v3/v3.js\";\nimport { getV3TestConfig } from \"./v3.config.js\";\nimport {\n closeV3,\n createScriptedAisdkTestLlmClient,\n findLastEncodedId,\n promptToText,\n} from \"./testUtils.js\";\n\nconst encodedIdPattern = /^\\d+-\\d+$/;\nconst mainFrameEncodedIdPattern = /^0-\\d+$/;\n\nfunction encodeHtml(html: string): string {\n return `data:text/html,${encodeURIComponent(html)}`;\n}\n\ntype MainFrameCase = {\n name: string;\n instruction: string;\n targetText: string;\n marker: string;\n html: string;\n};\n\nconst filler = Array.from(\n { length: 80 },\n (_, index) => `<span hidden data-filler=\"${index}\">filler ${index}</span>`,\n).join(\"\");\n\nconst cases: MainFrameCase[] = [\n {\n name: \"button after hidden filler nodes\",\n instruction: \"Find the Target Checkout button\",\n targetText: \"Target Checkout\",\n marker: \"checkout\",\n html: `\n <!doctype html>\n <html>\n <body>\n ${filler}\n <main>\n <button onclick=\"document.body.dataset.clicked = 'checkout'\">\n Target Checkout\n </button>\n </main>\n </body>\n </html>\n `,\n },\n {\n name: \"navigation link\",\n instruction: \"Find the Pricing Plans link\",\n targetText: \"Pricing Plans\",\n marker: \"pricing\",\n html: `\n <!doctype html>\n <html>\n <body>\n <nav>\n <a href=\"#pricing\" onclick=\"document.body.dataset.clicked = 'pricing'\">\n Pricing Plans\n </a>\n </nav>\n </body>\n </html>\n `,\n },\n {\n name: \"form input\",\n instruction: \"Find the Company Email input\",\n targetText: \"Company Email\",\n marker: \"email\",\n html: `\n <!doctype html>\n <html>\n <body>\n <form>\n <label>\n Company Email\n <input\n type=\"email\"\n onclick=\"document.body.dataset.clicked = 'email'\"\n />\n </label>\n </form>\n </body>\n </html>\n `,\n },\n];\n\nfunction observeResponseForTarget(\n testCase: MainFrameCase,\n onElementId: (elementId: string, options: LanguageModelV2CallOptions) => void,\n) {\n return (options: LanguageModelV2CallOptions) => {\n const promptText = promptToText(options.prompt);\n expect(promptText).toContain(\n \"Always copy the complete ID exactly as shown inside the brackets into elementId\",\n );\n expect(promptText).toContain('return elementId \"0-18372\"');\n\n expect(promptText).toContain(testCase.targetText);\n\n const elementId = findLastEncodedId(options);\n expect(elementId).toMatch(encodedIdPattern);\n expect(elementId).toMatch(mainFrameEncodedIdPattern);\n onElementId(elementId, options);\n\n return {\n elements: [\n {\n elementId,\n description: testCase.targetText,\n method: \"click\",\n arguments: [] as string[],\n },\n ],\n };\n };\n}\n\ntest.describe(\"observe main frame element IDs\", () => {\n for (const testCase of cases) {\n test(`keeps complete 0-ordinal element IDs for ${testCase.name}`, async () => {\n let observedElementId: string | undefined;\n const llmClient = createScriptedAisdkTestLlmClient({\n modelId: \"mock/observe-main-frame-element-id-format\",\n jsonResponses: {\n Observation: observeResponseForTarget(testCase, (elementId) => {\n observedElementId = elementId;\n }),\n },\n });\n\n const v3 = new V3(\n getV3TestConfig({\n llmClient,\n }),\n );\n await v3.init();\n\n try {\n const page = v3.context.pages()[0];\n await page.goto(encodeHtml(testCase.html));\n\n const observed = await v3.observe(testCase.instruction);\n\n expect(observedElementId).toMatch(mainFrameEncodedIdPattern);\n expect(observed).toHaveLength(1);\n expect(observed[0].selector).toMatch(/^xpath=/);\n\n const actResult = await v3.act(observed[0]);\n expect(actResult.success).toBe(true);\n\n const clicked = await page.evaluate(\n () => document.body.dataset.clicked,\n );\n expect(clicked).toBe(testCase.marker);\n } finally {\n await closeV3(v3);\n }\n });\n }\n});\n"]}
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const modelUtils_js_1 = require("../../lib/modelUtils.js");
5
+ const agent_js_1 = require("../../lib/v3/types/private/agent.js");
6
+ function resolveDefaultAgentMode(model, fallbackModelName) {
7
+ const modelName = (0, modelUtils_js_1.extractModelName)(model) ?? fallbackModelName;
8
+ const isHybridCapable = agent_js_1.HYBRID_CAPABLE_MODEL_PATTERNS.some((pattern) => modelName.includes(pattern));
9
+ return isHybridCapable ? "hybrid" : "dom";
10
+ }
11
+ function resolveAgentMode(explicitMode, model, fallbackModelName) {
12
+ return explicitMode ?? resolveDefaultAgentMode(model, fallbackModelName);
13
+ }
14
+ (0, vitest_1.describe)("agent mode auto-routing", () => {
15
+ (0, vitest_1.describe)("explicit mode is never overridden", () => {
16
+ (0, vitest_1.it)("respects mode: 'dom' even when model supports hybrid", () => {
17
+ const result = resolveAgentMode("dom", "anthropic/claude-sonnet-4-20250514", "openai/gpt-4o");
18
+ (0, vitest_1.expect)(result).toBe("dom");
19
+ });
20
+ (0, vitest_1.it)("respects mode: 'hybrid' even when model does not support hybrid", () => {
21
+ const result = resolveAgentMode("hybrid", "openai/gpt-4o-mini", "openai/gpt-4o-mini");
22
+ (0, vitest_1.expect)(result).toBe("hybrid");
23
+ });
24
+ (0, vitest_1.it)("respects mode: 'cua' regardless of model", () => {
25
+ const result = resolveAgentMode("cua", "anthropic/claude-sonnet-4-20250514", "openai/gpt-4o");
26
+ (0, vitest_1.expect)(result).toBe("cua");
27
+ });
28
+ });
29
+ (0, vitest_1.describe)("auto-routes to hybrid for supported models when no mode is set", () => {
30
+ vitest_1.it.each([
31
+ ["google/gemini-3-flash-preview", "gemini-3"],
32
+ ["google/gemini-3-flash", "gemini-3"],
33
+ ["anthropic/claude-sonnet-4-20250514", "claude"],
34
+ ["anthropic/claude-haiku-4-5-20251001", "claude"],
35
+ ["openai/gpt-5.4-turbo", "gpt-5.4"],
36
+ ["openai/gpt-5.4", "gpt-5.4"],
37
+ ])("model %s (pattern: %s) → hybrid", (modelName) => {
38
+ const result = resolveAgentMode(undefined, modelName, "fallback-model");
39
+ (0, vitest_1.expect)(result).toBe("hybrid");
40
+ });
41
+ });
42
+ (0, vitest_1.describe)("auto-routes to dom for unsupported models when no mode is set", () => {
43
+ vitest_1.it.each([
44
+ "openai/gpt-4o",
45
+ "openai/gpt-4o-mini",
46
+ "openai/gpt-4.1-mini",
47
+ "google/gemini-2.0-flash",
48
+ "google/gemini-2.5-flash",
49
+ "mistral/mistral-large",
50
+ ])("model %s → dom", (modelName) => {
51
+ const result = resolveAgentMode(undefined, modelName, "fallback-model");
52
+ (0, vitest_1.expect)(result).toBe("dom");
53
+ });
54
+ });
55
+ (0, vitest_1.describe)("falls back to stagehand-level model when no agent model is set", () => {
56
+ (0, vitest_1.it)("uses stagehand model for routing when agent model is undefined", () => {
57
+ const result = resolveAgentMode(undefined, undefined, "anthropic/claude-sonnet-4-20250514");
58
+ (0, vitest_1.expect)(result).toBe("hybrid");
59
+ });
60
+ (0, vitest_1.it)("routes to dom when stagehand model is not hybrid-capable", () => {
61
+ const result = resolveAgentMode(undefined, undefined, "openai/gpt-4o-mini");
62
+ (0, vitest_1.expect)(result).toBe("dom");
63
+ });
64
+ });
65
+ (0, vitest_1.describe)("handles AgentModelConfig objects", () => {
66
+ (0, vitest_1.it)("extracts modelName from config object for routing", () => {
67
+ const result = resolveAgentMode(undefined, { modelName: "anthropic/claude-sonnet-4-20250514" }, "openai/gpt-4o");
68
+ (0, vitest_1.expect)(result).toBe("hybrid");
69
+ });
70
+ (0, vitest_1.it)("routes to dom when config object model is not hybrid-capable", () => {
71
+ const result = resolveAgentMode(undefined, { modelName: "openai/gpt-4o-mini" }, "openai/gpt-4o");
72
+ (0, vitest_1.expect)(result).toBe("dom");
73
+ });
74
+ });
75
+ });
76
+ (0, vitest_1.describe)("V3AgentHandler mode fallback", () => {
77
+ (0, vitest_1.it)("handler defaults to dom when mode is undefined (safety net)", () => {
78
+ const mode = undefined;
79
+ const resolved = mode ?? "dom";
80
+ (0, vitest_1.expect)(resolved).toBe("dom");
81
+ });
82
+ (0, vitest_1.it)("handler uses provided mode when set", () => {
83
+ const mode = "hybrid";
84
+ const resolved = mode ?? "dom";
85
+ (0, vitest_1.expect)(resolved).toBe("hybrid");
86
+ });
87
+ });
88
+ //# sourceMappingURL=agent-mode-routing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-mode-routing.test.js","sourceRoot":"","sources":["../../../../tests/unit/agent-mode-routing.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { extractModelName } from \"../../lib/modelUtils.js\";\nimport type { AgentToolMode } from \"../../lib/v3/types/public/agent.js\";\nimport { HYBRID_CAPABLE_MODEL_PATTERNS } from \"../../lib/v3/types/private/agent.js\";\n\nfunction resolveDefaultAgentMode(\n model: string | { modelName: string } | undefined,\n fallbackModelName: string,\n): AgentToolMode {\n const modelName = extractModelName(model) ?? fallbackModelName;\n const isHybridCapable = HYBRID_CAPABLE_MODEL_PATTERNS.some((pattern) =>\n modelName.includes(pattern),\n );\n return isHybridCapable ? \"hybrid\" : \"dom\";\n}\n\nfunction resolveAgentMode(\n explicitMode: AgentToolMode | undefined,\n model: string | { modelName: string } | undefined,\n fallbackModelName: string,\n): AgentToolMode {\n return explicitMode ?? resolveDefaultAgentMode(model, fallbackModelName);\n}\n\ndescribe(\"agent mode auto-routing\", () => {\n describe(\"explicit mode is never overridden\", () => {\n it(\"respects mode: 'dom' even when model supports hybrid\", () => {\n const result = resolveAgentMode(\n \"dom\",\n \"anthropic/claude-sonnet-4-20250514\",\n \"openai/gpt-4o\",\n );\n expect(result).toBe(\"dom\");\n });\n\n it(\"respects mode: 'hybrid' even when model does not support hybrid\", () => {\n const result = resolveAgentMode(\n \"hybrid\",\n \"openai/gpt-4o-mini\",\n \"openai/gpt-4o-mini\",\n );\n expect(result).toBe(\"hybrid\");\n });\n\n it(\"respects mode: 'cua' regardless of model\", () => {\n const result = resolveAgentMode(\n \"cua\",\n \"anthropic/claude-sonnet-4-20250514\",\n \"openai/gpt-4o\",\n );\n expect(result).toBe(\"cua\");\n });\n });\n\n describe(\"auto-routes to hybrid for supported models when no mode is set\", () => {\n it.each([\n [\"google/gemini-3-flash-preview\", \"gemini-3\"],\n [\"google/gemini-3-flash\", \"gemini-3\"],\n [\"anthropic/claude-sonnet-4-20250514\", \"claude\"],\n [\"anthropic/claude-haiku-4-5-20251001\", \"claude\"],\n [\"openai/gpt-5.4-turbo\", \"gpt-5.4\"],\n [\"openai/gpt-5.4\", \"gpt-5.4\"],\n ])(\"model %s (pattern: %s) → hybrid\", (modelName: string) => {\n const result = resolveAgentMode(undefined, modelName, \"fallback-model\");\n expect(result).toBe(\"hybrid\");\n });\n });\n\n describe(\"auto-routes to dom for unsupported models when no mode is set\", () => {\n it.each([\n \"openai/gpt-4o\",\n \"openai/gpt-4o-mini\",\n \"openai/gpt-4.1-mini\",\n \"google/gemini-2.0-flash\",\n \"google/gemini-2.5-flash\",\n \"mistral/mistral-large\",\n ])(\"model %s → dom\", (modelName: string) => {\n const result = resolveAgentMode(undefined, modelName, \"fallback-model\");\n expect(result).toBe(\"dom\");\n });\n });\n\n describe(\"falls back to stagehand-level model when no agent model is set\", () => {\n it(\"uses stagehand model for routing when agent model is undefined\", () => {\n const result = resolveAgentMode(\n undefined,\n undefined,\n \"anthropic/claude-sonnet-4-20250514\",\n );\n expect(result).toBe(\"hybrid\");\n });\n\n it(\"routes to dom when stagehand model is not hybrid-capable\", () => {\n const result = resolveAgentMode(\n undefined,\n undefined,\n \"openai/gpt-4o-mini\",\n );\n expect(result).toBe(\"dom\");\n });\n });\n\n describe(\"handles AgentModelConfig objects\", () => {\n it(\"extracts modelName from config object for routing\", () => {\n const result = resolveAgentMode(\n undefined,\n { modelName: \"anthropic/claude-sonnet-4-20250514\" },\n \"openai/gpt-4o\",\n );\n expect(result).toBe(\"hybrid\");\n });\n\n it(\"routes to dom when config object model is not hybrid-capable\", () => {\n const result = resolveAgentMode(\n undefined,\n { modelName: \"openai/gpt-4o-mini\" },\n \"openai/gpt-4o\",\n );\n expect(result).toBe(\"dom\");\n });\n });\n});\n\ndescribe(\"V3AgentHandler mode fallback\", () => {\n it(\"handler defaults to dom when mode is undefined (safety net)\", () => {\n const mode: AgentToolMode | undefined = undefined;\n const resolved = mode ?? \"dom\";\n expect(resolved).toBe(\"dom\");\n });\n\n it(\"handler uses provided mode when set\", () => {\n const mode: AgentToolMode | undefined = \"hybrid\";\n const resolved = mode ?? \"dom\";\n expect(resolved).toBe(\"hybrid\");\n });\n});\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ vitest_1.vi.mock("ai", async () => {
5
+ const actual = await vitest_1.vi.importActual("ai");
6
+ return {
7
+ ...actual,
8
+ wrapLanguageModel: vitest_1.vi.fn(({ model }) => model),
9
+ };
10
+ });
11
+ const v3AgentHandler_js_1 = require("../../lib/v3/handlers/v3AgentHandler.js");
12
+ const usage = {
13
+ inputTokens: 1,
14
+ outputTokens: 1,
15
+ reasoningTokens: 0,
16
+ cachedInputTokens: 0,
17
+ totalTokens: 2,
18
+ };
19
+ const emptyList = () => [];
20
+ function createDoneStep() {
21
+ return {
22
+ content: emptyList(),
23
+ text: "",
24
+ reasoning: emptyList(),
25
+ reasoningText: undefined,
26
+ files: emptyList(),
27
+ sources: emptyList(),
28
+ toolCalls: [
29
+ {
30
+ type: "tool-call",
31
+ toolCallId: "call_done",
32
+ toolName: "done",
33
+ input: {
34
+ reasoning: "Task completed",
35
+ taskComplete: true,
36
+ },
37
+ },
38
+ ],
39
+ staticToolCalls: emptyList(),
40
+ dynamicToolCalls: emptyList(),
41
+ toolResults: [
42
+ {
43
+ type: "tool-result",
44
+ toolCallId: "call_done",
45
+ toolName: "done",
46
+ input: {
47
+ reasoning: "Task completed",
48
+ taskComplete: true,
49
+ },
50
+ output: {
51
+ success: true,
52
+ reasoning: "Task completed",
53
+ taskComplete: true,
54
+ },
55
+ },
56
+ ],
57
+ staticToolResults: emptyList(),
58
+ dynamicToolResults: emptyList(),
59
+ finishReason: "tool-calls",
60
+ usage,
61
+ warnings: undefined,
62
+ request: {},
63
+ response: {
64
+ id: "response-id",
65
+ modelId: "openai/gpt-5-mini",
66
+ timestamp: new Date(0),
67
+ messages: emptyList(),
68
+ },
69
+ providerMetadata: undefined,
70
+ };
71
+ }
72
+ function createGenerateResult(doneStep) {
73
+ return {
74
+ content: emptyList(),
75
+ text: "",
76
+ reasoning: emptyList(),
77
+ reasoningText: undefined,
78
+ files: emptyList(),
79
+ sources: emptyList(),
80
+ toolCalls: doneStep.toolCalls,
81
+ staticToolCalls: emptyList(),
82
+ dynamicToolCalls: emptyList(),
83
+ toolResults: doneStep.toolResults,
84
+ staticToolResults: emptyList(),
85
+ dynamicToolResults: emptyList(),
86
+ finishReason: "tool-calls",
87
+ usage,
88
+ totalUsage: usage,
89
+ warnings: undefined,
90
+ request: {},
91
+ response: {
92
+ id: "response-id",
93
+ modelId: "openai/gpt-5-mini",
94
+ timestamp: new Date(0),
95
+ messages: emptyList(),
96
+ },
97
+ providerMetadata: undefined,
98
+ steps: [doneStep],
99
+ experimental_output: undefined,
100
+ };
101
+ }
102
+ function createV3() {
103
+ const page = {
104
+ url: () => "https://example.com",
105
+ enableCursorOverlay: vitest_1.vi.fn(async () => { }),
106
+ };
107
+ return {
108
+ context: {
109
+ awaitActivePage: vitest_1.vi.fn(async () => page),
110
+ },
111
+ isCaptchaAutoSolveEnabled: false,
112
+ browserbaseApiKey: undefined,
113
+ logger: vitest_1.vi.fn(),
114
+ recordAgentReplayStep: vitest_1.vi.fn(),
115
+ updateMetrics: vitest_1.vi.fn(),
116
+ act: vitest_1.vi.fn(),
117
+ extract: vitest_1.vi.fn(),
118
+ observe: vitest_1.vi.fn(),
119
+ };
120
+ }
121
+ function createLlmClient() {
122
+ const model = {
123
+ modelId: "openai/gpt-5-mini",
124
+ provider: "openai",
125
+ specificationVersion: "v2",
126
+ };
127
+ const generateText = vitest_1.vi.fn(async (options) => {
128
+ const doneStep = createDoneStep();
129
+ await options.onStepFinish?.(doneStep);
130
+ return createGenerateResult(doneStep);
131
+ });
132
+ const streamText = vitest_1.vi.fn((options) => {
133
+ void (async () => {
134
+ const doneStep = createDoneStep();
135
+ await options.onStepFinish?.(doneStep);
136
+ options.onFinish?.(createGenerateResult(doneStep));
137
+ })();
138
+ return {
139
+ textStream: (async function* () { })(),
140
+ };
141
+ });
142
+ return {
143
+ client: {
144
+ getLanguageModel: vitest_1.vi.fn(() => model),
145
+ generateText,
146
+ streamText,
147
+ },
148
+ generateText,
149
+ streamText,
150
+ };
151
+ }
152
+ (0, vitest_1.describe)("v3 agent temperature options", () => {
153
+ let logger;
154
+ (0, vitest_1.beforeEach)(() => {
155
+ logger = vitest_1.vi.fn();
156
+ });
157
+ (0, vitest_1.it)("does not pass a temperature setting to non-streaming agent generation", async () => {
158
+ const { client, generateText } = createLlmClient();
159
+ const handler = new v3AgentHandler_js_1.V3AgentHandler(createV3(), logger, client);
160
+ await handler.execute({
161
+ instruction: "finish",
162
+ maxSteps: 1,
163
+ excludeTools: ["search"],
164
+ });
165
+ (0, vitest_1.expect)(generateText).toHaveBeenCalledTimes(1);
166
+ const options = generateText.mock.calls[0][0];
167
+ (0, vitest_1.expect)(options).not.toHaveProperty("temperature");
168
+ (0, vitest_1.expect)(options.providerOptions).toEqual({
169
+ google: { mediaResolution: "MEDIA_RESOLUTION_HIGH" },
170
+ openai: { store: false },
171
+ });
172
+ });
173
+ (0, vitest_1.it)("does not pass a temperature setting to streaming agent generation", async () => {
174
+ const { client, streamText } = createLlmClient();
175
+ const handler = new v3AgentHandler_js_1.V3AgentHandler(createV3(), logger, client);
176
+ const streamResult = await handler.stream({
177
+ instruction: "finish",
178
+ maxSteps: 1,
179
+ excludeTools: ["search"],
180
+ });
181
+ await streamResult.result;
182
+ (0, vitest_1.expect)(streamText).toHaveBeenCalledTimes(1);
183
+ const options = streamText.mock.calls[0][0];
184
+ (0, vitest_1.expect)(options).not.toHaveProperty("temperature");
185
+ (0, vitest_1.expect)(options.providerOptions).toEqual({
186
+ google: { mediaResolution: "MEDIA_RESOLUTION_HIGH" },
187
+ openai: { store: false },
188
+ });
189
+ });
190
+ });
191
+ //# sourceMappingURL=agent-temperature.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-temperature.test.js","sourceRoot":"","sources":["../../../../tests/unit/agent-temperature.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport type { LanguageModelV2 } from \"@ai-sdk/provider\";\nimport type { LLMClient } from \"../../lib/v3/llm/LLMClient.js\";\nimport type { LogLine } from \"../../lib/v3/types/public/logs.js\";\nimport type { V3 } from \"../../lib/v3/v3.js\";\n\nvi.mock(\"ai\", async () => {\n const actual = await vi.importActual<typeof import(\"ai\")>(\"ai\");\n return {\n ...actual,\n wrapLanguageModel: vi.fn(({ model }) => model),\n };\n});\n\nimport { V3AgentHandler } from \"../../lib/v3/handlers/v3AgentHandler.js\";\n\ntype AgentLlmOptions = {\n onStepFinish?: (step: unknown) => Promise<void> | void;\n onFinish?: (event: unknown) => void;\n providerOptions?: Record<string, unknown>;\n temperature?: number;\n};\n\nconst usage = {\n inputTokens: 1,\n outputTokens: 1,\n reasoningTokens: 0,\n cachedInputTokens: 0,\n totalTokens: 2,\n};\n\nconst emptyList = () => [] as unknown[];\n\nfunction createDoneStep() {\n return {\n content: emptyList(),\n text: \"\",\n reasoning: emptyList(),\n reasoningText: undefined as string | undefined,\n files: emptyList(),\n sources: emptyList(),\n toolCalls: [\n {\n type: \"tool-call\",\n toolCallId: \"call_done\",\n toolName: \"done\",\n input: {\n reasoning: \"Task completed\",\n taskComplete: true,\n },\n },\n ],\n staticToolCalls: emptyList(),\n dynamicToolCalls: emptyList(),\n toolResults: [\n {\n type: \"tool-result\",\n toolCallId: \"call_done\",\n toolName: \"done\",\n input: {\n reasoning: \"Task completed\",\n taskComplete: true,\n },\n output: {\n success: true,\n reasoning: \"Task completed\",\n taskComplete: true,\n },\n },\n ],\n staticToolResults: emptyList(),\n dynamicToolResults: emptyList(),\n finishReason: \"tool-calls\",\n usage,\n warnings: undefined as unknown,\n request: {},\n response: {\n id: \"response-id\",\n modelId: \"openai/gpt-5-mini\",\n timestamp: new Date(0),\n messages: emptyList(),\n },\n providerMetadata: undefined as unknown,\n };\n}\n\nfunction createGenerateResult(doneStep: ReturnType<typeof createDoneStep>) {\n return {\n content: emptyList(),\n text: \"\",\n reasoning: emptyList(),\n reasoningText: undefined as string | undefined,\n files: emptyList(),\n sources: emptyList(),\n toolCalls: doneStep.toolCalls,\n staticToolCalls: emptyList(),\n dynamicToolCalls: emptyList(),\n toolResults: doneStep.toolResults,\n staticToolResults: emptyList(),\n dynamicToolResults: emptyList(),\n finishReason: \"tool-calls\",\n usage,\n totalUsage: usage,\n warnings: undefined as unknown,\n request: {},\n response: {\n id: \"response-id\",\n modelId: \"openai/gpt-5-mini\",\n timestamp: new Date(0),\n messages: emptyList(),\n },\n providerMetadata: undefined as unknown,\n steps: [doneStep],\n experimental_output: undefined as unknown,\n };\n}\n\nfunction createV3() {\n const page = {\n url: () => \"https://example.com\",\n enableCursorOverlay: vi.fn(async () => {}),\n };\n\n return {\n context: {\n awaitActivePage: vi.fn(async () => page),\n },\n isCaptchaAutoSolveEnabled: false,\n browserbaseApiKey: undefined,\n logger: vi.fn(),\n recordAgentReplayStep: vi.fn(),\n updateMetrics: vi.fn(),\n act: vi.fn(),\n extract: vi.fn(),\n observe: vi.fn(),\n } as unknown as V3;\n}\n\nfunction createLlmClient() {\n const model = {\n modelId: \"openai/gpt-5-mini\",\n provider: \"openai\",\n specificationVersion: \"v2\",\n } as unknown as LanguageModelV2;\n\n const generateText = vi.fn(async (options: AgentLlmOptions) => {\n const doneStep = createDoneStep();\n await options.onStepFinish?.(doneStep);\n return createGenerateResult(doneStep);\n });\n\n const streamText = vi.fn((options: AgentLlmOptions) => {\n void (async () => {\n const doneStep = createDoneStep();\n await options.onStepFinish?.(doneStep);\n options.onFinish?.(createGenerateResult(doneStep));\n })();\n\n return {\n textStream: (async function* () {})(),\n };\n });\n\n return {\n client: {\n getLanguageModel: vi.fn(() => model),\n generateText,\n streamText,\n } as unknown as LLMClient,\n generateText,\n streamText,\n };\n}\n\ndescribe(\"v3 agent temperature options\", () => {\n let logger: (line: LogLine) => void;\n\n beforeEach(() => {\n logger = vi.fn();\n });\n\n it(\"does not pass a temperature setting to non-streaming agent generation\", async () => {\n const { client, generateText } = createLlmClient();\n const handler = new V3AgentHandler(createV3(), logger, client);\n\n await handler.execute({\n instruction: \"finish\",\n maxSteps: 1,\n excludeTools: [\"search\"],\n });\n\n expect(generateText).toHaveBeenCalledTimes(1);\n const options = generateText.mock.calls[0][0] as AgentLlmOptions;\n expect(options).not.toHaveProperty(\"temperature\");\n expect(options.providerOptions).toEqual({\n google: { mediaResolution: \"MEDIA_RESOLUTION_HIGH\" },\n openai: { store: false },\n });\n });\n\n it(\"does not pass a temperature setting to streaming agent generation\", async () => {\n const { client, streamText } = createLlmClient();\n const handler = new V3AgentHandler(createV3(), logger, client);\n\n const streamResult = await handler.stream({\n instruction: \"finish\",\n maxSteps: 1,\n excludeTools: [\"search\"],\n });\n await streamResult.result;\n\n expect(streamText).toHaveBeenCalledTimes(1);\n const options = streamText.mock.calls[0][0] as AgentLlmOptions;\n expect(options).not.toHaveProperty(\"temperature\");\n expect(options.providerOptions).toEqual({\n google: { mediaResolution: \"MEDIA_RESOLUTION_HIGH\" },\n openai: { store: false },\n });\n });\n});\n"]}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const validateExperimentalFeatures_js_1 = require("../../lib/v3/agent/utils/validateExperimentalFeatures.js");
5
+ const sdkErrors_js_1 = require("../../lib/v3/types/public/sdkErrors.js");
6
+ (0, vitest_1.describe)("agent variable experimental validation", () => {
7
+ (0, vitest_1.it)("allows variables without experimental mode", () => {
8
+ (0, vitest_1.expect)(() => (0, validateExperimentalFeatures_js_1.validateExperimentalFeatures)({
9
+ isExperimental: false,
10
+ agentConfig: { mode: "dom" },
11
+ executeOptions: {
12
+ instruction: "fill %username%",
13
+ variables: { username: "john@example.com" },
14
+ },
15
+ })).not.toThrow();
16
+ });
17
+ (0, vitest_1.it)("allows rich variables without experimental mode", () => {
18
+ (0, vitest_1.expect)(() => (0, validateExperimentalFeatures_js_1.validateExperimentalFeatures)({
19
+ isExperimental: false,
20
+ agentConfig: { mode: "dom" },
21
+ executeOptions: {
22
+ instruction: "fill %username%",
23
+ variables: {
24
+ username: {
25
+ value: "john@example.com",
26
+ description: "The login email",
27
+ },
28
+ },
29
+ },
30
+ })).not.toThrow();
31
+ });
32
+ (0, vitest_1.it)("continues to reject variables in CUA mode", () => {
33
+ (0, vitest_1.expect)(() => (0, validateExperimentalFeatures_js_1.validateExperimentalFeatures)({
34
+ isExperimental: true,
35
+ agentConfig: { mode: "cua" },
36
+ executeOptions: {
37
+ instruction: "fill %username%",
38
+ variables: { username: "john@example.com" },
39
+ },
40
+ })).toThrow(sdkErrors_js_1.StagehandInvalidArgumentError);
41
+ });
42
+ });
43
+ //# sourceMappingURL=agent-variables-validation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-variables-validation.test.js","sourceRoot":"","sources":["../../../../tests/unit/agent-variables-validation.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,8GAAwG;AACxG,yEAAuF;AAEvF,IAAA,iBAAQ,EAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,IAAA,WAAE,EAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,IAAA,eAAM,EAAC,GAAG,EAAE,CACV,IAAA,8DAA4B,EAAC;YAC3B,cAAc,EAAE,KAAK;YACrB,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;YAC5B,cAAc,EAAE;gBACd,WAAW,EAAE,iBAAiB;gBAC9B,SAAS,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE;aAC5C;SACF,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,IAAA,eAAM,EAAC,GAAG,EAAE,CACV,IAAA,8DAA4B,EAAC;YAC3B,cAAc,EAAE,KAAK;YACrB,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;YAC5B,cAAc,EAAE;gBACd,WAAW,EAAE,iBAAiB;gBAC9B,SAAS,EAAE;oBACT,QAAQ,EAAE;wBACR,KAAK,EAAE,kBAAkB;wBACzB,WAAW,EAAE,iBAAiB;qBAC/B;iBACF;aACF;SACF,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,IAAA,eAAM,EAAC,GAAG,EAAE,CACV,IAAA,8DAA4B,EAAC;YAC3B,cAAc,EAAE,IAAI;YACpB,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;YAC5B,cAAc,EAAE;gBACd,WAAW,EAAE,iBAAiB;gBAC9B,SAAS,EAAE,EAAE,QAAQ,EAAE,kBAAkB,EAAE;aAC5C;SACF,CAAC,CACH,CAAC,OAAO,CAAC,4CAA6B,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { validateExperimentalFeatures } from \"../../lib/v3/agent/utils/validateExperimentalFeatures.js\";\nimport { StagehandInvalidArgumentError } from \"../../lib/v3/types/public/sdkErrors.js\";\n\ndescribe(\"agent variable experimental validation\", () => {\n it(\"allows variables without experimental mode\", () => {\n expect(() =>\n validateExperimentalFeatures({\n isExperimental: false,\n agentConfig: { mode: \"dom\" },\n executeOptions: {\n instruction: \"fill %username%\",\n variables: { username: \"john@example.com\" },\n },\n }),\n ).not.toThrow();\n });\n\n it(\"allows rich variables without experimental mode\", () => {\n expect(() =>\n validateExperimentalFeatures({\n isExperimental: false,\n agentConfig: { mode: \"dom\" },\n executeOptions: {\n instruction: \"fill %username%\",\n variables: {\n username: {\n value: \"john@example.com\",\n description: \"The login email\",\n },\n },\n },\n }),\n ).not.toThrow();\n });\n\n it(\"continues to reject variables in CUA mode\", () => {\n expect(() =>\n validateExperimentalFeatures({\n isExperimental: true,\n agentConfig: { mode: \"cua\" },\n executeOptions: {\n instruction: \"fill %username%\",\n variables: { username: \"john@example.com\" },\n },\n }),\n ).toThrow(StagehandInvalidArgumentError);\n });\n});\n"]}
@@ -62,6 +62,7 @@ const api_js_1 = require("../../lib/v3/api.js");
62
62
  },
63
63
  password: "secret",
64
64
  },
65
+ ignoreSelectors: [".cookie-banner"],
65
66
  },
66
67
  });
67
68
  (0, vitest_1.expect)(executeMock).toHaveBeenCalledWith({
@@ -76,11 +77,59 @@ const api_js_1 = require("../../lib/v3/api.js");
76
77
  },
77
78
  password: "secret",
78
79
  },
80
+ ignoreSelectors: [".cookie-banner"],
79
81
  },
80
82
  frameId: undefined,
81
83
  },
82
84
  serverCache: undefined,
83
85
  });
84
86
  });
87
+ (0, vitest_1.it)("preserves rich variables when sending the agentExecute request", async () => {
88
+ const client = new api_js_1.StagehandAPIClient({
89
+ apiKey: "bb-test",
90
+ logger: vitest_1.vi.fn(),
91
+ });
92
+ const executeMock = vitest_1.vi.fn().mockResolvedValue({
93
+ success: true,
94
+ message: "ok",
95
+ actions: [],
96
+ completed: true,
97
+ });
98
+ client.execute = executeMock;
99
+ await client.agentExecute({ mode: "dom" }, {
100
+ instruction: "fill the form with %username% and %password%",
101
+ variables: {
102
+ username: "john@example.com",
103
+ password: {
104
+ value: "secret",
105
+ description: "The login password",
106
+ },
107
+ },
108
+ });
109
+ (0, vitest_1.expect)(executeMock).toHaveBeenCalledWith({
110
+ method: "agentExecute",
111
+ args: {
112
+ agentConfig: {
113
+ systemPrompt: undefined,
114
+ mode: "dom",
115
+ cua: undefined,
116
+ model: undefined,
117
+ executionModel: undefined,
118
+ },
119
+ executeOptions: {
120
+ instruction: "fill the form with %username% and %password%",
121
+ variables: {
122
+ username: "john@example.com",
123
+ password: {
124
+ value: "secret",
125
+ description: "The login password",
126
+ },
127
+ },
128
+ },
129
+ frameId: undefined,
130
+ shouldCache: undefined,
131
+ },
132
+ });
133
+ });
85
134
  });
86
135
  //# sourceMappingURL=api-client-observe-variables.test.js.map