Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/browserView/electron-browser/tools/runPlaywrightCodeTool.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import type { CancellationToken } from '../../../../../base/common/cancellation.js';
7
import { Codicon } from '../../../../../base/common/codicons.js';
8
import { MarkdownString } from '../../../../../base/common/htmlContent.js';
9
import { localize } from '../../../../../nls.js';
10
import { IPlaywrightService } from '../../../../../platform/browserView/common/playwrightService.js';
11
import { ToolDataSource, type CountTokensCallback, type IPreparedToolInvocation, type IToolData, type IToolImpl, type IToolInvocation, type IToolInvocationPreparationContext, type IToolResult, type ToolProgress } from '../../../chat/common/tools/languageModelToolsService.js';
12
import { errorResult, invokeFunctionResultToToolResult } from './browserToolHelpers.js';
13
import { BrowserChatToolReferenceName } from '../../common/browserChatToolReferenceNames.js';
14
import { OpenPageToolId } from './openBrowserTool.js';
15
16
export const RunPlaywrightCodeToolData: IToolData = {
17
id: 'run_playwright_code',
18
toolReferenceName: BrowserChatToolReferenceName.RunPlaywrightCode,
19
displayName: localize('runPlaywrightCodeTool.displayName', 'Run Playwright Code'),
20
userDescription: localize('runPlaywrightCodeTool.userDescription', 'Run a Playwright code snippet against a browser page'),
21
modelDescription: `Run a Playwright code snippet to control a browser page. Only use this if other browser tools are insufficient.`,
22
icon: Codicon.terminal,
23
source: ToolDataSource.Internal,
24
inputSchema: {
25
type: 'object',
26
properties: {
27
pageId: {
28
type: 'string',
29
description: `The browser page ID, acquired from context or the open tool.`
30
},
31
code: {
32
type: 'string',
33
description: `The Playwright code to execute. The code must be concise, serve one clear purpose, and be self-contained. You **must not** directly access \`document\` or \`window\` using this tool. You must access it via the provided \`page\` object, e.g. "return page.evaluate(() => document.title)". Omit this when resuming a deferred execution via deferredResultId.`
34
},
35
deferredResultId: {
36
type: 'string',
37
description: `If a previous call returned a deferredResultId, pass it here to continue waiting for that execution to complete.`
38
},
39
timeoutMs: {
40
type: 'number',
41
description: `Maximum time in milliseconds to wait for the code to complete. Defaults to 5000 (5 seconds).`
42
},
43
},
44
required: ['pageId'],
45
$comment: 'Either "code" or "deferredResultId" must be provided.',
46
},
47
};
48
49
interface IRunPlaywrightCodeToolParams {
50
pageId: string;
51
code?: string;
52
deferredResultId?: string;
53
timeoutMs?: number;
54
}
55
56
export class RunPlaywrightCodeTool implements IToolImpl {
57
constructor(
58
@IPlaywrightService private readonly playwrightService: IPlaywrightService,
59
) { }
60
61
async prepareToolInvocation(context: IToolInvocationPreparationContext, _token: CancellationToken): Promise<IPreparedToolInvocation | undefined> {
62
const params = context.parameters as IRunPlaywrightCodeToolParams;
63
64
if (params.deferredResultId) {
65
return {
66
invocationMessage: new MarkdownString(localize('browser.runCode.waitInvocation', "Waiting for Playwright code to complete...")),
67
pastTenseMessage: new MarkdownString(localize('browser.runCode.waitPast', "Waited for Playwright code")),
68
};
69
}
70
71
const code = params.code ?? '';
72
return {
73
invocationMessage: new MarkdownString(localize('browser.runCode.invocation', "Running Playwright code...")),
74
pastTenseMessage: new MarkdownString(localize('browser.runCode.past', "Ran Playwright code")),
75
confirmationMessages: {
76
title: localize('browser.runCode.confirmTitle', 'Run Playwright Code?'),
77
message: new MarkdownString(`\`\`\`javascript\n${code.trim()}\n\`\`\``),
78
disclaimer: localize('browser.runCode.confirmDisclaimer', 'Make sure you trust the code before continuing.'),
79
allowAutoConfirm: true,
80
}
81
};
82
}
83
84
async invoke(invocation: IToolInvocation, _countTokens: CountTokensCallback, _progress: ToolProgress, _token: CancellationToken): Promise<IToolResult> {
85
const params = invocation.parameters as IRunPlaywrightCodeToolParams;
86
87
if (!params.pageId) {
88
return errorResult(`No page ID provided. Use '${OpenPageToolId}' first.`);
89
}
90
91
// Resume waiting for a deferred execution
92
if (params.deferredResultId) {
93
try {
94
const result = await this.playwrightService.waitForDeferredResult(params.deferredResultId, params.timeoutMs ?? 5_000);
95
return invokeFunctionResultToToolResult(result);
96
} catch (e) {
97
return errorResult(e instanceof Error ? e.message : String(e));
98
}
99
}
100
101
if (!params.code) {
102
return errorResult('Either "code" or "deferredResultId" must be provided.');
103
}
104
105
let result;
106
try {
107
result = await this.playwrightService.invokeFunction(params.pageId, `async (page) => { ${params.code} }`, undefined, params.timeoutMs ?? 5_000);
108
} catch (e) {
109
const message = e instanceof Error ? e.message : String(e);
110
return errorResult(`Code execution failed: ${message}`);
111
}
112
113
return invokeFunctionResultToToolResult(result, params.code.trim());
114
}
115
}
116
117