@playwright/mcp 0.0.14 → 0.0.15
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/lib/context.js +15 -5
- package/lib/index.js +3 -0
- package/lib/server.js +8 -1
- package/lib/tools/common.js +17 -22
- package/lib/tools/console.js +5 -6
- package/lib/tools/dialogs.js +8 -10
- package/lib/tools/files.js +7 -9
- package/lib/tools/install.js +4 -4
- package/lib/tools/keyboard.js +8 -13
- package/lib/tools/navigate.js +12 -16
- package/lib/tools/network.js +51 -0
- package/lib/tools/pdf.js +4 -5
- package/lib/tools/screen.js +45 -53
- package/lib/tools/snapshot.js +50 -57
- package/lib/tools/tabs.js +21 -27
- package/lib/tools/tool.js +4 -0
- package/package.json +3 -3
package/lib/context.js
CHANGED
|
@@ -131,7 +131,7 @@ class Context {
|
|
|
131
131
|
}
|
|
132
132
|
async run(tool, params) {
|
|
133
133
|
// Tab management is done outside of the action() call.
|
|
134
|
-
const toolResult = await tool.handle(this, params);
|
|
134
|
+
const toolResult = await tool.handle(this, tool.schema.inputSchema.parse(params));
|
|
135
135
|
const { code, action, waitForNetwork, captureSnapshot, resultOverride } = toolResult;
|
|
136
136
|
const racingAction = action ? () => this._raceAgainstModalDialogs(action) : undefined;
|
|
137
137
|
if (resultOverride)
|
|
@@ -298,6 +298,7 @@ class Tab {
|
|
|
298
298
|
context;
|
|
299
299
|
page;
|
|
300
300
|
_console = [];
|
|
301
|
+
_requests = new Map();
|
|
301
302
|
_snapshot;
|
|
302
303
|
_onPageClose;
|
|
303
304
|
constructor(context, page, onPageClose) {
|
|
@@ -305,9 +306,11 @@ class Tab {
|
|
|
305
306
|
this.page = page;
|
|
306
307
|
this._onPageClose = onPageClose;
|
|
307
308
|
page.on('console', event => this._console.push(event));
|
|
309
|
+
page.on('request', request => this._requests.set(request, null));
|
|
310
|
+
page.on('response', response => this._requests.set(response.request(), response));
|
|
308
311
|
page.on('framenavigated', frame => {
|
|
309
312
|
if (!frame.parentFrame())
|
|
310
|
-
this.
|
|
313
|
+
this._clearCollectedArtifacts();
|
|
311
314
|
});
|
|
312
315
|
page.on('close', () => this._onClose());
|
|
313
316
|
page.on('filechooser', chooser => {
|
|
@@ -321,8 +324,12 @@ class Tab {
|
|
|
321
324
|
page.setDefaultNavigationTimeout(60000);
|
|
322
325
|
page.setDefaultTimeout(5000);
|
|
323
326
|
}
|
|
324
|
-
|
|
327
|
+
_clearCollectedArtifacts() {
|
|
325
328
|
this._console.length = 0;
|
|
329
|
+
this._requests.clear();
|
|
330
|
+
}
|
|
331
|
+
_onClose() {
|
|
332
|
+
this._clearCollectedArtifacts();
|
|
326
333
|
this._onPageClose(this);
|
|
327
334
|
}
|
|
328
335
|
async navigate(url) {
|
|
@@ -338,9 +345,12 @@ class Tab {
|
|
|
338
345
|
throw new Error('No snapshot available');
|
|
339
346
|
return this._snapshot;
|
|
340
347
|
}
|
|
341
|
-
|
|
348
|
+
console() {
|
|
342
349
|
return this._console;
|
|
343
350
|
}
|
|
351
|
+
requests() {
|
|
352
|
+
return this._requests;
|
|
353
|
+
}
|
|
344
354
|
async captureSnapshot() {
|
|
345
355
|
this._snapshot = await PageSnapshot.create(this.page);
|
|
346
356
|
}
|
|
@@ -370,7 +380,7 @@ class PageSnapshot {
|
|
|
370
380
|
}
|
|
371
381
|
async _snapshotFrame(frame) {
|
|
372
382
|
const frameIndex = this._frameLocators.push(frame) - 1;
|
|
373
|
-
const snapshotString = await frame.locator('body').ariaSnapshot({ ref: true });
|
|
383
|
+
const snapshotString = await frame.locator('body').ariaSnapshot({ ref: true, emitGeneric: true });
|
|
374
384
|
const snapshot = yaml_1.default.parseDocument(snapshotString);
|
|
375
385
|
const visit = async (node) => {
|
|
376
386
|
if (yaml_1.default.isPair(node)) {
|
package/lib/index.js
CHANGED
|
@@ -30,6 +30,7 @@ const files_1 = __importDefault(require("./tools/files"));
|
|
|
30
30
|
const install_1 = __importDefault(require("./tools/install"));
|
|
31
31
|
const keyboard_1 = __importDefault(require("./tools/keyboard"));
|
|
32
32
|
const navigate_1 = __importDefault(require("./tools/navigate"));
|
|
33
|
+
const network_1 = __importDefault(require("./tools/network"));
|
|
33
34
|
const pdf_1 = __importDefault(require("./tools/pdf"));
|
|
34
35
|
const snapshot_1 = __importDefault(require("./tools/snapshot"));
|
|
35
36
|
const tabs_1 = __importDefault(require("./tools/tabs"));
|
|
@@ -42,6 +43,7 @@ const snapshotTools = [
|
|
|
42
43
|
...install_1.default,
|
|
43
44
|
...(0, keyboard_1.default)(true),
|
|
44
45
|
...(0, navigate_1.default)(true),
|
|
46
|
+
...network_1.default,
|
|
45
47
|
...pdf_1.default,
|
|
46
48
|
...snapshot_1.default,
|
|
47
49
|
...(0, tabs_1.default)(true),
|
|
@@ -54,6 +56,7 @@ const screenshotTools = [
|
|
|
54
56
|
...install_1.default,
|
|
55
57
|
...(0, keyboard_1.default)(false),
|
|
56
58
|
...(0, navigate_1.default)(false),
|
|
59
|
+
...network_1.default,
|
|
57
60
|
...pdf_1.default,
|
|
58
61
|
...screen_1.default,
|
|
59
62
|
...(0, tabs_1.default)(false),
|
package/lib/server.js
CHANGED
|
@@ -19,6 +19,7 @@ exports.ServerList = void 0;
|
|
|
19
19
|
exports.createServerWithTools = createServerWithTools;
|
|
20
20
|
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
21
21
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
22
|
+
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
22
23
|
const context_1 = require("./context");
|
|
23
24
|
function createServerWithTools(options) {
|
|
24
25
|
const { name, version, tools, resources } = options;
|
|
@@ -30,7 +31,13 @@ function createServerWithTools(options) {
|
|
|
30
31
|
}
|
|
31
32
|
});
|
|
32
33
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
33
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
tools: tools.map(tool => ({
|
|
36
|
+
name: tool.schema.name,
|
|
37
|
+
description: tool.schema.description,
|
|
38
|
+
inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(tool.schema.inputSchema)
|
|
39
|
+
})),
|
|
40
|
+
};
|
|
34
41
|
});
|
|
35
42
|
server.setRequestHandler(types_js_1.ListResourcesRequestSchema, async () => {
|
|
36
43
|
return { resources: resources.map(resource => resource.schema) };
|
package/lib/tools/common.js
CHANGED
|
@@ -16,34 +16,31 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const zod_1 = require("zod");
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
time: zod_1.z.number().describe('The time to wait in seconds'),
|
|
22
|
-
});
|
|
23
|
-
const wait = captureSnapshot => ({
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const wait = captureSnapshot => (0, tool_1.defineTool)({
|
|
24
21
|
capability: 'wait',
|
|
25
22
|
schema: {
|
|
26
23
|
name: 'browser_wait',
|
|
27
24
|
description: 'Wait for a specified time in seconds',
|
|
28
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({
|
|
26
|
+
time: zod_1.z.number().describe('The time to wait in seconds'),
|
|
27
|
+
}),
|
|
29
28
|
},
|
|
30
29
|
handle: async (context, params) => {
|
|
31
|
-
|
|
32
|
-
await new Promise(f => setTimeout(f, Math.min(10000, validatedParams.time * 1000)));
|
|
30
|
+
await new Promise(f => setTimeout(f, Math.min(10000, params.time * 1000)));
|
|
33
31
|
return {
|
|
34
|
-
code: [`// Waited for ${
|
|
32
|
+
code: [`// Waited for ${params.time} seconds`],
|
|
35
33
|
captureSnapshot,
|
|
36
34
|
waitForNetwork: false,
|
|
37
35
|
};
|
|
38
36
|
},
|
|
39
37
|
});
|
|
40
|
-
const
|
|
41
|
-
const close = {
|
|
38
|
+
const close = (0, tool_1.defineTool)({
|
|
42
39
|
capability: 'core',
|
|
43
40
|
schema: {
|
|
44
41
|
name: 'browser_close',
|
|
45
42
|
description: 'Close the page',
|
|
46
|
-
inputSchema:
|
|
43
|
+
inputSchema: zod_1.z.object({}),
|
|
47
44
|
},
|
|
48
45
|
handle: async (context) => {
|
|
49
46
|
await context.close();
|
|
@@ -53,27 +50,25 @@ const close = {
|
|
|
53
50
|
waitForNetwork: false,
|
|
54
51
|
};
|
|
55
52
|
},
|
|
56
|
-
};
|
|
57
|
-
const resizeSchema = zod_1.z.object({
|
|
58
|
-
width: zod_1.z.number().describe('Width of the browser window'),
|
|
59
|
-
height: zod_1.z.number().describe('Height of the browser window'),
|
|
60
53
|
});
|
|
61
|
-
const resize = captureSnapshot => ({
|
|
54
|
+
const resize = captureSnapshot => (0, tool_1.defineTool)({
|
|
62
55
|
capability: 'core',
|
|
63
56
|
schema: {
|
|
64
57
|
name: 'browser_resize',
|
|
65
58
|
description: 'Resize the browser window',
|
|
66
|
-
inputSchema:
|
|
59
|
+
inputSchema: zod_1.z.object({
|
|
60
|
+
width: zod_1.z.number().describe('Width of the browser window'),
|
|
61
|
+
height: zod_1.z.number().describe('Height of the browser window'),
|
|
62
|
+
}),
|
|
67
63
|
},
|
|
68
64
|
handle: async (context, params) => {
|
|
69
|
-
const validatedParams = resizeSchema.parse(params);
|
|
70
65
|
const tab = context.currentTabOrDie();
|
|
71
66
|
const code = [
|
|
72
|
-
`// Resize browser window to ${
|
|
73
|
-
`await page.setViewportSize({ width: ${
|
|
67
|
+
`// Resize browser window to ${params.width}x${params.height}`,
|
|
68
|
+
`await page.setViewportSize({ width: ${params.width}, height: ${params.height} });`
|
|
74
69
|
];
|
|
75
70
|
const action = async () => {
|
|
76
|
-
await tab.page.setViewportSize({ width:
|
|
71
|
+
await tab.page.setViewportSize({ width: params.width, height: params.height });
|
|
77
72
|
};
|
|
78
73
|
return {
|
|
79
74
|
code,
|
package/lib/tools/console.js
CHANGED
|
@@ -16,17 +16,16 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const zod_1 = require("zod");
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const console = {
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const console = (0, tool_1.defineTool)({
|
|
22
21
|
capability: 'core',
|
|
23
22
|
schema: {
|
|
24
23
|
name: 'browser_console_messages',
|
|
25
24
|
description: 'Returns all console messages',
|
|
26
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({}),
|
|
27
26
|
},
|
|
28
27
|
handle: async (context) => {
|
|
29
|
-
const messages =
|
|
28
|
+
const messages = context.currentTabOrDie().console();
|
|
30
29
|
const log = messages.map(message => `[${message.type().toUpperCase()}] ${message.text()}`).join('\n');
|
|
31
30
|
return {
|
|
32
31
|
code: [`// <internal code to get console messages>`],
|
|
@@ -39,7 +38,7 @@ const console = {
|
|
|
39
38
|
waitForNetwork: false,
|
|
40
39
|
};
|
|
41
40
|
},
|
|
42
|
-
};
|
|
41
|
+
});
|
|
43
42
|
exports.default = [
|
|
44
43
|
console,
|
|
45
44
|
];
|
package/lib/tools/dialogs.js
CHANGED
|
@@ -16,25 +16,23 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const zod_1 = require("zod");
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
accept: zod_1.z.boolean().describe('Whether to accept the dialog.'),
|
|
22
|
-
promptText: zod_1.z.string().optional().describe('The text of the prompt in case of a prompt dialog.'),
|
|
23
|
-
});
|
|
24
|
-
const handleDialog = captureSnapshot => ({
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const handleDialog = captureSnapshot => (0, tool_1.defineTool)({
|
|
25
21
|
capability: 'core',
|
|
26
22
|
schema: {
|
|
27
23
|
name: 'browser_handle_dialog',
|
|
28
24
|
description: 'Handle a dialog',
|
|
29
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({
|
|
26
|
+
accept: zod_1.z.boolean().describe('Whether to accept the dialog.'),
|
|
27
|
+
promptText: zod_1.z.string().optional().describe('The text of the prompt in case of a prompt dialog.'),
|
|
28
|
+
}),
|
|
30
29
|
},
|
|
31
30
|
handle: async (context, params) => {
|
|
32
|
-
const validatedParams = handleDialogSchema.parse(params);
|
|
33
31
|
const dialogState = context.modalStates().find(state => state.type === 'dialog');
|
|
34
32
|
if (!dialogState)
|
|
35
33
|
throw new Error('No dialog visible');
|
|
36
|
-
if (
|
|
37
|
-
await dialogState.dialog.accept(
|
|
34
|
+
if (params.accept)
|
|
35
|
+
await dialogState.dialog.accept(params.promptText);
|
|
38
36
|
else
|
|
39
37
|
await dialogState.dialog.dismiss();
|
|
40
38
|
context.clearModalState(dialogState);
|
package/lib/tools/files.js
CHANGED
|
@@ -16,27 +16,25 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const zod_1 = require("zod");
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
paths: zod_1.z.array(zod_1.z.string()).describe('The absolute paths to the files to upload. Can be a single file or multiple files.'),
|
|
22
|
-
});
|
|
23
|
-
const uploadFile = captureSnapshot => ({
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const uploadFile = captureSnapshot => (0, tool_1.defineTool)({
|
|
24
21
|
capability: 'files',
|
|
25
22
|
schema: {
|
|
26
23
|
name: 'browser_file_upload',
|
|
27
24
|
description: 'Upload one or multiple files',
|
|
28
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({
|
|
26
|
+
paths: zod_1.z.array(zod_1.z.string()).describe('The absolute paths to the files to upload. Can be a single file or multiple files.'),
|
|
27
|
+
}),
|
|
29
28
|
},
|
|
30
29
|
handle: async (context, params) => {
|
|
31
|
-
const validatedParams = uploadFileSchema.parse(params);
|
|
32
30
|
const modalState = context.modalStates().find(state => state.type === 'fileChooser');
|
|
33
31
|
if (!modalState)
|
|
34
32
|
throw new Error('No file chooser visible');
|
|
35
33
|
const code = [
|
|
36
|
-
`// <internal code to chose files ${
|
|
34
|
+
`// <internal code to chose files ${params.paths.join(', ')}`,
|
|
37
35
|
];
|
|
38
36
|
const action = async () => {
|
|
39
|
-
await modalState.fileChooser.setFiles(
|
|
37
|
+
await modalState.fileChooser.setFiles(params.paths);
|
|
40
38
|
context.clearModalState(modalState);
|
|
41
39
|
};
|
|
42
40
|
return {
|
package/lib/tools/install.js
CHANGED
|
@@ -21,13 +21,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
21
21
|
const child_process_1 = require("child_process");
|
|
22
22
|
const path_1 = __importDefault(require("path"));
|
|
23
23
|
const zod_1 = require("zod");
|
|
24
|
-
const
|
|
25
|
-
const install = {
|
|
24
|
+
const tool_1 = require("./tool");
|
|
25
|
+
const install = (0, tool_1.defineTool)({
|
|
26
26
|
capability: 'install',
|
|
27
27
|
schema: {
|
|
28
28
|
name: 'browser_install',
|
|
29
29
|
description: 'Install the browser specified in the config. Call this if you get an error about the browser not being installed.',
|
|
30
|
-
inputSchema:
|
|
30
|
+
inputSchema: zod_1.z.object({}),
|
|
31
31
|
},
|
|
32
32
|
handle: async (context) => {
|
|
33
33
|
const channel = context.options.launchOptions?.channel ?? context.options.browserName ?? 'chrome';
|
|
@@ -52,7 +52,7 @@ const install = {
|
|
|
52
52
|
waitForNetwork: false,
|
|
53
53
|
};
|
|
54
54
|
},
|
|
55
|
-
};
|
|
55
|
+
});
|
|
56
56
|
exports.default = [
|
|
57
57
|
install,
|
|
58
58
|
];
|
package/lib/tools/keyboard.js
CHANGED
|
@@ -14,30 +14,25 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
-
};
|
|
20
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
18
|
const zod_1 = require("zod");
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
key: zod_1.z.string().describe('Name of the key to press or a character to generate, such as `ArrowLeft` or `a`'),
|
|
25
|
-
});
|
|
26
|
-
const pressKey = captureSnapshot => ({
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const pressKey = captureSnapshot => (0, tool_1.defineTool)({
|
|
27
21
|
capability: 'core',
|
|
28
22
|
schema: {
|
|
29
23
|
name: 'browser_press_key',
|
|
30
24
|
description: 'Press a key on the keyboard',
|
|
31
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({
|
|
26
|
+
key: zod_1.z.string().describe('Name of the key to press or a character to generate, such as `ArrowLeft` or `a`'),
|
|
27
|
+
}),
|
|
32
28
|
},
|
|
33
29
|
handle: async (context, params) => {
|
|
34
|
-
const validatedParams = pressKeySchema.parse(params);
|
|
35
30
|
const tab = context.currentTabOrDie();
|
|
36
31
|
const code = [
|
|
37
|
-
`// Press ${
|
|
38
|
-
`await page.keyboard.press('${
|
|
32
|
+
`// Press ${params.key}`,
|
|
33
|
+
`await page.keyboard.press('${params.key}');`,
|
|
39
34
|
];
|
|
40
|
-
const action = () => tab.page.keyboard.press(
|
|
35
|
+
const action = () => tab.page.keyboard.press(params.key);
|
|
41
36
|
return {
|
|
42
37
|
code,
|
|
43
38
|
action,
|
package/lib/tools/navigate.js
CHANGED
|
@@ -16,24 +16,22 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const zod_1 = require("zod");
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
url: zod_1.z.string().describe('The URL to navigate to'),
|
|
22
|
-
});
|
|
23
|
-
const navigate = captureSnapshot => ({
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const navigate = captureSnapshot => (0, tool_1.defineTool)({
|
|
24
21
|
capability: 'core',
|
|
25
22
|
schema: {
|
|
26
23
|
name: 'browser_navigate',
|
|
27
24
|
description: 'Navigate to a URL',
|
|
28
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({
|
|
26
|
+
url: zod_1.z.string().describe('The URL to navigate to'),
|
|
27
|
+
}),
|
|
29
28
|
},
|
|
30
29
|
handle: async (context, params) => {
|
|
31
|
-
const validatedParams = navigateSchema.parse(params);
|
|
32
30
|
const tab = await context.ensureTab();
|
|
33
|
-
await tab.navigate(
|
|
31
|
+
await tab.navigate(params.url);
|
|
34
32
|
const code = [
|
|
35
|
-
`// Navigate to ${
|
|
36
|
-
`await page.goto('${
|
|
33
|
+
`// Navigate to ${params.url}`,
|
|
34
|
+
`await page.goto('${params.url}');`,
|
|
37
35
|
];
|
|
38
36
|
return {
|
|
39
37
|
code,
|
|
@@ -42,13 +40,12 @@ const navigate = captureSnapshot => ({
|
|
|
42
40
|
};
|
|
43
41
|
},
|
|
44
42
|
});
|
|
45
|
-
const
|
|
46
|
-
const goBack = captureSnapshot => ({
|
|
43
|
+
const goBack = captureSnapshot => (0, tool_1.defineTool)({
|
|
47
44
|
capability: 'history',
|
|
48
45
|
schema: {
|
|
49
46
|
name: 'browser_navigate_back',
|
|
50
47
|
description: 'Go back to the previous page',
|
|
51
|
-
inputSchema:
|
|
48
|
+
inputSchema: zod_1.z.object({}),
|
|
52
49
|
},
|
|
53
50
|
handle: async (context) => {
|
|
54
51
|
const tab = await context.ensureTab();
|
|
@@ -64,13 +61,12 @@ const goBack = captureSnapshot => ({
|
|
|
64
61
|
};
|
|
65
62
|
},
|
|
66
63
|
});
|
|
67
|
-
const
|
|
68
|
-
const goForward = captureSnapshot => ({
|
|
64
|
+
const goForward = captureSnapshot => (0, tool_1.defineTool)({
|
|
69
65
|
capability: 'history',
|
|
70
66
|
schema: {
|
|
71
67
|
name: 'browser_navigate_forward',
|
|
72
68
|
description: 'Go forward to the next page',
|
|
73
|
-
inputSchema:
|
|
69
|
+
inputSchema: zod_1.z.object({}),
|
|
74
70
|
},
|
|
75
71
|
handle: async (context) => {
|
|
76
72
|
const tab = context.currentTabOrDie();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Microsoft Corporation.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const zod_1 = require("zod");
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const requests = (0, tool_1.defineTool)({
|
|
21
|
+
capability: 'core',
|
|
22
|
+
schema: {
|
|
23
|
+
name: 'browser_network_requests',
|
|
24
|
+
description: 'Returns all network requests since loading the page',
|
|
25
|
+
inputSchema: zod_1.z.object({}),
|
|
26
|
+
},
|
|
27
|
+
handle: async (context) => {
|
|
28
|
+
const requests = context.currentTabOrDie().requests();
|
|
29
|
+
const log = [...requests.entries()].map(([request, response]) => renderRequest(request, response)).join('\n');
|
|
30
|
+
return {
|
|
31
|
+
code: [`// <internal code to list network requests>`],
|
|
32
|
+
action: async () => {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: log }]
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
captureSnapshot: false,
|
|
38
|
+
waitForNetwork: false,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
function renderRequest(request, response) {
|
|
43
|
+
const result = [];
|
|
44
|
+
result.push(`[${request.method().toUpperCase()}] ${request.url()}`);
|
|
45
|
+
if (response)
|
|
46
|
+
result.push(`=> [${response.status()}] ${response.statusText()}`);
|
|
47
|
+
return result.join(' ');
|
|
48
|
+
}
|
|
49
|
+
exports.default = [
|
|
50
|
+
requests,
|
|
51
|
+
];
|
package/lib/tools/pdf.js
CHANGED
|
@@ -54,16 +54,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
54
54
|
const os_1 = __importDefault(require("os"));
|
|
55
55
|
const path_1 = __importDefault(require("path"));
|
|
56
56
|
const zod_1 = require("zod");
|
|
57
|
-
const
|
|
57
|
+
const tool_1 = require("./tool");
|
|
58
58
|
const utils_1 = require("./utils");
|
|
59
59
|
const javascript = __importStar(require("../javascript"));
|
|
60
|
-
const
|
|
61
|
-
const pdf = {
|
|
60
|
+
const pdf = (0, tool_1.defineTool)({
|
|
62
61
|
capability: 'pdf',
|
|
63
62
|
schema: {
|
|
64
63
|
name: 'browser_pdf_save',
|
|
65
64
|
description: 'Save page as PDF',
|
|
66
|
-
inputSchema:
|
|
65
|
+
inputSchema: zod_1.z.object({}),
|
|
67
66
|
},
|
|
68
67
|
handle: async (context) => {
|
|
69
68
|
const tab = context.currentTabOrDie();
|
|
@@ -79,7 +78,7 @@ const pdf = {
|
|
|
79
78
|
waitForNetwork: false,
|
|
80
79
|
};
|
|
81
80
|
},
|
|
82
|
-
};
|
|
81
|
+
});
|
|
83
82
|
exports.default = [
|
|
84
83
|
pdf,
|
|
85
84
|
];
|
package/lib/tools/screen.js
CHANGED
|
@@ -49,14 +49,17 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
49
49
|
})();
|
|
50
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
51
|
const zod_1 = require("zod");
|
|
52
|
-
const
|
|
52
|
+
const tool_1 = require("./tool");
|
|
53
53
|
const javascript = __importStar(require("../javascript"));
|
|
54
|
-
const
|
|
54
|
+
const elementSchema = zod_1.z.object({
|
|
55
|
+
element: zod_1.z.string().describe('Human-readable element description used to obtain permission to interact with the element'),
|
|
56
|
+
});
|
|
57
|
+
const screenshot = (0, tool_1.defineTool)({
|
|
55
58
|
capability: 'core',
|
|
56
59
|
schema: {
|
|
57
60
|
name: 'browser_screen_capture',
|
|
58
61
|
description: 'Take a screenshot of the current page',
|
|
59
|
-
inputSchema:
|
|
62
|
+
inputSchema: zod_1.z.object({}),
|
|
60
63
|
},
|
|
61
64
|
handle: async (context) => {
|
|
62
65
|
const tab = await context.ensureTab();
|
|
@@ -77,29 +80,24 @@ const screenshot = {
|
|
|
77
80
|
waitForNetwork: false
|
|
78
81
|
};
|
|
79
82
|
},
|
|
80
|
-
};
|
|
81
|
-
const elementSchema = zod_1.z.object({
|
|
82
|
-
element: zod_1.z.string().describe('Human-readable element description used to obtain permission to interact with the element'),
|
|
83
|
-
});
|
|
84
|
-
const moveMouseSchema = elementSchema.extend({
|
|
85
|
-
x: zod_1.z.number().describe('X coordinate'),
|
|
86
|
-
y: zod_1.z.number().describe('Y coordinate'),
|
|
87
83
|
});
|
|
88
|
-
const moveMouse = {
|
|
84
|
+
const moveMouse = (0, tool_1.defineTool)({
|
|
89
85
|
capability: 'core',
|
|
90
86
|
schema: {
|
|
91
87
|
name: 'browser_screen_move_mouse',
|
|
92
88
|
description: 'Move mouse to a given position',
|
|
93
|
-
inputSchema:
|
|
89
|
+
inputSchema: elementSchema.extend({
|
|
90
|
+
x: zod_1.z.number().describe('X coordinate'),
|
|
91
|
+
y: zod_1.z.number().describe('Y coordinate'),
|
|
92
|
+
}),
|
|
94
93
|
},
|
|
95
94
|
handle: async (context, params) => {
|
|
96
|
-
const validatedParams = moveMouseSchema.parse(params);
|
|
97
95
|
const tab = context.currentTabOrDie();
|
|
98
96
|
const code = [
|
|
99
|
-
`// Move mouse to (${
|
|
100
|
-
`await page.mouse.move(${
|
|
97
|
+
`// Move mouse to (${params.x}, ${params.y})`,
|
|
98
|
+
`await page.mouse.move(${params.x}, ${params.y});`,
|
|
101
99
|
];
|
|
102
|
-
const action = () => tab.page.mouse.move(
|
|
100
|
+
const action = () => tab.page.mouse.move(params.x, params.y);
|
|
103
101
|
return {
|
|
104
102
|
code,
|
|
105
103
|
action,
|
|
@@ -107,29 +105,27 @@ const moveMouse = {
|
|
|
107
105
|
waitForNetwork: false
|
|
108
106
|
};
|
|
109
107
|
},
|
|
110
|
-
};
|
|
111
|
-
const clickSchema = elementSchema.extend({
|
|
112
|
-
x: zod_1.z.number().describe('X coordinate'),
|
|
113
|
-
y: zod_1.z.number().describe('Y coordinate'),
|
|
114
108
|
});
|
|
115
|
-
const click = {
|
|
109
|
+
const click = (0, tool_1.defineTool)({
|
|
116
110
|
capability: 'core',
|
|
117
111
|
schema: {
|
|
118
112
|
name: 'browser_screen_click',
|
|
119
113
|
description: 'Click left mouse button',
|
|
120
|
-
inputSchema:
|
|
114
|
+
inputSchema: elementSchema.extend({
|
|
115
|
+
x: zod_1.z.number().describe('X coordinate'),
|
|
116
|
+
y: zod_1.z.number().describe('Y coordinate'),
|
|
117
|
+
}),
|
|
121
118
|
},
|
|
122
119
|
handle: async (context, params) => {
|
|
123
|
-
const validatedParams = clickSchema.parse(params);
|
|
124
120
|
const tab = context.currentTabOrDie();
|
|
125
121
|
const code = [
|
|
126
|
-
`// Click mouse at coordinates (${
|
|
127
|
-
`await page.mouse.move(${
|
|
122
|
+
`// Click mouse at coordinates (${params.x}, ${params.y})`,
|
|
123
|
+
`await page.mouse.move(${params.x}, ${params.y});`,
|
|
128
124
|
`await page.mouse.down();`,
|
|
129
125
|
`await page.mouse.up();`,
|
|
130
126
|
];
|
|
131
127
|
const action = async () => {
|
|
132
|
-
await tab.page.mouse.move(
|
|
128
|
+
await tab.page.mouse.move(params.x, params.y);
|
|
133
129
|
await tab.page.mouse.down();
|
|
134
130
|
await tab.page.mouse.up();
|
|
135
131
|
};
|
|
@@ -140,34 +136,32 @@ const click = {
|
|
|
140
136
|
waitForNetwork: true,
|
|
141
137
|
};
|
|
142
138
|
},
|
|
143
|
-
};
|
|
144
|
-
const dragSchema = elementSchema.extend({
|
|
145
|
-
startX: zod_1.z.number().describe('Start X coordinate'),
|
|
146
|
-
startY: zod_1.z.number().describe('Start Y coordinate'),
|
|
147
|
-
endX: zod_1.z.number().describe('End X coordinate'),
|
|
148
|
-
endY: zod_1.z.number().describe('End Y coordinate'),
|
|
149
139
|
});
|
|
150
|
-
const drag = {
|
|
140
|
+
const drag = (0, tool_1.defineTool)({
|
|
151
141
|
capability: 'core',
|
|
152
142
|
schema: {
|
|
153
143
|
name: 'browser_screen_drag',
|
|
154
144
|
description: 'Drag left mouse button',
|
|
155
|
-
inputSchema:
|
|
145
|
+
inputSchema: elementSchema.extend({
|
|
146
|
+
startX: zod_1.z.number().describe('Start X coordinate'),
|
|
147
|
+
startY: zod_1.z.number().describe('Start Y coordinate'),
|
|
148
|
+
endX: zod_1.z.number().describe('End X coordinate'),
|
|
149
|
+
endY: zod_1.z.number().describe('End Y coordinate'),
|
|
150
|
+
}),
|
|
156
151
|
},
|
|
157
152
|
handle: async (context, params) => {
|
|
158
|
-
const validatedParams = dragSchema.parse(params);
|
|
159
153
|
const tab = context.currentTabOrDie();
|
|
160
154
|
const code = [
|
|
161
|
-
`// Drag mouse from (${
|
|
162
|
-
`await page.mouse.move(${
|
|
155
|
+
`// Drag mouse from (${params.startX}, ${params.startY}) to (${params.endX}, ${params.endY})`,
|
|
156
|
+
`await page.mouse.move(${params.startX}, ${params.startY});`,
|
|
163
157
|
`await page.mouse.down();`,
|
|
164
|
-
`await page.mouse.move(${
|
|
158
|
+
`await page.mouse.move(${params.endX}, ${params.endY});`,
|
|
165
159
|
`await page.mouse.up();`,
|
|
166
160
|
];
|
|
167
161
|
const action = async () => {
|
|
168
|
-
await tab.page.mouse.move(
|
|
162
|
+
await tab.page.mouse.move(params.startX, params.startY);
|
|
169
163
|
await tab.page.mouse.down();
|
|
170
|
-
await tab.page.mouse.move(
|
|
164
|
+
await tab.page.mouse.move(params.endX, params.endY);
|
|
171
165
|
await tab.page.mouse.up();
|
|
172
166
|
};
|
|
173
167
|
return {
|
|
@@ -177,31 +171,29 @@ const drag = {
|
|
|
177
171
|
waitForNetwork: true,
|
|
178
172
|
};
|
|
179
173
|
},
|
|
180
|
-
};
|
|
181
|
-
const typeSchema = zod_1.z.object({
|
|
182
|
-
text: zod_1.z.string().describe('Text to type into the element'),
|
|
183
|
-
submit: zod_1.z.boolean().optional().describe('Whether to submit entered text (press Enter after)'),
|
|
184
174
|
});
|
|
185
|
-
const type = {
|
|
175
|
+
const type = (0, tool_1.defineTool)({
|
|
186
176
|
capability: 'core',
|
|
187
177
|
schema: {
|
|
188
178
|
name: 'browser_screen_type',
|
|
189
179
|
description: 'Type text',
|
|
190
|
-
inputSchema:
|
|
180
|
+
inputSchema: zod_1.z.object({
|
|
181
|
+
text: zod_1.z.string().describe('Text to type into the element'),
|
|
182
|
+
submit: zod_1.z.boolean().optional().describe('Whether to submit entered text (press Enter after)'),
|
|
183
|
+
}),
|
|
191
184
|
},
|
|
192
185
|
handle: async (context, params) => {
|
|
193
|
-
const validatedParams = typeSchema.parse(params);
|
|
194
186
|
const tab = context.currentTabOrDie();
|
|
195
187
|
const code = [
|
|
196
|
-
`// Type ${
|
|
197
|
-
`await page.keyboard.type('${
|
|
188
|
+
`// Type ${params.text}`,
|
|
189
|
+
`await page.keyboard.type('${params.text}');`,
|
|
198
190
|
];
|
|
199
191
|
const action = async () => {
|
|
200
|
-
await tab.page.keyboard.type(
|
|
201
|
-
if (
|
|
192
|
+
await tab.page.keyboard.type(params.text);
|
|
193
|
+
if (params.submit)
|
|
202
194
|
await tab.page.keyboard.press('Enter');
|
|
203
195
|
};
|
|
204
|
-
if (
|
|
196
|
+
if (params.submit) {
|
|
205
197
|
code.push(`// Submit text`);
|
|
206
198
|
code.push(`await page.keyboard.press('Enter');`);
|
|
207
199
|
}
|
|
@@ -212,7 +204,7 @@ const type = {
|
|
|
212
204
|
waitForNetwork: true,
|
|
213
205
|
};
|
|
214
206
|
},
|
|
215
|
-
};
|
|
207
|
+
});
|
|
216
208
|
exports.default = [
|
|
217
209
|
screenshot,
|
|
218
210
|
moveMouse,
|
package/lib/tools/snapshot.js
CHANGED
|
@@ -54,16 +54,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
54
54
|
const path_1 = __importDefault(require("path"));
|
|
55
55
|
const os_1 = __importDefault(require("os"));
|
|
56
56
|
const zod_1 = require("zod");
|
|
57
|
-
const zod_to_json_schema_1 = __importDefault(require("zod-to-json-schema"));
|
|
58
57
|
const utils_1 = require("./utils");
|
|
59
58
|
const context_1 = require("../context");
|
|
60
59
|
const javascript = __importStar(require("../javascript"));
|
|
61
|
-
const
|
|
60
|
+
const tool_1 = require("./tool");
|
|
61
|
+
const snapshot = (0, tool_1.defineTool)({
|
|
62
62
|
capability: 'core',
|
|
63
63
|
schema: {
|
|
64
64
|
name: 'browser_snapshot',
|
|
65
65
|
description: 'Capture accessibility snapshot of the current page, this is better than screenshot',
|
|
66
|
-
inputSchema:
|
|
66
|
+
inputSchema: zod_1.z.object({}),
|
|
67
67
|
},
|
|
68
68
|
handle: async (context) => {
|
|
69
69
|
await context.ensureTab();
|
|
@@ -73,24 +73,23 @@ const snapshot = {
|
|
|
73
73
|
waitForNetwork: false,
|
|
74
74
|
};
|
|
75
75
|
},
|
|
76
|
-
};
|
|
76
|
+
});
|
|
77
77
|
const elementSchema = zod_1.z.object({
|
|
78
78
|
element: zod_1.z.string().describe('Human-readable element description used to obtain permission to interact with the element'),
|
|
79
79
|
ref: zod_1.z.string().describe('Exact target element reference from the page snapshot'),
|
|
80
80
|
});
|
|
81
|
-
const click = {
|
|
81
|
+
const click = (0, tool_1.defineTool)({
|
|
82
82
|
capability: 'core',
|
|
83
83
|
schema: {
|
|
84
84
|
name: 'browser_click',
|
|
85
85
|
description: 'Perform click on a web page',
|
|
86
|
-
inputSchema:
|
|
86
|
+
inputSchema: elementSchema,
|
|
87
87
|
},
|
|
88
88
|
handle: async (context, params) => {
|
|
89
|
-
const validatedParams = elementSchema.parse(params);
|
|
90
89
|
const tab = context.currentTabOrDie();
|
|
91
|
-
const locator = tab.snapshotOrDie().refLocator(
|
|
90
|
+
const locator = tab.snapshotOrDie().refLocator(params.ref);
|
|
92
91
|
const code = [
|
|
93
|
-
`// Click ${
|
|
92
|
+
`// Click ${params.element}`,
|
|
94
93
|
`await page.${await (0, context_1.generateLocator)(locator)}.click();`
|
|
95
94
|
];
|
|
96
95
|
return {
|
|
@@ -100,27 +99,25 @@ const click = {
|
|
|
100
99
|
waitForNetwork: true,
|
|
101
100
|
};
|
|
102
101
|
},
|
|
103
|
-
};
|
|
104
|
-
const dragSchema = zod_1.z.object({
|
|
105
|
-
startElement: zod_1.z.string().describe('Human-readable source element description used to obtain the permission to interact with the element'),
|
|
106
|
-
startRef: zod_1.z.string().describe('Exact source element reference from the page snapshot'),
|
|
107
|
-
endElement: zod_1.z.string().describe('Human-readable target element description used to obtain the permission to interact with the element'),
|
|
108
|
-
endRef: zod_1.z.string().describe('Exact target element reference from the page snapshot'),
|
|
109
102
|
});
|
|
110
|
-
const drag = {
|
|
103
|
+
const drag = (0, tool_1.defineTool)({
|
|
111
104
|
capability: 'core',
|
|
112
105
|
schema: {
|
|
113
106
|
name: 'browser_drag',
|
|
114
107
|
description: 'Perform drag and drop between two elements',
|
|
115
|
-
inputSchema:
|
|
108
|
+
inputSchema: zod_1.z.object({
|
|
109
|
+
startElement: zod_1.z.string().describe('Human-readable source element description used to obtain the permission to interact with the element'),
|
|
110
|
+
startRef: zod_1.z.string().describe('Exact source element reference from the page snapshot'),
|
|
111
|
+
endElement: zod_1.z.string().describe('Human-readable target element description used to obtain the permission to interact with the element'),
|
|
112
|
+
endRef: zod_1.z.string().describe('Exact target element reference from the page snapshot'),
|
|
113
|
+
}),
|
|
116
114
|
},
|
|
117
115
|
handle: async (context, params) => {
|
|
118
|
-
const validatedParams = dragSchema.parse(params);
|
|
119
116
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
120
|
-
const startLocator = snapshot.refLocator(
|
|
121
|
-
const endLocator = snapshot.refLocator(
|
|
117
|
+
const startLocator = snapshot.refLocator(params.startRef);
|
|
118
|
+
const endLocator = snapshot.refLocator(params.endRef);
|
|
122
119
|
const code = [
|
|
123
|
-
`// Drag ${
|
|
120
|
+
`// Drag ${params.startElement} to ${params.endElement}`,
|
|
124
121
|
`await page.${await (0, context_1.generateLocator)(startLocator)}.dragTo(page.${await (0, context_1.generateLocator)(endLocator)});`
|
|
125
122
|
];
|
|
126
123
|
return {
|
|
@@ -130,20 +127,19 @@ const drag = {
|
|
|
130
127
|
waitForNetwork: true,
|
|
131
128
|
};
|
|
132
129
|
},
|
|
133
|
-
};
|
|
134
|
-
const hover = {
|
|
130
|
+
});
|
|
131
|
+
const hover = (0, tool_1.defineTool)({
|
|
135
132
|
capability: 'core',
|
|
136
133
|
schema: {
|
|
137
134
|
name: 'browser_hover',
|
|
138
135
|
description: 'Hover over element on page',
|
|
139
|
-
inputSchema:
|
|
136
|
+
inputSchema: elementSchema,
|
|
140
137
|
},
|
|
141
138
|
handle: async (context, params) => {
|
|
142
|
-
const validatedParams = elementSchema.parse(params);
|
|
143
139
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
144
|
-
const locator = snapshot.refLocator(
|
|
140
|
+
const locator = snapshot.refLocator(params.ref);
|
|
145
141
|
const code = [
|
|
146
|
-
`// Hover over ${
|
|
142
|
+
`// Hover over ${params.element}`,
|
|
147
143
|
`await page.${await (0, context_1.generateLocator)(locator)}.hover();`
|
|
148
144
|
];
|
|
149
145
|
return {
|
|
@@ -153,36 +149,35 @@ const hover = {
|
|
|
153
149
|
waitForNetwork: true,
|
|
154
150
|
};
|
|
155
151
|
},
|
|
156
|
-
};
|
|
152
|
+
});
|
|
157
153
|
const typeSchema = elementSchema.extend({
|
|
158
154
|
text: zod_1.z.string().describe('Text to type into the element'),
|
|
159
155
|
submit: zod_1.z.boolean().optional().describe('Whether to submit entered text (press Enter after)'),
|
|
160
156
|
slowly: zod_1.z.boolean().optional().describe('Whether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.'),
|
|
161
157
|
});
|
|
162
|
-
const type = {
|
|
158
|
+
const type = (0, tool_1.defineTool)({
|
|
163
159
|
capability: 'core',
|
|
164
160
|
schema: {
|
|
165
161
|
name: 'browser_type',
|
|
166
162
|
description: 'Type text into editable element',
|
|
167
|
-
inputSchema:
|
|
163
|
+
inputSchema: typeSchema,
|
|
168
164
|
},
|
|
169
165
|
handle: async (context, params) => {
|
|
170
|
-
const validatedParams = typeSchema.parse(params);
|
|
171
166
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
172
|
-
const locator = snapshot.refLocator(
|
|
167
|
+
const locator = snapshot.refLocator(params.ref);
|
|
173
168
|
const code = [];
|
|
174
169
|
const steps = [];
|
|
175
|
-
if (
|
|
176
|
-
code.push(`// Press "${
|
|
177
|
-
code.push(`await page.${await (0, context_1.generateLocator)(locator)}.pressSequentially(${javascript.quote(
|
|
178
|
-
steps.push(() => locator.pressSequentially(
|
|
170
|
+
if (params.slowly) {
|
|
171
|
+
code.push(`// Press "${params.text}" sequentially into "${params.element}"`);
|
|
172
|
+
code.push(`await page.${await (0, context_1.generateLocator)(locator)}.pressSequentially(${javascript.quote(params.text)});`);
|
|
173
|
+
steps.push(() => locator.pressSequentially(params.text));
|
|
179
174
|
}
|
|
180
175
|
else {
|
|
181
|
-
code.push(`// Fill "${
|
|
182
|
-
code.push(`await page.${await (0, context_1.generateLocator)(locator)}.fill(${javascript.quote(
|
|
183
|
-
steps.push(() => locator.fill(
|
|
176
|
+
code.push(`// Fill "${params.text}" into "${params.element}"`);
|
|
177
|
+
code.push(`await page.${await (0, context_1.generateLocator)(locator)}.fill(${javascript.quote(params.text)});`);
|
|
178
|
+
steps.push(() => locator.fill(params.text));
|
|
184
179
|
}
|
|
185
|
-
if (
|
|
180
|
+
if (params.submit) {
|
|
186
181
|
code.push(`// Submit text`);
|
|
187
182
|
code.push(`await page.${await (0, context_1.generateLocator)(locator)}.press('Enter');`);
|
|
188
183
|
steps.push(() => locator.press('Enter'));
|
|
@@ -194,33 +189,32 @@ const type = {
|
|
|
194
189
|
waitForNetwork: true,
|
|
195
190
|
};
|
|
196
191
|
},
|
|
197
|
-
};
|
|
192
|
+
});
|
|
198
193
|
const selectOptionSchema = elementSchema.extend({
|
|
199
194
|
values: zod_1.z.array(zod_1.z.string()).describe('Array of values to select in the dropdown. This can be a single value or multiple values.'),
|
|
200
195
|
});
|
|
201
|
-
const selectOption = {
|
|
196
|
+
const selectOption = (0, tool_1.defineTool)({
|
|
202
197
|
capability: 'core',
|
|
203
198
|
schema: {
|
|
204
199
|
name: 'browser_select_option',
|
|
205
200
|
description: 'Select an option in a dropdown',
|
|
206
|
-
inputSchema:
|
|
201
|
+
inputSchema: selectOptionSchema,
|
|
207
202
|
},
|
|
208
203
|
handle: async (context, params) => {
|
|
209
|
-
const validatedParams = selectOptionSchema.parse(params);
|
|
210
204
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
211
|
-
const locator = snapshot.refLocator(
|
|
205
|
+
const locator = snapshot.refLocator(params.ref);
|
|
212
206
|
const code = [
|
|
213
|
-
`// Select options [${
|
|
214
|
-
`await page.${await (0, context_1.generateLocator)(locator)}.selectOption(${javascript.formatObject(
|
|
207
|
+
`// Select options [${params.values.join(', ')}] in ${params.element}`,
|
|
208
|
+
`await page.${await (0, context_1.generateLocator)(locator)}.selectOption(${javascript.formatObject(params.values)});`
|
|
215
209
|
];
|
|
216
210
|
return {
|
|
217
211
|
code,
|
|
218
|
-
action: () => locator.selectOption(
|
|
212
|
+
action: () => locator.selectOption(params.values).then(() => { }),
|
|
219
213
|
captureSnapshot: true,
|
|
220
214
|
waitForNetwork: true,
|
|
221
215
|
};
|
|
222
216
|
},
|
|
223
|
-
};
|
|
217
|
+
});
|
|
224
218
|
const screenshotSchema = zod_1.z.object({
|
|
225
219
|
raw: zod_1.z.boolean().optional().describe('Whether to return without compression (in PNG format). Default is false, which returns a JPEG image.'),
|
|
226
220
|
element: zod_1.z.string().optional().describe('Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.'),
|
|
@@ -231,25 +225,24 @@ const screenshotSchema = zod_1.z.object({
|
|
|
231
225
|
message: 'Both element and ref must be provided or neither.',
|
|
232
226
|
path: ['ref', 'element']
|
|
233
227
|
});
|
|
234
|
-
const screenshot = {
|
|
228
|
+
const screenshot = (0, tool_1.defineTool)({
|
|
235
229
|
capability: 'core',
|
|
236
230
|
schema: {
|
|
237
231
|
name: 'browser_take_screenshot',
|
|
238
232
|
description: `Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.`,
|
|
239
|
-
inputSchema:
|
|
233
|
+
inputSchema: screenshotSchema,
|
|
240
234
|
},
|
|
241
235
|
handle: async (context, params) => {
|
|
242
|
-
const validatedParams = screenshotSchema.parse(params);
|
|
243
236
|
const tab = context.currentTabOrDie();
|
|
244
237
|
const snapshot = tab.snapshotOrDie();
|
|
245
|
-
const fileType =
|
|
238
|
+
const fileType = params.raw ? 'png' : 'jpeg';
|
|
246
239
|
const fileName = path_1.default.join(os_1.default.tmpdir(), (0, utils_1.sanitizeForFilePath)(`page-${new Date().toISOString()}`)) + `.${fileType}`;
|
|
247
240
|
const options = { type: fileType, quality: fileType === 'png' ? undefined : 50, scale: 'css', path: fileName };
|
|
248
|
-
const isElementScreenshot =
|
|
241
|
+
const isElementScreenshot = params.element && params.ref;
|
|
249
242
|
const code = [
|
|
250
|
-
`// Screenshot ${isElementScreenshot ?
|
|
243
|
+
`// Screenshot ${isElementScreenshot ? params.element : 'viewport'} and save it as ${fileName}`,
|
|
251
244
|
];
|
|
252
|
-
const locator =
|
|
245
|
+
const locator = params.ref ? snapshot.refLocator(params.ref) : null;
|
|
253
246
|
if (locator)
|
|
254
247
|
code.push(`await page.${await (0, context_1.generateLocator)(locator)}.screenshot(${javascript.formatObject(options)});`);
|
|
255
248
|
else
|
|
@@ -271,7 +264,7 @@ const screenshot = {
|
|
|
271
264
|
waitForNetwork: false,
|
|
272
265
|
};
|
|
273
266
|
}
|
|
274
|
-
};
|
|
267
|
+
});
|
|
275
268
|
exports.default = [
|
|
276
269
|
snapshot,
|
|
277
270
|
click,
|
package/lib/tools/tabs.js
CHANGED
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
const zod_1 = require("zod");
|
|
19
|
-
const
|
|
20
|
-
const listTabs = {
|
|
19
|
+
const tool_1 = require("./tool");
|
|
20
|
+
const listTabs = (0, tool_1.defineTool)({
|
|
21
21
|
capability: 'tabs',
|
|
22
22
|
schema: {
|
|
23
23
|
name: 'browser_tab_list',
|
|
24
24
|
description: 'List browser tabs',
|
|
25
|
-
inputSchema:
|
|
25
|
+
inputSchema: zod_1.z.object({}),
|
|
26
26
|
},
|
|
27
27
|
handle: async (context) => {
|
|
28
28
|
await context.ensureTab();
|
|
@@ -38,22 +38,20 @@ const listTabs = {
|
|
|
38
38
|
},
|
|
39
39
|
};
|
|
40
40
|
},
|
|
41
|
-
};
|
|
42
|
-
const selectTabSchema = zod_1.z.object({
|
|
43
|
-
index: zod_1.z.number().describe('The index of the tab to select'),
|
|
44
41
|
});
|
|
45
|
-
const selectTab = captureSnapshot => ({
|
|
42
|
+
const selectTab = captureSnapshot => (0, tool_1.defineTool)({
|
|
46
43
|
capability: 'tabs',
|
|
47
44
|
schema: {
|
|
48
45
|
name: 'browser_tab_select',
|
|
49
46
|
description: 'Select a tab by index',
|
|
50
|
-
inputSchema:
|
|
47
|
+
inputSchema: zod_1.z.object({
|
|
48
|
+
index: zod_1.z.number().describe('The index of the tab to select'),
|
|
49
|
+
}),
|
|
51
50
|
},
|
|
52
51
|
handle: async (context, params) => {
|
|
53
|
-
|
|
54
|
-
await context.selectTab(validatedParams.index);
|
|
52
|
+
await context.selectTab(params.index);
|
|
55
53
|
const code = [
|
|
56
|
-
`// <internal code to select tab ${
|
|
54
|
+
`// <internal code to select tab ${params.index}>`,
|
|
57
55
|
];
|
|
58
56
|
return {
|
|
59
57
|
code,
|
|
@@ -62,21 +60,19 @@ const selectTab = captureSnapshot => ({
|
|
|
62
60
|
};
|
|
63
61
|
},
|
|
64
62
|
});
|
|
65
|
-
const
|
|
66
|
-
url: zod_1.z.string().optional().describe('The URL to navigate to in the new tab. If not provided, the new tab will be blank.'),
|
|
67
|
-
});
|
|
68
|
-
const newTab = captureSnapshot => ({
|
|
63
|
+
const newTab = captureSnapshot => (0, tool_1.defineTool)({
|
|
69
64
|
capability: 'tabs',
|
|
70
65
|
schema: {
|
|
71
66
|
name: 'browser_tab_new',
|
|
72
67
|
description: 'Open a new tab',
|
|
73
|
-
inputSchema:
|
|
68
|
+
inputSchema: zod_1.z.object({
|
|
69
|
+
url: zod_1.z.string().optional().describe('The URL to navigate to in the new tab. If not provided, the new tab will be blank.'),
|
|
70
|
+
}),
|
|
74
71
|
},
|
|
75
72
|
handle: async (context, params) => {
|
|
76
|
-
const validatedParams = newTabSchema.parse(params);
|
|
77
73
|
await context.newTab();
|
|
78
|
-
if (
|
|
79
|
-
await context.currentTabOrDie().navigate(
|
|
74
|
+
if (params.url)
|
|
75
|
+
await context.currentTabOrDie().navigate(params.url);
|
|
80
76
|
const code = [
|
|
81
77
|
`// <internal code to open a new tab>`,
|
|
82
78
|
];
|
|
@@ -87,21 +83,19 @@ const newTab = captureSnapshot => ({
|
|
|
87
83
|
};
|
|
88
84
|
},
|
|
89
85
|
});
|
|
90
|
-
const
|
|
91
|
-
index: zod_1.z.number().optional().describe('The index of the tab to close. Closes current tab if not provided.'),
|
|
92
|
-
});
|
|
93
|
-
const closeTab = captureSnapshot => ({
|
|
86
|
+
const closeTab = captureSnapshot => (0, tool_1.defineTool)({
|
|
94
87
|
capability: 'tabs',
|
|
95
88
|
schema: {
|
|
96
89
|
name: 'browser_tab_close',
|
|
97
90
|
description: 'Close a tab',
|
|
98
|
-
inputSchema:
|
|
91
|
+
inputSchema: zod_1.z.object({
|
|
92
|
+
index: zod_1.z.number().optional().describe('The index of the tab to close. Closes current tab if not provided.'),
|
|
93
|
+
}),
|
|
99
94
|
},
|
|
100
95
|
handle: async (context, params) => {
|
|
101
|
-
|
|
102
|
-
await context.closeTab(validatedParams.index);
|
|
96
|
+
await context.closeTab(params.index);
|
|
103
97
|
const code = [
|
|
104
|
-
`// <internal code to close tab ${
|
|
98
|
+
`// <internal code to close tab ${params.index}>`,
|
|
105
99
|
];
|
|
106
100
|
return {
|
|
107
101
|
code,
|
package/lib/tools/tool.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playwright/mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Playwright Tools for MCP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.6.1",
|
|
38
38
|
"commander": "^13.1.0",
|
|
39
|
-
"playwright": "
|
|
39
|
+
"playwright": "1.53.0-alpha-1745357020000",
|
|
40
40
|
"yaml": "^2.7.1",
|
|
41
41
|
"zod-to-json-schema": "^3.24.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@eslint/eslintrc": "^3.2.0",
|
|
45
45
|
"@eslint/js": "^9.19.0",
|
|
46
|
-
"@playwright/test": "
|
|
46
|
+
"@playwright/test": "1.53.0-alpha-1745357020000",
|
|
47
47
|
"@stylistic/eslint-plugin": "^3.0.1",
|
|
48
48
|
"@types/node": "^22.13.10",
|
|
49
49
|
"@typescript-eslint/eslint-plugin": "^8.26.1",
|