@browserbasehq/orca 3.5.0-vertex-test → 3.5.1-preview.0

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 (192) hide show
  1. package/README.md +7 -3
  2. package/dist/cjs/lib/utils.d.ts +2 -0
  3. package/dist/cjs/lib/utils.js +20 -0
  4. package/dist/cjs/lib/utils.js.map +1 -1
  5. package/dist/cjs/lib/v3/agent/AgentProvider.js +1 -0
  6. package/dist/cjs/lib/v3/agent/AgentProvider.js.map +1 -1
  7. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +1 -0
  8. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  9. package/dist/cjs/lib/v3/agent/utils/captureAriaTreeProbe.d.ts +35 -0
  10. package/dist/cjs/lib/v3/agent/utils/captureAriaTreeProbe.js +38 -0
  11. package/dist/cjs/lib/v3/agent/utils/captureAriaTreeProbe.js.map +1 -0
  12. package/dist/cjs/lib/v3/agent/utils/postStepProbeEvidence.d.ts +19 -0
  13. package/dist/cjs/lib/v3/agent/utils/postStepProbeEvidence.js +54 -0
  14. package/dist/cjs/lib/v3/agent/utils/postStepProbeEvidence.js.map +1 -0
  15. package/dist/cjs/lib/v3/agent/utils/toolOutputEvidence.d.ts +2 -0
  16. package/dist/cjs/lib/v3/agent/utils/toolOutputEvidence.js +62 -0
  17. package/dist/cjs/lib/v3/agent/utils/toolOutputEvidence.js.map +1 -0
  18. package/dist/cjs/lib/v3/agent/utils/wrapEvidenceCallback.d.ts +3 -0
  19. package/dist/cjs/lib/v3/agent/utils/wrapEvidenceCallback.js +25 -0
  20. package/dist/cjs/lib/v3/agent/utils/wrapEvidenceCallback.js.map +1 -0
  21. package/dist/cjs/lib/v3/api.d.ts +1 -0
  22. package/dist/cjs/lib/v3/api.js +37 -16
  23. package/dist/cjs/lib/v3/api.js.map +1 -1
  24. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.d.ts +24 -24
  25. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js +24 -24
  26. package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
  27. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
  28. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js +31 -0
  29. package/dist/cjs/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
  30. package/dist/cjs/lib/v3/dom/locatorScripts/xpathResolver.js +79 -10
  31. package/dist/cjs/lib/v3/dom/locatorScripts/xpathResolver.js.map +1 -1
  32. package/dist/cjs/lib/v3/handlers/v3AgentHandler.d.ts +1 -0
  33. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +83 -7
  34. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  35. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.d.ts +11 -0
  36. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js +119 -5
  37. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  38. package/dist/cjs/lib/v3/index.d.ts +13 -1
  39. package/dist/cjs/lib/v3/index.js +19 -1
  40. package/dist/cjs/lib/v3/index.js.map +1 -1
  41. package/dist/cjs/lib/v3/llm/LLMProvider.d.ts +3 -0
  42. package/dist/cjs/lib/v3/llm/LLMProvider.js +44 -3
  43. package/dist/cjs/lib/v3/llm/LLMProvider.js.map +1 -1
  44. package/dist/cjs/lib/v3/types/public/agent.d.ts +8 -2
  45. package/dist/cjs/lib/v3/types/public/agent.js +1 -0
  46. package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
  47. package/dist/cjs/lib/v3/types/public/agentEvidenceEvents.d.ts +85 -0
  48. package/dist/cjs/lib/v3/types/public/agentEvidenceEvents.js +15 -0
  49. package/dist/cjs/lib/v3/types/public/agentEvidenceEvents.js.map +1 -0
  50. package/dist/cjs/lib/v3/types/public/api.d.ts +925 -182
  51. package/dist/cjs/lib/v3/types/public/api.js +138 -20
  52. package/dist/cjs/lib/v3/types/public/api.js.map +1 -1
  53. package/dist/cjs/lib/v3/types/public/clipboard.d.ts +15 -0
  54. package/dist/cjs/lib/v3/types/public/clipboard.js +3 -0
  55. package/dist/cjs/lib/v3/types/public/clipboard.js.map +1 -0
  56. package/dist/cjs/lib/v3/types/public/index.d.ts +2 -0
  57. package/dist/cjs/lib/v3/types/public/index.js +2 -0
  58. package/dist/cjs/lib/v3/types/public/index.js.map +1 -1
  59. package/dist/cjs/lib/v3/types/public/model.d.ts +30 -6
  60. package/dist/cjs/lib/v3/types/public/model.js.map +1 -1
  61. package/dist/cjs/lib/v3/types/public/page.d.ts +29 -0
  62. package/dist/cjs/lib/v3/types/public/page.js.map +1 -1
  63. package/dist/cjs/lib/v3/types/public/sdkErrors.d.ts +3 -0
  64. package/dist/cjs/lib/v3/types/public/sdkErrors.js +8 -2
  65. package/dist/cjs/lib/v3/types/public/sdkErrors.js.map +1 -1
  66. package/dist/cjs/lib/v3/understudy/clipboard.d.ts +24 -0
  67. package/dist/cjs/lib/v3/understudy/clipboard.js +166 -0
  68. package/dist/cjs/lib/v3/understudy/clipboard.js.map +1 -0
  69. package/dist/cjs/lib/v3/understudy/context.d.ts +3 -0
  70. package/dist/cjs/lib/v3/understudy/context.js +15 -0
  71. package/dist/cjs/lib/v3/understudy/context.js.map +1 -1
  72. package/dist/cjs/lib/v3/understudy/page.d.ts +23 -1
  73. package/dist/cjs/lib/v3/understudy/page.js +283 -0
  74. package/dist/cjs/lib/v3/understudy/page.js.map +1 -1
  75. package/dist/cjs/lib/v3/v3.js +15 -6
  76. package/dist/cjs/lib/v3/v3.js.map +1 -1
  77. package/dist/cjs/lib/v3/verifier/evidenceNormalization.d.ts +7 -0
  78. package/dist/cjs/lib/v3/verifier/evidenceNormalization.js +100 -0
  79. package/dist/cjs/lib/v3/verifier/evidenceNormalization.js.map +1 -0
  80. package/dist/cjs/lib/v3/verifier/index.d.ts +6 -0
  81. package/dist/cjs/lib/v3/verifier/index.js +16 -0
  82. package/dist/cjs/lib/v3/verifier/index.js.map +1 -0
  83. package/dist/cjs/lib/v3/verifier/trajectory.d.ts +50 -0
  84. package/dist/cjs/lib/v3/verifier/trajectory.js +316 -0
  85. package/dist/cjs/lib/v3/verifier/trajectory.js.map +1 -0
  86. package/dist/cjs/lib/v3/verifier/types.d.ts +281 -0
  87. package/dist/cjs/lib/v3/verifier/types.js +10 -0
  88. package/dist/cjs/lib/v3/verifier/types.js.map +1 -0
  89. package/dist/cjs/lib/v3Evaluator.d.ts +9 -4
  90. package/dist/cjs/lib/v3Evaluator.js +148 -0
  91. package/dist/cjs/lib/v3Evaluator.js.map +1 -1
  92. package/dist/cjs/lib/v3LegacyEvaluator.js +5 -1
  93. package/dist/cjs/lib/v3LegacyEvaluator.js.map +1 -1
  94. package/dist/cjs/lib/version.d.ts +1 -1
  95. package/dist/cjs/lib/version.js +1 -1
  96. package/dist/cjs/lib/version.js.map +1 -1
  97. package/dist/esm/lib/utils.d.ts +2 -0
  98. package/dist/esm/lib/utils.js +18 -0
  99. package/dist/esm/lib/utils.js.map +1 -1
  100. package/dist/esm/lib/v3/agent/AgentProvider.js +1 -0
  101. package/dist/esm/lib/v3/agent/AgentProvider.js.map +1 -1
  102. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +1 -0
  103. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  104. package/dist/esm/lib/v3/agent/utils/captureAriaTreeProbe.d.ts +35 -0
  105. package/dist/esm/lib/v3/agent/utils/captureAriaTreeProbe.js +35 -0
  106. package/dist/esm/lib/v3/agent/utils/captureAriaTreeProbe.js.map +1 -0
  107. package/dist/esm/lib/v3/agent/utils/postStepProbeEvidence.d.ts +19 -0
  108. package/dist/esm/lib/v3/agent/utils/postStepProbeEvidence.js +50 -0
  109. package/dist/esm/lib/v3/agent/utils/postStepProbeEvidence.js.map +1 -0
  110. package/dist/esm/lib/v3/agent/utils/toolOutputEvidence.d.ts +2 -0
  111. package/dist/esm/lib/v3/agent/utils/toolOutputEvidence.js +59 -0
  112. package/dist/esm/lib/v3/agent/utils/toolOutputEvidence.js.map +1 -0
  113. package/dist/esm/lib/v3/agent/utils/wrapEvidenceCallback.d.ts +3 -0
  114. package/dist/esm/lib/v3/agent/utils/wrapEvidenceCallback.js +22 -0
  115. package/dist/esm/lib/v3/agent/utils/wrapEvidenceCallback.js.map +1 -0
  116. package/dist/esm/lib/v3/api.d.ts +1 -0
  117. package/dist/esm/lib/v3/api.js +38 -17
  118. package/dist/esm/lib/v3/api.js.map +1 -1
  119. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.d.ts +24 -24
  120. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js +24 -24
  121. package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
  122. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.d.ts +24 -0
  123. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js +28 -0
  124. package/dist/esm/lib/v3/dom/build/selectorRuntime.generated.js.map +1 -0
  125. package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.js +79 -10
  126. package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.js.map +1 -1
  127. package/dist/esm/lib/v3/handlers/v3AgentHandler.d.ts +1 -0
  128. package/dist/esm/lib/v3/handlers/v3AgentHandler.js +83 -7
  129. package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  130. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.d.ts +11 -0
  131. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +119 -5
  132. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  133. package/dist/esm/lib/v3/index.d.ts +13 -1
  134. package/dist/esm/lib/v3/index.js +10 -0
  135. package/dist/esm/lib/v3/index.js.map +1 -1
  136. package/dist/esm/lib/v3/llm/LLMProvider.d.ts +3 -0
  137. package/dist/esm/lib/v3/llm/LLMProvider.js +43 -3
  138. package/dist/esm/lib/v3/llm/LLMProvider.js.map +1 -1
  139. package/dist/esm/lib/v3/types/public/agent.d.ts +8 -2
  140. package/dist/esm/lib/v3/types/public/agent.js +1 -0
  141. package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
  142. package/dist/esm/lib/v3/types/public/agentEvidenceEvents.d.ts +85 -0
  143. package/dist/esm/lib/v3/types/public/agentEvidenceEvents.js +14 -0
  144. package/dist/esm/lib/v3/types/public/agentEvidenceEvents.js.map +1 -0
  145. package/dist/esm/lib/v3/types/public/api.d.ts +925 -182
  146. package/dist/esm/lib/v3/types/public/api.js +136 -18
  147. package/dist/esm/lib/v3/types/public/api.js.map +1 -1
  148. package/dist/esm/lib/v3/types/public/clipboard.d.ts +15 -0
  149. package/dist/esm/lib/v3/types/public/clipboard.js +2 -0
  150. package/dist/esm/lib/v3/types/public/clipboard.js.map +1 -0
  151. package/dist/esm/lib/v3/types/public/index.d.ts +2 -0
  152. package/dist/esm/lib/v3/types/public/index.js +2 -0
  153. package/dist/esm/lib/v3/types/public/index.js.map +1 -1
  154. package/dist/esm/lib/v3/types/public/model.d.ts +30 -6
  155. package/dist/esm/lib/v3/types/public/model.js.map +1 -1
  156. package/dist/esm/lib/v3/types/public/page.d.ts +29 -0
  157. package/dist/esm/lib/v3/types/public/page.js.map +1 -1
  158. package/dist/esm/lib/v3/types/public/sdkErrors.d.ts +3 -0
  159. package/dist/esm/lib/v3/types/public/sdkErrors.js +5 -0
  160. package/dist/esm/lib/v3/types/public/sdkErrors.js.map +1 -1
  161. package/dist/esm/lib/v3/understudy/clipboard.d.ts +24 -0
  162. package/dist/esm/lib/v3/understudy/clipboard.js +163 -0
  163. package/dist/esm/lib/v3/understudy/clipboard.js.map +1 -0
  164. package/dist/esm/lib/v3/understudy/context.d.ts +3 -0
  165. package/dist/esm/lib/v3/understudy/context.js +15 -0
  166. package/dist/esm/lib/v3/understudy/context.js.map +1 -1
  167. package/dist/esm/lib/v3/understudy/page.d.ts +23 -1
  168. package/dist/esm/lib/v3/understudy/page.js +284 -1
  169. package/dist/esm/lib/v3/understudy/page.js.map +1 -1
  170. package/dist/esm/lib/v3/v3.js +16 -7
  171. package/dist/esm/lib/v3/v3.js.map +1 -1
  172. package/dist/esm/lib/v3/verifier/evidenceNormalization.d.ts +7 -0
  173. package/dist/esm/lib/v3/verifier/evidenceNormalization.js +93 -0
  174. package/dist/esm/lib/v3/verifier/evidenceNormalization.js.map +1 -0
  175. package/dist/esm/lib/v3/verifier/index.d.ts +6 -0
  176. package/dist/esm/lib/v3/verifier/index.js +3 -0
  177. package/dist/esm/lib/v3/verifier/index.js.map +1 -0
  178. package/dist/esm/lib/v3/verifier/trajectory.d.ts +50 -0
  179. package/dist/esm/lib/v3/verifier/trajectory.js +273 -0
  180. package/dist/esm/lib/v3/verifier/trajectory.js.map +1 -0
  181. package/dist/esm/lib/v3/verifier/types.d.ts +281 -0
  182. package/dist/esm/lib/v3/verifier/types.js +9 -0
  183. package/dist/esm/lib/v3/verifier/types.js.map +1 -0
  184. package/dist/esm/lib/v3Evaluator.d.ts +9 -4
  185. package/dist/esm/lib/v3Evaluator.js +148 -0
  186. package/dist/esm/lib/v3Evaluator.js.map +1 -1
  187. package/dist/esm/lib/v3LegacyEvaluator.js +5 -1
  188. package/dist/esm/lib/v3LegacyEvaluator.js.map +1 -1
  189. package/dist/esm/lib/version.d.ts +1 -1
  190. package/dist/esm/lib/version.js +1 -1
  191. package/dist/esm/lib/version.js.map +1 -1
  192. package/package.json +16 -10
