@playwright/mcp 0.0.20 → 0.0.22
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 +84 -9
- package/config.d.ts +14 -14
- package/index.d.ts +8 -2
- package/index.js +2 -2
- package/lib/config.js +14 -16
- package/lib/{server.js → connection.js} +31 -28
- package/lib/context.js +36 -2
- package/lib/index.js +2 -51
- package/lib/program.js +15 -9
- package/lib/tab.js +18 -1
- package/lib/tools/common.js +6 -0
- package/lib/tools/console.js +2 -0
- package/lib/tools/dialogs.js +2 -0
- package/lib/tools/files.js +2 -0
- package/lib/tools/install.js +6 -4
- package/lib/tools/keyboard.js +2 -0
- package/lib/tools/navigate.js +6 -0
- package/lib/tools/network.js +2 -0
- package/lib/tools/pdf.js +2 -0
- package/lib/tools/screen.js +10 -0
- package/lib/tools/snapshot.js +15 -1
- package/lib/tools/tabs.js +8 -0
- package/lib/tools/testing.js +2 -0
- package/lib/tools.js +56 -0
- package/lib/transport.js +23 -15
- package/package.json +3 -3
package/lib/index.js
CHANGED
|
@@ -13,55 +13,6 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import console from './tools/console.js';
|
|
19
|
-
import dialogs from './tools/dialogs.js';
|
|
20
|
-
import files from './tools/files.js';
|
|
21
|
-
import install from './tools/install.js';
|
|
22
|
-
import keyboard from './tools/keyboard.js';
|
|
23
|
-
import navigate from './tools/navigate.js';
|
|
24
|
-
import network from './tools/network.js';
|
|
25
|
-
import pdf from './tools/pdf.js';
|
|
26
|
-
import snapshot from './tools/snapshot.js';
|
|
27
|
-
import tabs from './tools/tabs.js';
|
|
28
|
-
import screen from './tools/screen.js';
|
|
29
|
-
import testing from './tools/testing.js';
|
|
30
|
-
const snapshotTools = [
|
|
31
|
-
...common(true),
|
|
32
|
-
...console,
|
|
33
|
-
...dialogs(true),
|
|
34
|
-
...files(true),
|
|
35
|
-
...install,
|
|
36
|
-
...keyboard(true),
|
|
37
|
-
...navigate(true),
|
|
38
|
-
...network,
|
|
39
|
-
...pdf,
|
|
40
|
-
...snapshot,
|
|
41
|
-
...tabs(true),
|
|
42
|
-
...testing,
|
|
43
|
-
];
|
|
44
|
-
const screenshotTools = [
|
|
45
|
-
...common(false),
|
|
46
|
-
...console,
|
|
47
|
-
...dialogs(false),
|
|
48
|
-
...files(false),
|
|
49
|
-
...install,
|
|
50
|
-
...keyboard(false),
|
|
51
|
-
...navigate(false),
|
|
52
|
-
...network,
|
|
53
|
-
...pdf,
|
|
54
|
-
...screen,
|
|
55
|
-
...tabs(false),
|
|
56
|
-
...testing,
|
|
57
|
-
];
|
|
58
|
-
import packageJSON from '../package.json' with { type: 'json' };
|
|
59
|
-
export async function createServer(config = {}) {
|
|
60
|
-
const allTools = config.vision ? screenshotTools : snapshotTools;
|
|
61
|
-
const tools = allTools.filter(tool => !config.capabilities || tool.capability === 'core' || config.capabilities.includes(tool.capability));
|
|
62
|
-
return createServerWithTools({
|
|
63
|
-
name: 'Playwright',
|
|
64
|
-
version: packageJSON.version,
|
|
65
|
-
tools,
|
|
66
|
-
}, config);
|
|
16
|
+
export async function createConnection(config = {}) {
|
|
17
|
+
return createConnection(config);
|
|
67
18
|
}
|
package/lib/program.js
CHANGED
|
@@ -14,11 +14,9 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { program } from 'commander';
|
|
17
|
-
import { createServer } from './index.js';
|
|
18
|
-
import { ServerList } from './server.js';
|
|
19
17
|
import { startHttpTransport, startStdioTransport } from './transport.js';
|
|
20
18
|
import { resolveConfig } from './config.js';
|
|
21
|
-
import packageJSON from '
|
|
19
|
+
import { packageJSON } from './context.js';
|
|
22
20
|
program
|
|
23
21
|
.version('Version ' + packageJSON.version)
|
|
24
22
|
.name(packageJSON.name)
|
|
@@ -31,25 +29,33 @@ program
|
|
|
31
29
|
.option('--user-data-dir <path>', 'Path to the user data directory')
|
|
32
30
|
.option('--port <port>', 'Port to listen on for SSE transport.')
|
|
33
31
|
.option('--host <host>', 'Host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.')
|
|
32
|
+
.option('--allowed-origins <origins>', 'Semicolon-separated list of origins to allow the browser to request. Default is to allow all.', semicolonSeparatedList)
|
|
33
|
+
.option('--blocked-origins <origins>', 'Semicolon-separated list of origins to block the browser from requesting. Blocklist is evaluated before allowlist. If used without the allowlist, requests not matching the blocklist are still allowed.', semicolonSeparatedList)
|
|
34
34
|
.option('--vision', 'Run server that uses screenshots (Aria snapshots are used by default)')
|
|
35
|
+
.option('--no-image-responses', 'Do not send image responses to the client.')
|
|
36
|
+
.option('--output-dir <path>', 'Path to the directory for output files.')
|
|
35
37
|
.option('--config <path>', 'Path to the configuration file.')
|
|
36
38
|
.action(async (options) => {
|
|
37
39
|
const config = await resolveConfig(options);
|
|
38
|
-
const
|
|
39
|
-
setupExitWatchdog(
|
|
40
|
+
const connectionList = [];
|
|
41
|
+
setupExitWatchdog(connectionList);
|
|
40
42
|
if (options.port)
|
|
41
|
-
startHttpTransport(+options.port, options.host,
|
|
43
|
+
startHttpTransport(config, +options.port, options.host, connectionList);
|
|
42
44
|
else
|
|
43
|
-
await startStdioTransport(
|
|
45
|
+
await startStdioTransport(config, connectionList);
|
|
44
46
|
});
|
|
45
|
-
function setupExitWatchdog(
|
|
47
|
+
function setupExitWatchdog(connectionList) {
|
|
46
48
|
const handleExit = async () => {
|
|
47
49
|
setTimeout(() => process.exit(0), 15000);
|
|
48
|
-
|
|
50
|
+
for (const connection of connectionList)
|
|
51
|
+
await connection.close();
|
|
49
52
|
process.exit(0);
|
|
50
53
|
};
|
|
51
54
|
process.stdin.on('close', handleExit);
|
|
52
55
|
process.on('SIGINT', handleExit);
|
|
53
56
|
process.on('SIGTERM', handleExit);
|
|
54
57
|
}
|
|
58
|
+
function semicolonSeparatedList(value) {
|
|
59
|
+
return value.split(';').map(v => v.trim());
|
|
60
|
+
}
|
|
55
61
|
program.parse(process.argv);
|
package/lib/tab.js
CHANGED
|
@@ -56,7 +56,24 @@ export class Tab {
|
|
|
56
56
|
this._onPageClose(this);
|
|
57
57
|
}
|
|
58
58
|
async navigate(url) {
|
|
59
|
-
|
|
59
|
+
const downloadEvent = this.page.waitForEvent('download').catch(() => { });
|
|
60
|
+
try {
|
|
61
|
+
await this.page.goto(url, { waitUntil: 'domcontentloaded' });
|
|
62
|
+
}
|
|
63
|
+
catch (_e) {
|
|
64
|
+
const e = _e;
|
|
65
|
+
const mightBeDownload = e.message.includes('net::ERR_ABORTED') // chromium
|
|
66
|
+
|| e.message.includes('Download is starting'); // firefox + webkit
|
|
67
|
+
if (!mightBeDownload)
|
|
68
|
+
throw e;
|
|
69
|
+
// on chromium, the download event is fired *after* page.goto rejects, so we wait a lil bit
|
|
70
|
+
const download = await Promise.race([
|
|
71
|
+
downloadEvent,
|
|
72
|
+
new Promise(resolve => setTimeout(resolve, 500)),
|
|
73
|
+
]);
|
|
74
|
+
if (!download)
|
|
75
|
+
throw e;
|
|
76
|
+
}
|
|
60
77
|
// Cap load event to 5 seconds, the page is operational at this point.
|
|
61
78
|
await this.page.waitForLoadState('load', { timeout: 5000 }).catch(() => { });
|
|
62
79
|
}
|
package/lib/tools/common.js
CHANGED
|
@@ -19,10 +19,12 @@ const wait = captureSnapshot => defineTool({
|
|
|
19
19
|
capability: 'wait',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_wait',
|
|
22
|
+
title: 'Wait',
|
|
22
23
|
description: 'Wait for a specified time in seconds',
|
|
23
24
|
inputSchema: z.object({
|
|
24
25
|
time: z.number().describe('The time to wait in seconds'),
|
|
25
26
|
}),
|
|
27
|
+
type: 'readOnly',
|
|
26
28
|
},
|
|
27
29
|
handle: async (context, params) => {
|
|
28
30
|
await new Promise(f => setTimeout(f, Math.min(10000, params.time * 1000)));
|
|
@@ -37,8 +39,10 @@ const close = defineTool({
|
|
|
37
39
|
capability: 'core',
|
|
38
40
|
schema: {
|
|
39
41
|
name: 'browser_close',
|
|
42
|
+
title: 'Close browser',
|
|
40
43
|
description: 'Close the page',
|
|
41
44
|
inputSchema: z.object({}),
|
|
45
|
+
type: 'readOnly',
|
|
42
46
|
},
|
|
43
47
|
handle: async (context) => {
|
|
44
48
|
await context.close();
|
|
@@ -53,11 +57,13 @@ const resize = captureSnapshot => defineTool({
|
|
|
53
57
|
capability: 'core',
|
|
54
58
|
schema: {
|
|
55
59
|
name: 'browser_resize',
|
|
60
|
+
title: 'Resize browser window',
|
|
56
61
|
description: 'Resize the browser window',
|
|
57
62
|
inputSchema: z.object({
|
|
58
63
|
width: z.number().describe('Width of the browser window'),
|
|
59
64
|
height: z.number().describe('Height of the browser window'),
|
|
60
65
|
}),
|
|
66
|
+
type: 'readOnly',
|
|
61
67
|
},
|
|
62
68
|
handle: async (context, params) => {
|
|
63
69
|
const tab = context.currentTabOrDie();
|
package/lib/tools/console.js
CHANGED
|
@@ -19,8 +19,10 @@ const console = defineTool({
|
|
|
19
19
|
capability: 'core',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_console_messages',
|
|
22
|
+
title: 'Get console messages',
|
|
22
23
|
description: 'Returns all console messages',
|
|
23
24
|
inputSchema: z.object({}),
|
|
25
|
+
type: 'readOnly',
|
|
24
26
|
},
|
|
25
27
|
handle: async (context) => {
|
|
26
28
|
const messages = context.currentTabOrDie().console();
|
package/lib/tools/dialogs.js
CHANGED
|
@@ -19,11 +19,13 @@ const handleDialog = captureSnapshot => defineTool({
|
|
|
19
19
|
capability: 'core',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_handle_dialog',
|
|
22
|
+
title: 'Handle a dialog',
|
|
22
23
|
description: 'Handle a dialog',
|
|
23
24
|
inputSchema: z.object({
|
|
24
25
|
accept: z.boolean().describe('Whether to accept the dialog.'),
|
|
25
26
|
promptText: z.string().optional().describe('The text of the prompt in case of a prompt dialog.'),
|
|
26
27
|
}),
|
|
28
|
+
type: 'destructive',
|
|
27
29
|
},
|
|
28
30
|
handle: async (context, params) => {
|
|
29
31
|
const dialogState = context.modalStates().find(state => state.type === 'dialog');
|
package/lib/tools/files.js
CHANGED
|
@@ -19,10 +19,12 @@ const uploadFile = captureSnapshot => defineTool({
|
|
|
19
19
|
capability: 'files',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_file_upload',
|
|
22
|
+
title: 'Upload files',
|
|
22
23
|
description: 'Upload one or multiple files',
|
|
23
24
|
inputSchema: z.object({
|
|
24
25
|
paths: z.array(z.string()).describe('The absolute paths to the files to upload. Can be a single file or multiple files.'),
|
|
25
26
|
}),
|
|
27
|
+
type: 'destructive',
|
|
26
28
|
},
|
|
27
29
|
handle: async (context, params) => {
|
|
28
30
|
const modalState = context.modalStates().find(state => state.type === 'fileChooser');
|
package/lib/tools/install.js
CHANGED
|
@@ -17,19 +17,21 @@ import { fork } from 'child_process';
|
|
|
17
17
|
import path from 'path';
|
|
18
18
|
import { z } from 'zod';
|
|
19
19
|
import { defineTool } from './tool.js';
|
|
20
|
-
import {
|
|
21
|
-
const require = createRequire(import.meta.url);
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
22
21
|
const install = defineTool({
|
|
23
22
|
capability: 'install',
|
|
24
23
|
schema: {
|
|
25
24
|
name: 'browser_install',
|
|
25
|
+
title: 'Install the browser specified in the config',
|
|
26
26
|
description: 'Install the browser specified in the config. Call this if you get an error about the browser not being installed.',
|
|
27
27
|
inputSchema: z.object({}),
|
|
28
|
+
type: 'destructive',
|
|
28
29
|
},
|
|
29
30
|
handle: async (context) => {
|
|
30
31
|
const channel = context.config.browser?.launchOptions?.channel ?? context.config.browser?.launchOptions.browserName ?? 'chrome';
|
|
31
|
-
const
|
|
32
|
-
const
|
|
32
|
+
const cliUrl = import.meta.resolve('playwright/package.json');
|
|
33
|
+
const cliPath = path.join(fileURLToPath(cliUrl), '..', 'cli.js');
|
|
34
|
+
const child = fork(cliPath, ['install', channel], {
|
|
33
35
|
stdio: 'pipe',
|
|
34
36
|
});
|
|
35
37
|
const output = [];
|
package/lib/tools/keyboard.js
CHANGED
|
@@ -19,10 +19,12 @@ const pressKey = captureSnapshot => defineTool({
|
|
|
19
19
|
capability: 'core',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_press_key',
|
|
22
|
+
title: 'Press a key',
|
|
22
23
|
description: 'Press a key on the keyboard',
|
|
23
24
|
inputSchema: z.object({
|
|
24
25
|
key: z.string().describe('Name of the key to press or a character to generate, such as `ArrowLeft` or `a`'),
|
|
25
26
|
}),
|
|
27
|
+
type: 'destructive',
|
|
26
28
|
},
|
|
27
29
|
handle: async (context, params) => {
|
|
28
30
|
const tab = context.currentTabOrDie();
|
package/lib/tools/navigate.js
CHANGED
|
@@ -19,10 +19,12 @@ const navigate = captureSnapshot => defineTool({
|
|
|
19
19
|
capability: 'core',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_navigate',
|
|
22
|
+
title: 'Navigate to a URL',
|
|
22
23
|
description: 'Navigate to a URL',
|
|
23
24
|
inputSchema: z.object({
|
|
24
25
|
url: z.string().describe('The URL to navigate to'),
|
|
25
26
|
}),
|
|
27
|
+
type: 'destructive',
|
|
26
28
|
},
|
|
27
29
|
handle: async (context, params) => {
|
|
28
30
|
const tab = await context.ensureTab();
|
|
@@ -42,8 +44,10 @@ const goBack = captureSnapshot => defineTool({
|
|
|
42
44
|
capability: 'history',
|
|
43
45
|
schema: {
|
|
44
46
|
name: 'browser_navigate_back',
|
|
47
|
+
title: 'Go back',
|
|
45
48
|
description: 'Go back to the previous page',
|
|
46
49
|
inputSchema: z.object({}),
|
|
50
|
+
type: 'readOnly',
|
|
47
51
|
},
|
|
48
52
|
handle: async (context) => {
|
|
49
53
|
const tab = await context.ensureTab();
|
|
@@ -63,8 +67,10 @@ const goForward = captureSnapshot => defineTool({
|
|
|
63
67
|
capability: 'history',
|
|
64
68
|
schema: {
|
|
65
69
|
name: 'browser_navigate_forward',
|
|
70
|
+
title: 'Go forward',
|
|
66
71
|
description: 'Go forward to the next page',
|
|
67
72
|
inputSchema: z.object({}),
|
|
73
|
+
type: 'readOnly',
|
|
68
74
|
},
|
|
69
75
|
handle: async (context) => {
|
|
70
76
|
const tab = context.currentTabOrDie();
|
package/lib/tools/network.js
CHANGED
|
@@ -19,8 +19,10 @@ const requests = defineTool({
|
|
|
19
19
|
capability: 'core',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_network_requests',
|
|
22
|
+
title: 'List network requests',
|
|
22
23
|
description: 'Returns all network requests since loading the page',
|
|
23
24
|
inputSchema: z.object({}),
|
|
25
|
+
type: 'readOnly',
|
|
24
26
|
},
|
|
25
27
|
handle: async (context) => {
|
|
26
28
|
const requests = context.currentTabOrDie().requests();
|
package/lib/tools/pdf.js
CHANGED
|
@@ -21,8 +21,10 @@ const pdf = defineTool({
|
|
|
21
21
|
capability: 'pdf',
|
|
22
22
|
schema: {
|
|
23
23
|
name: 'browser_pdf_save',
|
|
24
|
+
title: 'Save as PDF',
|
|
24
25
|
description: 'Save page as PDF',
|
|
25
26
|
inputSchema: z.object({}),
|
|
27
|
+
type: 'readOnly',
|
|
26
28
|
},
|
|
27
29
|
handle: async (context) => {
|
|
28
30
|
const tab = context.currentTabOrDie();
|
package/lib/tools/screen.js
CHANGED
|
@@ -23,8 +23,10 @@ const screenshot = defineTool({
|
|
|
23
23
|
capability: 'core',
|
|
24
24
|
schema: {
|
|
25
25
|
name: 'browser_screen_capture',
|
|
26
|
+
title: 'Take a screenshot',
|
|
26
27
|
description: 'Take a screenshot of the current page',
|
|
27
28
|
inputSchema: z.object({}),
|
|
29
|
+
type: 'readOnly',
|
|
28
30
|
},
|
|
29
31
|
handle: async (context) => {
|
|
30
32
|
const tab = await context.ensureTab();
|
|
@@ -50,11 +52,13 @@ const moveMouse = defineTool({
|
|
|
50
52
|
capability: 'core',
|
|
51
53
|
schema: {
|
|
52
54
|
name: 'browser_screen_move_mouse',
|
|
55
|
+
title: 'Move mouse',
|
|
53
56
|
description: 'Move mouse to a given position',
|
|
54
57
|
inputSchema: elementSchema.extend({
|
|
55
58
|
x: z.number().describe('X coordinate'),
|
|
56
59
|
y: z.number().describe('Y coordinate'),
|
|
57
60
|
}),
|
|
61
|
+
type: 'readOnly',
|
|
58
62
|
},
|
|
59
63
|
handle: async (context, params) => {
|
|
60
64
|
const tab = context.currentTabOrDie();
|
|
@@ -75,11 +79,13 @@ const click = defineTool({
|
|
|
75
79
|
capability: 'core',
|
|
76
80
|
schema: {
|
|
77
81
|
name: 'browser_screen_click',
|
|
82
|
+
title: 'Click',
|
|
78
83
|
description: 'Click left mouse button',
|
|
79
84
|
inputSchema: elementSchema.extend({
|
|
80
85
|
x: z.number().describe('X coordinate'),
|
|
81
86
|
y: z.number().describe('Y coordinate'),
|
|
82
87
|
}),
|
|
88
|
+
type: 'destructive',
|
|
83
89
|
},
|
|
84
90
|
handle: async (context, params) => {
|
|
85
91
|
const tab = context.currentTabOrDie();
|
|
@@ -106,6 +112,7 @@ const drag = defineTool({
|
|
|
106
112
|
capability: 'core',
|
|
107
113
|
schema: {
|
|
108
114
|
name: 'browser_screen_drag',
|
|
115
|
+
title: 'Drag mouse',
|
|
109
116
|
description: 'Drag left mouse button',
|
|
110
117
|
inputSchema: elementSchema.extend({
|
|
111
118
|
startX: z.number().describe('Start X coordinate'),
|
|
@@ -113,6 +120,7 @@ const drag = defineTool({
|
|
|
113
120
|
endX: z.number().describe('End X coordinate'),
|
|
114
121
|
endY: z.number().describe('End Y coordinate'),
|
|
115
122
|
}),
|
|
123
|
+
type: 'destructive',
|
|
116
124
|
},
|
|
117
125
|
handle: async (context, params) => {
|
|
118
126
|
const tab = context.currentTabOrDie();
|
|
@@ -141,11 +149,13 @@ const type = defineTool({
|
|
|
141
149
|
capability: 'core',
|
|
142
150
|
schema: {
|
|
143
151
|
name: 'browser_screen_type',
|
|
152
|
+
title: 'Type text',
|
|
144
153
|
description: 'Type text',
|
|
145
154
|
inputSchema: z.object({
|
|
146
155
|
text: z.string().describe('Text to type into the element'),
|
|
147
156
|
submit: z.boolean().optional().describe('Whether to submit entered text (press Enter after)'),
|
|
148
157
|
}),
|
|
158
|
+
type: 'destructive',
|
|
149
159
|
},
|
|
150
160
|
handle: async (context, params) => {
|
|
151
161
|
const tab = context.currentTabOrDie();
|
package/lib/tools/snapshot.js
CHANGED
|
@@ -21,8 +21,10 @@ const snapshot = defineTool({
|
|
|
21
21
|
capability: 'core',
|
|
22
22
|
schema: {
|
|
23
23
|
name: 'browser_snapshot',
|
|
24
|
+
title: 'Page snapshot',
|
|
24
25
|
description: 'Capture accessibility snapshot of the current page, this is better than screenshot',
|
|
25
26
|
inputSchema: z.object({}),
|
|
27
|
+
type: 'readOnly',
|
|
26
28
|
},
|
|
27
29
|
handle: async (context) => {
|
|
28
30
|
await context.ensureTab();
|
|
@@ -41,8 +43,10 @@ const click = defineTool({
|
|
|
41
43
|
capability: 'core',
|
|
42
44
|
schema: {
|
|
43
45
|
name: 'browser_click',
|
|
46
|
+
title: 'Click',
|
|
44
47
|
description: 'Perform click on a web page',
|
|
45
48
|
inputSchema: elementSchema,
|
|
49
|
+
type: 'destructive',
|
|
46
50
|
},
|
|
47
51
|
handle: async (context, params) => {
|
|
48
52
|
const tab = context.currentTabOrDie();
|
|
@@ -63,6 +67,7 @@ const drag = defineTool({
|
|
|
63
67
|
capability: 'core',
|
|
64
68
|
schema: {
|
|
65
69
|
name: 'browser_drag',
|
|
70
|
+
title: 'Drag mouse',
|
|
66
71
|
description: 'Perform drag and drop between two elements',
|
|
67
72
|
inputSchema: z.object({
|
|
68
73
|
startElement: z.string().describe('Human-readable source element description used to obtain the permission to interact with the element'),
|
|
@@ -70,6 +75,7 @@ const drag = defineTool({
|
|
|
70
75
|
endElement: z.string().describe('Human-readable target element description used to obtain the permission to interact with the element'),
|
|
71
76
|
endRef: z.string().describe('Exact target element reference from the page snapshot'),
|
|
72
77
|
}),
|
|
78
|
+
type: 'destructive',
|
|
73
79
|
},
|
|
74
80
|
handle: async (context, params) => {
|
|
75
81
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
@@ -91,8 +97,10 @@ const hover = defineTool({
|
|
|
91
97
|
capability: 'core',
|
|
92
98
|
schema: {
|
|
93
99
|
name: 'browser_hover',
|
|
100
|
+
title: 'Hover mouse',
|
|
94
101
|
description: 'Hover over element on page',
|
|
95
102
|
inputSchema: elementSchema,
|
|
103
|
+
type: 'readOnly',
|
|
96
104
|
},
|
|
97
105
|
handle: async (context, params) => {
|
|
98
106
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
@@ -118,8 +126,10 @@ const type = defineTool({
|
|
|
118
126
|
capability: 'core',
|
|
119
127
|
schema: {
|
|
120
128
|
name: 'browser_type',
|
|
129
|
+
title: 'Type text',
|
|
121
130
|
description: 'Type text into editable element',
|
|
122
131
|
inputSchema: typeSchema,
|
|
132
|
+
type: 'destructive',
|
|
123
133
|
},
|
|
124
134
|
handle: async (context, params) => {
|
|
125
135
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
@@ -156,8 +166,10 @@ const selectOption = defineTool({
|
|
|
156
166
|
capability: 'core',
|
|
157
167
|
schema: {
|
|
158
168
|
name: 'browser_select_option',
|
|
169
|
+
title: 'Select option',
|
|
159
170
|
description: 'Select an option in a dropdown',
|
|
160
171
|
inputSchema: selectOptionSchema,
|
|
172
|
+
type: 'destructive',
|
|
161
173
|
},
|
|
162
174
|
handle: async (context, params) => {
|
|
163
175
|
const snapshot = context.currentTabOrDie().snapshotOrDie();
|
|
@@ -188,8 +200,10 @@ const screenshot = defineTool({
|
|
|
188
200
|
capability: 'core',
|
|
189
201
|
schema: {
|
|
190
202
|
name: 'browser_take_screenshot',
|
|
203
|
+
title: 'Take a screenshot',
|
|
191
204
|
description: `Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.`,
|
|
192
205
|
inputSchema: screenshotSchema,
|
|
206
|
+
type: 'readOnly',
|
|
193
207
|
},
|
|
194
208
|
handle: async (context, params) => {
|
|
195
209
|
const tab = context.currentTabOrDie();
|
|
@@ -206,7 +220,7 @@ const screenshot = defineTool({
|
|
|
206
220
|
code.push(`await page.${await generateLocator(locator)}.screenshot(${javascript.formatObject(options)});`);
|
|
207
221
|
else
|
|
208
222
|
code.push(`await page.screenshot(${javascript.formatObject(options)});`);
|
|
209
|
-
const includeBase64 = !context.config.
|
|
223
|
+
const includeBase64 = !context.config.noImageResponses;
|
|
210
224
|
const action = async () => {
|
|
211
225
|
const screenshot = locator ? await locator.screenshot(options) : await tab.page.screenshot(options);
|
|
212
226
|
return {
|
package/lib/tools/tabs.js
CHANGED
|
@@ -19,8 +19,10 @@ const listTabs = defineTool({
|
|
|
19
19
|
capability: 'tabs',
|
|
20
20
|
schema: {
|
|
21
21
|
name: 'browser_tab_list',
|
|
22
|
+
title: 'List tabs',
|
|
22
23
|
description: 'List browser tabs',
|
|
23
24
|
inputSchema: z.object({}),
|
|
25
|
+
type: 'readOnly',
|
|
24
26
|
},
|
|
25
27
|
handle: async (context) => {
|
|
26
28
|
await context.ensureTab();
|
|
@@ -41,10 +43,12 @@ const selectTab = captureSnapshot => defineTool({
|
|
|
41
43
|
capability: 'tabs',
|
|
42
44
|
schema: {
|
|
43
45
|
name: 'browser_tab_select',
|
|
46
|
+
title: 'Select a tab',
|
|
44
47
|
description: 'Select a tab by index',
|
|
45
48
|
inputSchema: z.object({
|
|
46
49
|
index: z.number().describe('The index of the tab to select'),
|
|
47
50
|
}),
|
|
51
|
+
type: 'readOnly',
|
|
48
52
|
},
|
|
49
53
|
handle: async (context, params) => {
|
|
50
54
|
await context.selectTab(params.index);
|
|
@@ -62,10 +66,12 @@ const newTab = captureSnapshot => defineTool({
|
|
|
62
66
|
capability: 'tabs',
|
|
63
67
|
schema: {
|
|
64
68
|
name: 'browser_tab_new',
|
|
69
|
+
title: 'Open a new tab',
|
|
65
70
|
description: 'Open a new tab',
|
|
66
71
|
inputSchema: z.object({
|
|
67
72
|
url: z.string().optional().describe('The URL to navigate to in the new tab. If not provided, the new tab will be blank.'),
|
|
68
73
|
}),
|
|
74
|
+
type: 'readOnly',
|
|
69
75
|
},
|
|
70
76
|
handle: async (context, params) => {
|
|
71
77
|
await context.newTab();
|
|
@@ -85,10 +91,12 @@ const closeTab = captureSnapshot => defineTool({
|
|
|
85
91
|
capability: 'tabs',
|
|
86
92
|
schema: {
|
|
87
93
|
name: 'browser_tab_close',
|
|
94
|
+
title: 'Close a tab',
|
|
88
95
|
description: 'Close a tab',
|
|
89
96
|
inputSchema: z.object({
|
|
90
97
|
index: z.number().optional().describe('The index of the tab to close. Closes current tab if not provided.'),
|
|
91
98
|
}),
|
|
99
|
+
type: 'destructive',
|
|
92
100
|
},
|
|
93
101
|
handle: async (context, params) => {
|
|
94
102
|
await context.closeTab(params.index);
|
package/lib/tools/testing.js
CHANGED
|
@@ -24,8 +24,10 @@ const generateTest = defineTool({
|
|
|
24
24
|
capability: 'testing',
|
|
25
25
|
schema: {
|
|
26
26
|
name: 'browser_generate_playwright_test',
|
|
27
|
+
title: 'Generate a Playwright test',
|
|
27
28
|
description: 'Generate a Playwright test for given scenario',
|
|
28
29
|
inputSchema: generateTestSchema,
|
|
30
|
+
type: 'readOnly',
|
|
29
31
|
},
|
|
30
32
|
handle: async (context, params) => {
|
|
31
33
|
return {
|
package/lib/tools.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import common from './tools/common.js';
|
|
17
|
+
import console from './tools/console.js';
|
|
18
|
+
import dialogs from './tools/dialogs.js';
|
|
19
|
+
import files from './tools/files.js';
|
|
20
|
+
import install from './tools/install.js';
|
|
21
|
+
import keyboard from './tools/keyboard.js';
|
|
22
|
+
import navigate from './tools/navigate.js';
|
|
23
|
+
import network from './tools/network.js';
|
|
24
|
+
import pdf from './tools/pdf.js';
|
|
25
|
+
import snapshot from './tools/snapshot.js';
|
|
26
|
+
import tabs from './tools/tabs.js';
|
|
27
|
+
import screen from './tools/screen.js';
|
|
28
|
+
import testing from './tools/testing.js';
|
|
29
|
+
export const snapshotTools = [
|
|
30
|
+
...common(true),
|
|
31
|
+
...console,
|
|
32
|
+
...dialogs(true),
|
|
33
|
+
...files(true),
|
|
34
|
+
...install,
|
|
35
|
+
...keyboard(true),
|
|
36
|
+
...navigate(true),
|
|
37
|
+
...network,
|
|
38
|
+
...pdf,
|
|
39
|
+
...snapshot,
|
|
40
|
+
...tabs(true),
|
|
41
|
+
...testing,
|
|
42
|
+
];
|
|
43
|
+
export const screenshotTools = [
|
|
44
|
+
...common(false),
|
|
45
|
+
...console,
|
|
46
|
+
...dialogs(false),
|
|
47
|
+
...files(false),
|
|
48
|
+
...install,
|
|
49
|
+
...keyboard(false),
|
|
50
|
+
...navigate(false),
|
|
51
|
+
...network,
|
|
52
|
+
...pdf,
|
|
53
|
+
...screen,
|
|
54
|
+
...tabs(false),
|
|
55
|
+
...testing,
|
|
56
|
+
];
|