@browserbasehq/orca 3.5.0-preview.1 → 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.
- package/README.md +7 -3
- package/dist/cjs/lib/utils.d.ts +2 -0
- package/dist/cjs/lib/utils.js +20 -0
- package/dist/cjs/lib/utils.js.map +1 -1
- package/dist/cjs/lib/v3/agent/AgentProvider.js +1 -0
- package/dist/cjs/lib/v3/agent/AgentProvider.js.map +1 -1
- package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +1 -0
- package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
- package/dist/cjs/lib/v3/api.js +28 -33
- package/dist/cjs/lib/v3/api.js.map +1 -1
- package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.d.ts +24 -24
- package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js +24 -24
- package/dist/cjs/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
- package/dist/cjs/lib/v3/dom/locatorScripts/xpathResolver.js +79 -10
- package/dist/cjs/lib/v3/dom/locatorScripts/xpathResolver.js.map +1 -1
- package/dist/cjs/lib/v3/index.d.ts +2 -1
- package/dist/cjs/lib/v3/llm/LLMProvider.js +18 -2
- package/dist/cjs/lib/v3/llm/LLMProvider.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/agent.d.ts +2 -2
- package/dist/cjs/lib/v3/types/public/agent.js +1 -0
- package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/api.d.ts +538 -27
- package/dist/cjs/lib/v3/types/public/api.js +83 -7
- package/dist/cjs/lib/v3/types/public/api.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/clipboard.d.ts +15 -0
- package/dist/cjs/lib/v3/types/public/clipboard.js +3 -0
- package/dist/cjs/lib/v3/types/public/clipboard.js.map +1 -0
- package/dist/cjs/lib/v3/types/public/index.d.ts +1 -0
- package/dist/cjs/lib/v3/types/public/index.js +1 -0
- package/dist/cjs/lib/v3/types/public/index.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/model.d.ts +18 -3
- package/dist/cjs/lib/v3/types/public/model.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/page.d.ts +29 -0
- package/dist/cjs/lib/v3/types/public/page.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/sdkErrors.d.ts +3 -0
- package/dist/cjs/lib/v3/types/public/sdkErrors.js +8 -2
- package/dist/cjs/lib/v3/types/public/sdkErrors.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/clipboard.d.ts +24 -0
- package/dist/cjs/lib/v3/understudy/clipboard.js +166 -0
- package/dist/cjs/lib/v3/understudy/clipboard.js.map +1 -0
- package/dist/cjs/lib/v3/understudy/context.d.ts +3 -0
- package/dist/cjs/lib/v3/understudy/context.js +15 -0
- package/dist/cjs/lib/v3/understudy/context.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/page.d.ts +23 -1
- package/dist/cjs/lib/v3/understudy/page.js +283 -0
- package/dist/cjs/lib/v3/understudy/page.js.map +1 -1
- package/dist/cjs/lib/v3/v3.js +15 -6
- package/dist/cjs/lib/v3/v3.js.map +1 -1
- package/dist/cjs/lib/version.d.ts +1 -1
- package/dist/cjs/lib/version.js +1 -1
- package/dist/cjs/lib/version.js.map +1 -1
- package/dist/esm/lib/utils.d.ts +2 -0
- package/dist/esm/lib/utils.js +18 -0
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/lib/v3/agent/AgentProvider.js +1 -0
- package/dist/esm/lib/v3/agent/AgentProvider.js.map +1 -1
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +1 -0
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
- package/dist/esm/lib/v3/api.js +29 -34
- package/dist/esm/lib/v3/api.js.map +1 -1
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.d.ts +24 -24
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js +24 -24
- package/dist/esm/lib/v3/dom/build/locatorScripts.generated.js.map +1 -1
- package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.js +79 -10
- package/dist/esm/lib/v3/dom/locatorScripts/xpathResolver.js.map +1 -1
- package/dist/esm/lib/v3/index.d.ts +2 -1
- package/dist/esm/lib/v3/llm/LLMProvider.js +18 -2
- package/dist/esm/lib/v3/llm/LLMProvider.js.map +1 -1
- package/dist/esm/lib/v3/types/public/agent.d.ts +2 -2
- package/dist/esm/lib/v3/types/public/agent.js +1 -0
- package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
- package/dist/esm/lib/v3/types/public/api.d.ts +538 -27
- package/dist/esm/lib/v3/types/public/api.js +81 -5
- package/dist/esm/lib/v3/types/public/api.js.map +1 -1
- package/dist/esm/lib/v3/types/public/clipboard.d.ts +15 -0
- package/dist/esm/lib/v3/types/public/clipboard.js +2 -0
- package/dist/esm/lib/v3/types/public/clipboard.js.map +1 -0
- package/dist/esm/lib/v3/types/public/index.d.ts +1 -0
- package/dist/esm/lib/v3/types/public/index.js +1 -0
- package/dist/esm/lib/v3/types/public/index.js.map +1 -1
- package/dist/esm/lib/v3/types/public/model.d.ts +18 -3
- package/dist/esm/lib/v3/types/public/model.js.map +1 -1
- package/dist/esm/lib/v3/types/public/page.d.ts +29 -0
- package/dist/esm/lib/v3/types/public/page.js.map +1 -1
- package/dist/esm/lib/v3/types/public/sdkErrors.d.ts +3 -0
- package/dist/esm/lib/v3/types/public/sdkErrors.js +5 -0
- package/dist/esm/lib/v3/types/public/sdkErrors.js.map +1 -1
- package/dist/esm/lib/v3/understudy/clipboard.d.ts +24 -0
- package/dist/esm/lib/v3/understudy/clipboard.js +163 -0
- package/dist/esm/lib/v3/understudy/clipboard.js.map +1 -0
- package/dist/esm/lib/v3/understudy/context.d.ts +3 -0
- package/dist/esm/lib/v3/understudy/context.js +15 -0
- package/dist/esm/lib/v3/understudy/context.js.map +1 -1
- package/dist/esm/lib/v3/understudy/page.d.ts +23 -1
- package/dist/esm/lib/v3/understudy/page.js +284 -1
- package/dist/esm/lib/v3/understudy/page.js.map +1 -1
- package/dist/esm/lib/v3/v3.js +16 -7
- package/dist/esm/lib/v3/v3.js.map +1 -1
- package/dist/esm/lib/version.d.ts +1 -1
- package/dist/esm/lib/version.js +1 -1
- package/dist/esm/lib/version.js.map +1 -1
- package/package.json +13 -7
|
@@ -73,8 +73,49 @@ const LIFECYCLE_NAME = {
|
|
|
73
73
|
domcontentloaded: "DOMContentLoaded",
|
|
74
74
|
networkidle: "networkIdle",
|
|
75
75
|
};
|
|
76
|
+
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.";
|
|
77
|
+
function createDeferred() {
|
|
78
|
+
let resolve;
|
|
79
|
+
let reject;
|
|
80
|
+
const promise = new Promise((res, rej) => {
|
|
81
|
+
resolve = res;
|
|
82
|
+
reject = rej;
|
|
83
|
+
});
|
|
84
|
+
return { promise, resolve, reject };
|
|
85
|
+
}
|
|
86
|
+
function stripWebMCPToolDebugFields(tool) {
|
|
87
|
+
const { name, description, inputSchema, annotations, frameId } = tool;
|
|
88
|
+
const publicAnnotations = annotations === undefined ? undefined : { ...annotations };
|
|
89
|
+
return {
|
|
90
|
+
name,
|
|
91
|
+
...(description !== undefined && { description }),
|
|
92
|
+
...(inputSchema !== undefined && { inputSchema }),
|
|
93
|
+
...(publicAnnotations !== undefined && { annotations: publicAnnotations }),
|
|
94
|
+
frameId,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function webMCPResultFromEvent(invocationId, event) {
|
|
98
|
+
return {
|
|
99
|
+
invocationId,
|
|
100
|
+
status: event.status ?? "Error",
|
|
101
|
+
...(event.output !== undefined && { output: event.output }),
|
|
102
|
+
...(event.errorText !== undefined && { errorText: event.errorText }),
|
|
103
|
+
...(event.exception !== undefined && { exception: event.exception }),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function isWebMCPUnsupportedBrowserError(error) {
|
|
107
|
+
if (error instanceof sdkErrors_js_1.StagehandUnsupportedBrowserFeatureError)
|
|
108
|
+
return true;
|
|
109
|
+
const code = error?.code;
|
|
110
|
+
if (code === -32601)
|
|
111
|
+
return true;
|
|
112
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
113
|
+
return /method not found/i.test(message);
|
|
114
|
+
}
|
|
76
115
|
let Page = (() => {
|
|
77
116
|
let _instanceExtraInitializers = [];
|
|
117
|
+
let _listWebMCPTools_decorators;
|
|
118
|
+
let _invokeWebMCPTool_decorators;
|
|
78
119
|
let _close_decorators;
|
|
79
120
|
let _goto_decorators;
|
|
80
121
|
let _reload_decorators;
|
|
@@ -94,6 +135,8 @@ let Page = (() => {
|
|
|
94
135
|
return class Page {
|
|
95
136
|
static {
|
|
96
137
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
138
|
+
_listWebMCPTools_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageListWebMCPTools" })];
|
|
139
|
+
_invokeWebMCPTool_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageInvokeWebMCPTool" })];
|
|
97
140
|
_close_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageClose" })];
|
|
98
141
|
_goto_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageGoto" })];
|
|
99
142
|
_reload_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageReload" })];
|
|
@@ -120,6 +163,8 @@ let Page = (() => {
|
|
|
120
163
|
_type_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageType" })];
|
|
121
164
|
_keyPress_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageKeyPress" })];
|
|
122
165
|
_snapshot_decorators = [FlowLogger_js_1.FlowLogger.wrapWithLogging({ eventType: "PageSnapshot" })];
|
|
166
|
+
__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);
|
|
167
|
+
__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);
|
|
123
168
|
__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);
|
|
124
169
|
__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);
|
|
125
170
|
__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);
|
|
@@ -164,6 +209,10 @@ let Page = (() => {
|
|
|
164
209
|
apiClient = null;
|
|
165
210
|
consoleListeners = new Set();
|
|
166
211
|
consoleHandlers = new Map();
|
|
212
|
+
webMCPEnablePromise = null;
|
|
213
|
+
pendingWebMCPInvocations = new Map();
|
|
214
|
+
bufferedWebMCPResults = new Map();
|
|
215
|
+
pendingWebMCPInvokeToolResponses = 0;
|
|
167
216
|
/** Document-start scripts installed across every session this page owns. */
|
|
168
217
|
initScripts = [];
|
|
169
218
|
extraHTTPHeaders;
|
|
@@ -517,6 +566,154 @@ let Page = (() => {
|
|
|
517
566
|
}
|
|
518
567
|
return this;
|
|
519
568
|
}
|
|
569
|
+
onWebMCPToolResponded = (event) => {
|
|
570
|
+
if (!event.invocationId)
|
|
571
|
+
return;
|
|
572
|
+
const result = webMCPResultFromEvent(event.invocationId, event);
|
|
573
|
+
const pending = this.pendingWebMCPInvocations.get(event.invocationId);
|
|
574
|
+
if (!pending) {
|
|
575
|
+
/*
|
|
576
|
+
* WebMCP.invokeTool returns the invocationId, while WebMCP.toolResponded
|
|
577
|
+
* is a separate event. Very fast tools can emit the event before the
|
|
578
|
+
* invokeTool command response reaches us, so there is not yet a pending
|
|
579
|
+
* invocation entry to resolve. Buffer only during that command-response
|
|
580
|
+
* window; otherwise unmatched events are stale or unexpected.
|
|
581
|
+
*/
|
|
582
|
+
if (this.pendingWebMCPInvokeToolResponses > 0) {
|
|
583
|
+
this.bufferedWebMCPResults.set(event.invocationId, result);
|
|
584
|
+
}
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
clearTimeout(pending.timer);
|
|
588
|
+
this.pendingWebMCPInvocations.delete(event.invocationId);
|
|
589
|
+
pending.deferred.resolve(result);
|
|
590
|
+
};
|
|
591
|
+
async ensureWebMCPEnabled() {
|
|
592
|
+
if (this.webMCPEnablePromise) {
|
|
593
|
+
return this.webMCPEnablePromise;
|
|
594
|
+
}
|
|
595
|
+
this.mainSession.on("WebMCP.toolResponded", this.onWebMCPToolResponded);
|
|
596
|
+
this.webMCPEnablePromise = this.mainSession
|
|
597
|
+
.send("WebMCP.enable")
|
|
598
|
+
.then(() => undefined)
|
|
599
|
+
.catch((error) => {
|
|
600
|
+
this.teardownWebMCP();
|
|
601
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
602
|
+
if (isWebMCPUnsupportedBrowserError(error)) {
|
|
603
|
+
throw new sdkErrors_js_1.StagehandUnsupportedBrowserFeatureError("WebMCP", `Unable to enable WebMCP. ${WEB_MCP_SUPPORT_MESSAGE} CDP error: ${message}`, error);
|
|
604
|
+
}
|
|
605
|
+
throw error;
|
|
606
|
+
});
|
|
607
|
+
return this.webMCPEnablePromise;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* `WebMCP.enable` is the browser's source-of-truth snapshot trigger: CDP emits
|
|
611
|
+
* `WebMCP.toolsAdded` for all tools currently registered on the page. Keep
|
|
612
|
+
* this scoped to the list call so tools from old documents are not cached here.
|
|
613
|
+
*/
|
|
614
|
+
async collectWebMCPToolsSnapshot(timeoutMs) {
|
|
615
|
+
const quietWindowMs = Math.min(100, Math.max(0, timeoutMs));
|
|
616
|
+
const tools = new Map();
|
|
617
|
+
let toolsVersion = 0;
|
|
618
|
+
let toolsLastUpdatedAt = null;
|
|
619
|
+
const toolKey = (tool) => `${tool.frameId}:${tool.name}`;
|
|
620
|
+
const onToolsAdded = (event) => {
|
|
621
|
+
if (!Array.isArray(event.tools))
|
|
622
|
+
return;
|
|
623
|
+
let changed = false;
|
|
624
|
+
for (const tool of event.tools) {
|
|
625
|
+
const normalized = stripWebMCPToolDebugFields(tool);
|
|
626
|
+
tools.set(toolKey(normalized), normalized);
|
|
627
|
+
changed = true;
|
|
628
|
+
}
|
|
629
|
+
if (!changed)
|
|
630
|
+
return;
|
|
631
|
+
toolsVersion += 1;
|
|
632
|
+
toolsLastUpdatedAt = Date.now();
|
|
633
|
+
schedule?.();
|
|
634
|
+
};
|
|
635
|
+
const onToolsRemoved = (event) => {
|
|
636
|
+
if (!Array.isArray(event.tools))
|
|
637
|
+
return;
|
|
638
|
+
let changed = false;
|
|
639
|
+
for (const tool of event.tools) {
|
|
640
|
+
changed = tools.delete(toolKey(tool)) || changed;
|
|
641
|
+
}
|
|
642
|
+
if (!changed)
|
|
643
|
+
return;
|
|
644
|
+
toolsVersion += 1;
|
|
645
|
+
toolsLastUpdatedAt = Date.now();
|
|
646
|
+
schedule?.();
|
|
647
|
+
};
|
|
648
|
+
const deadline = Date.now() + timeoutMs;
|
|
649
|
+
let schedule = null;
|
|
650
|
+
this.mainSession.on("WebMCP.toolsAdded", onToolsAdded);
|
|
651
|
+
this.mainSession.on("WebMCP.toolsRemoved", onToolsRemoved);
|
|
652
|
+
try {
|
|
653
|
+
await this.mainSession.send("WebMCP.enable");
|
|
654
|
+
if (quietWindowMs === 0)
|
|
655
|
+
return [...tools.values()];
|
|
656
|
+
await new Promise((resolve) => {
|
|
657
|
+
const startVersion = toolsVersion;
|
|
658
|
+
let quietTimer = null;
|
|
659
|
+
let timeoutTimer = null;
|
|
660
|
+
let done = false;
|
|
661
|
+
const cleanup = () => {
|
|
662
|
+
if (done)
|
|
663
|
+
return;
|
|
664
|
+
done = true;
|
|
665
|
+
if (quietTimer)
|
|
666
|
+
clearTimeout(quietTimer);
|
|
667
|
+
if (timeoutTimer)
|
|
668
|
+
clearTimeout(timeoutTimer);
|
|
669
|
+
resolve();
|
|
670
|
+
};
|
|
671
|
+
schedule = () => {
|
|
672
|
+
if (done)
|
|
673
|
+
return;
|
|
674
|
+
if (quietTimer) {
|
|
675
|
+
clearTimeout(quietTimer);
|
|
676
|
+
quietTimer = null;
|
|
677
|
+
}
|
|
678
|
+
const now = Date.now();
|
|
679
|
+
if (now >= deadline) {
|
|
680
|
+
cleanup();
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const sawToolsSinceStart = toolsVersion > startVersion;
|
|
684
|
+
const lastUpdate = toolsLastUpdatedAt;
|
|
685
|
+
const quietRemaining = sawToolsSinceStart && lastUpdate !== null
|
|
686
|
+
? Math.max(0, quietWindowMs - (now - lastUpdate))
|
|
687
|
+
: quietWindowMs;
|
|
688
|
+
quietTimer = setTimeout(cleanup, Math.min(quietRemaining, deadline - now));
|
|
689
|
+
};
|
|
690
|
+
timeoutTimer = setTimeout(cleanup, timeoutMs);
|
|
691
|
+
schedule();
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
finally {
|
|
695
|
+
this.mainSession.off("WebMCP.toolsAdded", onToolsAdded);
|
|
696
|
+
this.mainSession.off("WebMCP.toolsRemoved", onToolsRemoved);
|
|
697
|
+
}
|
|
698
|
+
return [...tools.values()];
|
|
699
|
+
}
|
|
700
|
+
cleanupWebMCPInvocation(invocationId) {
|
|
701
|
+
const pending = this.pendingWebMCPInvocations.get(invocationId);
|
|
702
|
+
if (!pending)
|
|
703
|
+
return;
|
|
704
|
+
clearTimeout(pending.timer);
|
|
705
|
+
this.pendingWebMCPInvocations.delete(invocationId);
|
|
706
|
+
}
|
|
707
|
+
teardownWebMCP() {
|
|
708
|
+
this.mainSession.off("WebMCP.toolResponded", this.onWebMCPToolResponded);
|
|
709
|
+
for (const [invocationId, pending] of this.pendingWebMCPInvocations) {
|
|
710
|
+
clearTimeout(pending.timer);
|
|
711
|
+
pending.deferred.reject(new sdkErrors_js_1.StagehandInvalidArgumentError(`WebMCP invocation "${invocationId}" was disposed before it completed.`));
|
|
712
|
+
}
|
|
713
|
+
this.pendingWebMCPInvocations.clear();
|
|
714
|
+
this.bufferedWebMCPResults.clear();
|
|
715
|
+
this.webMCPEnablePromise = null;
|
|
716
|
+
}
|
|
520
717
|
// ---------------- MAIN APIs ----------------
|
|
521
718
|
targetId() {
|
|
522
719
|
return this._targetId;
|
|
@@ -543,6 +740,90 @@ let Page = (() => {
|
|
|
543
740
|
sendCDP(method, params) {
|
|
544
741
|
return this.mainSession.send(method, params);
|
|
545
742
|
}
|
|
743
|
+
/**
|
|
744
|
+
* List WebMCP tools registered by the current page.
|
|
745
|
+
* CDP emits WebMCP.toolsAdded for all currently registered tools each time
|
|
746
|
+
* WebMCP.enable is called, so this method treats the browser as the source of
|
|
747
|
+
* truth and collects that per-call snapshot instead of keeping a tool cache.
|
|
748
|
+
*/
|
|
749
|
+
async listWebMCPTools(options) {
|
|
750
|
+
const timeoutMs = options?.timeoutMs ?? 1_000;
|
|
751
|
+
try {
|
|
752
|
+
return await this.collectWebMCPToolsSnapshot(timeoutMs);
|
|
753
|
+
}
|
|
754
|
+
catch (error) {
|
|
755
|
+
if (error instanceof sdkErrors_js_1.StagehandUnsupportedBrowserFeatureError)
|
|
756
|
+
throw error;
|
|
757
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
758
|
+
if (isWebMCPUnsupportedBrowserError(error)) {
|
|
759
|
+
throw new sdkErrors_js_1.StagehandUnsupportedBrowserFeatureError("WebMCP", `Unable to list WebMCP tools. ${WEB_MCP_SUPPORT_MESSAGE} CDP error: ${message}`, error);
|
|
760
|
+
}
|
|
761
|
+
throw error;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
async invokeWebMCPTool(toolName, input, options) {
|
|
765
|
+
const timeoutMs = options?.timeoutMs ?? 30_000;
|
|
766
|
+
let frameId = options?.frameId;
|
|
767
|
+
if (!frameId) {
|
|
768
|
+
const matchingTools = (await this.listWebMCPTools()).filter((tool) => tool.name === toolName);
|
|
769
|
+
if (matchingTools.length === 0) {
|
|
770
|
+
throw new sdkErrors_js_1.StagehandInvalidArgumentError(`Unable to invoke WebMCP tool "${toolName}" because it was not found on the current page.`);
|
|
771
|
+
}
|
|
772
|
+
if (matchingTools.length > 1) {
|
|
773
|
+
throw new sdkErrors_js_1.StagehandInvalidArgumentError(`Unable to invoke WebMCP tool "${toolName}" because multiple frames registered a tool with that name. Pass options.frameId to disambiguate.`);
|
|
774
|
+
}
|
|
775
|
+
frameId = matchingTools[0].frameId;
|
|
776
|
+
}
|
|
777
|
+
const deferred = createDeferred();
|
|
778
|
+
let invocationId;
|
|
779
|
+
await this.ensureWebMCPEnabled();
|
|
780
|
+
try {
|
|
781
|
+
this.pendingWebMCPInvokeToolResponses += 1;
|
|
782
|
+
const response = await this.mainSession
|
|
783
|
+
.send("WebMCP.invokeTool", {
|
|
784
|
+
frameId,
|
|
785
|
+
toolName,
|
|
786
|
+
input,
|
|
787
|
+
})
|
|
788
|
+
.finally(() => {
|
|
789
|
+
this.pendingWebMCPInvokeToolResponses -= 1;
|
|
790
|
+
});
|
|
791
|
+
invocationId = response.invocationId;
|
|
792
|
+
}
|
|
793
|
+
catch (error) {
|
|
794
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
795
|
+
if (isWebMCPUnsupportedBrowserError(error)) {
|
|
796
|
+
throw new sdkErrors_js_1.StagehandUnsupportedBrowserFeatureError("WebMCP", `Unable to invoke WebMCP tool "${toolName}". ${WEB_MCP_SUPPORT_MESSAGE} CDP error: ${message}`, error);
|
|
797
|
+
}
|
|
798
|
+
throw error;
|
|
799
|
+
}
|
|
800
|
+
const bufferedResult = this.bufferedWebMCPResults.get(invocationId);
|
|
801
|
+
if (bufferedResult) {
|
|
802
|
+
this.bufferedWebMCPResults.delete(invocationId);
|
|
803
|
+
deferred.resolve(bufferedResult);
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
const timer = setTimeout(() => {
|
|
807
|
+
this.cleanupWebMCPInvocation(invocationId);
|
|
808
|
+
deferred.reject(new sdkErrors_js_1.StagehandInvalidArgumentError(`Timed out waiting for WebMCP tool "${toolName}" invocation result after ${timeoutMs}ms.`));
|
|
809
|
+
}, timeoutMs);
|
|
810
|
+
this.pendingWebMCPInvocations.set(invocationId, {
|
|
811
|
+
deferred,
|
|
812
|
+
timer,
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
return {
|
|
816
|
+
invocationId,
|
|
817
|
+
toolName,
|
|
818
|
+
frameId,
|
|
819
|
+
result: deferred.promise,
|
|
820
|
+
cancel: async () => {
|
|
821
|
+
await this.mainSession.send("WebMCP.cancelInvocation", {
|
|
822
|
+
invocationId,
|
|
823
|
+
});
|
|
824
|
+
},
|
|
825
|
+
};
|
|
826
|
+
}
|
|
546
827
|
/** Seed the cached URL before navigation events converge. */
|
|
547
828
|
seedCurrentUrl(url) {
|
|
548
829
|
if (!url)
|
|
@@ -579,6 +860,7 @@ let Page = (() => {
|
|
|
579
860
|
const targets = await this.conn.getTargets();
|
|
580
861
|
if (!targets.some((t) => t.targetId === this._targetId)) {
|
|
581
862
|
this.networkManager.dispose();
|
|
863
|
+
this.teardownWebMCP();
|
|
582
864
|
return;
|
|
583
865
|
}
|
|
584
866
|
}
|
|
@@ -588,6 +870,7 @@ let Page = (() => {
|
|
|
588
870
|
await new Promise((r) => setTimeout(r, 25));
|
|
589
871
|
}
|
|
590
872
|
this.networkManager.dispose();
|
|
873
|
+
this.teardownWebMCP();
|
|
591
874
|
this.removeAllConsoleTaps();
|
|
592
875
|
this.consoleListeners.clear();
|
|
593
876
|
}
|