@@ -47,7 +47,7 @@ import { NavigationResponseTracker } from "./navigationResponseTracker.js";
47
47
  import { Response, isSerializableResponse } from "./response.js";
48
48
  import { ConsoleMessage } from "./consoleMessage.js";
49
49
  import { StagehandSetExtraHTTPHeadersError, StagehandSnapshotError, } from "../types/public/index.js";
50
- import { StagehandInvalidArgumentError, StagehandEvalError, } from "../types/public/sdkErrors.js";
50
+ import { StagehandInvalidArgumentError, StagehandEvalError, StagehandUnsupportedBrowserFeatureError, } from "../types/public/sdkErrors.js";
51
51
  import { normalizeInitScriptSource } from "./initScripts.js";
52
52
  import { buildLocatorInvocation } from "./locatorInvocation.js";
53
53
  import { applyMaskOverlays, applyStyleToFrames, collectFramesForScreenshot, computeScreenshotScale, disableAnimations, hideCaret, normalizeScreenshotClip, runScreenshotCleanups, setTransparentBackground, } from "./screenshotUtils.js";
@@ -70,8 +70,49 @@ const LIFECYCLE_NAME = {
70
70
  domcontentloaded: "DOMContentLoaded",
71
71
  networkidle: "networkIdle",
72
72
  };
73
+ const WEB_MCP_SUPPORT_MESSAGE = "Make sure you are using Chrome/Chromium newer than version 149 and that it is launched with --enable-features=WebMCPTesting,DevToolsWebMCPSupport.";
74
+ function createDeferred() {
75
+ let resolve;
76
+ let reject;
77
+ const promise = new Promise((res, rej) => {
78
+ resolve = res;
79
+ reject = rej;
80
+ });
81
+ return { promise, resolve, reject };
82
+ }
83
+ function stripWebMCPToolDebugFields(tool) {
84
+ const { name, description, inputSchema, annotations, frameId } = tool;
85
+ const publicAnnotations = annotations === undefined ? undefined : { ...annotations };
86
+ return {
87
+ name,
88
+ ...(description !== undefined && { description }),
89
+ ...(inputSchema !== undefined && { inputSchema }),
90
+ ...(publicAnnotations !== undefined && { annotations: publicAnnotations }),
91
+ frameId,
92
+ };
93
+ }
94
+ function webMCPResultFromEvent(invocationId, event) {
95
+ return {
96
+ invocationId,
97
+ status: event.status ?? "Error",
98
+ ...(event.output !== undefined && { output: event.output }),
99
+ ...(event.errorText !== undefined && { errorText: event.errorText }),
100
+ ...(event.exception !== undefined && { exception: event.exception }),
101
+ };
102
+ }
103
+ function isWebMCPUnsupportedBrowserError(error) {
104
+ if (error instanceof StagehandUnsupportedBrowserFeatureError)
105
+ return true;
106
+ const code = error?.code;
107
+ if (code === -32601)
108
+ return true;
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ return /method not found/i.test(message);
111
+ }
73
112
  let Page = (() => {
74
113
  let _instanceExtraInitializers = [];
114
+ let _listWebMCPTools_decorators;
115
+ let _invokeWebMCPTool_decorators;
75
116
  let _close_decorators;
76
117
  let _goto_decorators;
77
118
  let _reload_decorators;
@@ -91,6 +132,8 @@ let Page = (() => {
91
132
  return class Page {
92
133
  static {
93
134
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
135
+ _listWebMCPTools_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageListWebMCPTools" })];
136
+ _invokeWebMCPTool_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageInvokeWebMCPTool" })];
94
137
  _close_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageClose" })];
95
138
  _goto_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageGoto" })];
96
139
  _reload_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageReload" })];
@@ -117,6 +160,8 @@ let Page = (() => {
117
160
  _type_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageType" })];
118
161
  _keyPress_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageKeyPress" })];
119
162
  _snapshot_decorators = [FlowLogger.wrapWithLogging({ eventType: "PageSnapshot" })];
163
+ __esDecorate(this, null, _listWebMCPTools_decorators, { kind: "method", name: "listWebMCPTools", static: false, private: false, access: { has: obj => "listWebMCPTools" in obj, get: obj => obj.listWebMCPTools }, metadata: _metadata }, null, _instanceExtraInitializers);
164
+ __esDecorate(this, null, _invokeWebMCPTool_decorators, { kind: "method", name: "invokeWebMCPTool", static: false, private: false, access: { has: obj => "invokeWebMCPTool" in obj, get: obj => obj.invokeWebMCPTool }, metadata: _metadata }, null, _instanceExtraInitializers);
120
165
  __esDecorate(this, null, _close_decorators, { kind: "method", name: "close", static: false, private: false, access: { has: obj => "close" in obj, get: obj => obj.close }, metadata: _metadata }, null, _instanceExtraInitializers);
121
166
  __esDecorate(this, null, _goto_decorators, { kind: "method", name: "goto", static: false, private: false, access: { has: obj => "goto" in obj, get: obj => obj.goto }, metadata: _metadata }, null, _instanceExtraInitializers);
122
167
  __esDecorate(this, null, _reload_decorators, { kind: "method", name: "reload", static: false, private: false, access: { has: obj => "reload" in obj, get: obj => obj.reload }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -161,6 +206,10 @@ let Page = (() => {
161
206
  apiClient = null;
162
207
  consoleListeners = new Set();
163
208
  consoleHandlers = new Map();
209
+ webMCPEnablePromise = null;
210
+ pendingWebMCPInvocations = new Map();
211
+ bufferedWebMCPResults = new Map();
212
+ pendingWebMCPInvokeToolResponses = 0;
164
213
  /** Document-start scripts installed across every session this page owns. */
165
214
  initScripts = [];
166
215
  extraHTTPHeaders;
@@ -514,6 +563,154 @@ let Page = (() => {
514
563
  }
515
564
  return this;
516
565
  }
566
+ onWebMCPToolResponded = (event) => {
567
+ if (!event.invocationId)
568
+ return;
569
+ const result = webMCPResultFromEvent(event.invocationId, event);
570
+ const pending = this.pendingWebMCPInvocations.get(event.invocationId);
571
+ if (!pending) {
572
+ /*
573
+ * WebMCP.invokeTool returns the invocationId, while WebMCP.toolResponded
574
+ * is a separate event. Very fast tools can emit the event before the
575
+ * invokeTool command response reaches us, so there is not yet a pending
576
+ * invocation entry to resolve. Buffer only during that command-response
577
+ * window; otherwise unmatched events are stale or unexpected.
578
+ */
579
+ if (this.pendingWebMCPInvokeToolResponses > 0) {
580
+ this.bufferedWebMCPResults.set(event.invocationId, result);
581
+ }
582
+ return;
583
+ }
584
+ clearTimeout(pending.timer);
585
+ this.pendingWebMCPInvocations.delete(event.invocationId);
586
+ pending.deferred.resolve(result);
587
+ };
588
+ async ensureWebMCPEnabled() {
589
+ if (this.webMCPEnablePromise) {
590
+ return this.webMCPEnablePromise;
591
+ }
592
+ this.mainSession.on("WebMCP.toolResponded", this.onWebMCPToolResponded);
593
+ this.webMCPEnablePromise = this.mainSession
594
+ .send("WebMCP.enable")
595
+ .then(() => undefined)
596
+ .catch((error) => {
597
+ this.teardownWebMCP();
598
+ const message = error instanceof Error ? error.message : String(error);
599
+ if (isWebMCPUnsupportedBrowserError(error)) {
600
+ throw new StagehandUnsupportedBrowserFeatureError("WebMCP", `Unable to enable WebMCP. ${WEB_MCP_SUPPORT_MESSAGE} CDP error: ${message}`, error);
601
+ }
602
+ throw error;
603
+ });
604
+ return this.webMCPEnablePromise;
605
+ }
606
+ /**
607
+ * `WebMCP.enable` is the browser's source-of-truth snapshot trigger: CDP emits
608
+ * `WebMCP.toolsAdded` for all tools currently registered on the page. Keep
609
+ * this scoped to the list call so tools from old documents are not cached here.
610
+ */
611
+ async collectWebMCPToolsSnapshot(timeoutMs) {
612
+ const quietWindowMs = Math.min(100, Math.max(0, timeoutMs));
613
+ const tools = new Map();
614
+ let toolsVersion = 0;
615
+ let toolsLastUpdatedAt = null;
616
+ const toolKey = (tool) => `${tool.frameId}:${tool.name}`;
617
+ const onToolsAdded = (event) => {
618
+ if (!Array.isArray(event.tools))
619
+ return;
620
+ let changed = false;
621
+ for (const tool of event.tools) {
622
+ const normalized = stripWebMCPToolDebugFields(tool);
623
+ tools.set(toolKey(normalized), normalized);
624
+ changed = true;
625
+ }
626
+ if (!changed)
627
+ return;
628
+ toolsVersion += 1;
629
+ toolsLastUpdatedAt = Date.now();
630
+ schedule?.();
631
+ };
632
+ const onToolsRemoved = (event) => {
633
+ if (!Array.isArray(event.tools))
634
+ return;
635
+ let changed = false;
636
+ for (const tool of event.tools) {
637
+ changed = tools.delete(toolKey(tool)) || changed;
638
+ }
639
+ if (!changed)
640
+ return;
641
+ toolsVersion += 1;
642
+ toolsLastUpdatedAt = Date.now();
643
+ schedule?.();
644
+ };
645
+ const deadline = Date.now() + timeoutMs;
646
+ let schedule = null;
647
+ this.mainSession.on("WebMCP.toolsAdded", onToolsAdded);
648
+ this.mainSession.on("WebMCP.toolsRemoved", onToolsRemoved);
649
+ try {
650
+ await this.mainSession.send("WebMCP.enable");
651
+ if (quietWindowMs === 0)
652
+ return [...tools.values()];
653
+ await new Promise((resolve) => {
654
+ const startVersion = toolsVersion;
655
+ let quietTimer = null;
656
+ let timeoutTimer = null;
657
+ let done = false;
658
+ const cleanup = () => {
659
+ if (done)
660
+ return;
661
+ done = true;
662
+ if (quietTimer)
663
+ clearTimeout(quietTimer);
664
+ if (timeoutTimer)
665
+ clearTimeout(timeoutTimer);
666
+ resolve();
667
+ };
668
+ schedule = () => {
669
+ if (done)
670
+ return;
671
+ if (quietTimer) {
672
+ clearTimeout(quietTimer);
673
+ quietTimer = null;
674
+ }
675
+ const now = Date.now();
676
+ if (now >= deadline) {
677
+ cleanup();
678
+ return;
679
+ }
680
+ const sawToolsSinceStart = toolsVersion > startVersion;
681
+ const lastUpdate = toolsLastUpdatedAt;
682
+ const quietRemaining = sawToolsSinceStart && lastUpdate !== null
683
+ ? Math.max(0, quietWindowMs - (now - lastUpdate))
684
+ : quietWindowMs;
685
+ quietTimer = setTimeout(cleanup, Math.min(quietRemaining, deadline - now));
686
+ };
687
+ timeoutTimer = setTimeout(cleanup, timeoutMs);
688
+ schedule();
689
+ });
690
+ }
691
+ finally {
692
+ this.mainSession.off("WebMCP.toolsAdded", onToolsAdded);
693
+ this.mainSession.off("WebMCP.toolsRemoved", onToolsRemoved);
694
+ }
695
+ return [...tools.values()];
696
+ }
697
+ cleanupWebMCPInvocation(invocationId) {
698
+ const pending = this.pendingWebMCPInvocations.get(invocationId);
699
+ if (!pending)
700
+ return;
701
+ clearTimeout(pending.timer);
702
+ this.pendingWebMCPInvocations.delete(invocationId);
703
+ }
704
+ teardownWebMCP() {
705
+ this.mainSession.off("WebMCP.toolResponded", this.onWebMCPToolResponded);
706
+ for (const [invocationId, pending] of this.pendingWebMCPInvocations) {
707
+ clearTimeout(pending.timer);
708
+ pending.deferred.reject(new StagehandInvalidArgumentError(`WebMCP invocation "${invocationId}" was disposed before it completed.`));
709
+ }
710
+ this.pendingWebMCPInvocations.clear();
711
+ this.bufferedWebMCPResults.clear();
712
+ this.webMCPEnablePromise = null;
713
+ }
517
714
  // ---------------- MAIN APIs ----------------
518
715
  targetId() {
519
716
  return this._targetId;
@@ -540,6 +737,90 @@ let Page = (() => {
540
737
  sendCDP(method, params) {
541
738
  return this.mainSession.send(method, params);
542
739
  }
740
+ /**
741
+ * List WebMCP tools registered by the current page.
742
+ * CDP emits WebMCP.toolsAdded for all currently registered tools each time
743
+ * WebMCP.enable is called, so this method treats the browser as the source of
744
+ * truth and collects that per-call snapshot instead of keeping a tool cache.
745
+ */
746
+ async listWebMCPTools(options) {
747
+ const timeoutMs = options?.timeoutMs ?? 1_000;
748
+ try {
749
+ return await this.collectWebMCPToolsSnapshot(timeoutMs);
750
+ }
751
+ catch (error) {
752
+ if (error instanceof StagehandUnsupportedBrowserFeatureError)
753
+ throw error;
754
+ const message = error instanceof Error ? error.message : String(error);
755
+ if (isWebMCPUnsupportedBrowserError(error)) {
756
+ throw new StagehandUnsupportedBrowserFeatureError("WebMCP", `Unable to list WebMCP tools. ${WEB_MCP_SUPPORT_MESSAGE} CDP error: ${message}`, error);
757
+ }
758
+ throw error;
759
+ }
760
+ }
761
+ async invokeWebMCPTool(toolName, input, options) {
762
+ const timeoutMs = options?.timeoutMs ?? 30_000;
763
+ let frameId = options?.frameId;
764
+ if (!frameId) {
765
+ const matchingTools = (await this.listWebMCPTools()).filter((tool) => tool.name === toolName);
766
+ if (matchingTools.length === 0) {
767
+ throw new StagehandInvalidArgumentError(`Unable to invoke WebMCP tool "${toolName}" because it was not found on the current page.`);
768
+ }
769
+ if (matchingTools.length > 1) {
770
+ throw new StagehandInvalidArgumentError(`Unable to invoke WebMCP tool "${toolName}" because multiple frames registered a tool with that name. Pass options.frameId to disambiguate.`);
771
+ }
772
+ frameId = matchingTools[0].frameId;
773
+ }
774
+ const deferred = createDeferred();
775
+ let invocationId;
776
+ await this.ensureWebMCPEnabled();
777
+ try {
778
+ this.pendingWebMCPInvokeToolResponses += 1;
779
+ const response = await this.mainSession
780
+ .send("WebMCP.invokeTool", {
781
+ frameId,
782
+ toolName,
783
+ input,
784
+ })
785
+ .finally(() => {
786
+ this.pendingWebMCPInvokeToolResponses -= 1;
787
+ });
788
+ invocationId = response.invocationId;
789
+ }
790
+ catch (error) {
791
+ const message = error instanceof Error ? error.message : String(error);
792
+ if (isWebMCPUnsupportedBrowserError(error)) {
793
+ throw new StagehandUnsupportedBrowserFeatureError("WebMCP", `Unable to invoke WebMCP tool "${toolName}". ${WEB_MCP_SUPPORT_MESSAGE} CDP error: ${message}`, error);
794
+ }
795
+ throw error;
796
+ }
797
+ const bufferedResult = this.bufferedWebMCPResults.get(invocationId);
798
+ if (bufferedResult) {
799
+ this.bufferedWebMCPResults.delete(invocationId);
800
+ deferred.resolve(bufferedResult);
801
+ }
802
+ else {
803
+ const timer = setTimeout(() => {
804
+ this.cleanupWebMCPInvocation(invocationId);
805
+ deferred.reject(new StagehandInvalidArgumentError(`Timed out waiting for WebMCP tool "${toolName}" invocation result after ${timeoutMs}ms.`));
806
+ }, timeoutMs);
807
+ this.pendingWebMCPInvocations.set(invocationId, {
808
+ deferred,
809
+ timer,
810
+ });
811
+ }
812
+ return {
813
+ invocationId,
814
+ toolName,
815
+ frameId,
816
+ result: deferred.promise,
817
+ cancel: async () => {
818
+ await this.mainSession.send("WebMCP.cancelInvocation", {
819
+ invocationId,
820
+ });
821
+ },
822
+ };
823
+ }
543
824
  /** Seed the cached URL before navigation events converge. */
544
825
  seedCurrentUrl(url) {
545
826
  if (!url)
@@ -576,6 +857,7 @@ let Page = (() => {
576
857
  const targets = await this.conn.getTargets();
577
858
  if (!targets.some((t) => t.targetId === this._targetId)) {
578
859
  this.networkManager.dispose();
860
+ this.teardownWebMCP();
579
861
  return;
580
862
  }
581
863
  }
@@ -585,6 +867,7 @@ let Page = (() => {
585
867
  await new Promise((r) => setTimeout(r, 25));
586
868
  }
587
869
  this.networkManager.dispose();
870
+ this.teardownWebMCP();
588
871
  this.removeAllConsoleTaps();
589
872
  this.consoleListeners.clear();
590
873
  }