Path: blob/main/src/vs/workbench/contrib/browserView/electron-browser/tools/handleDialogBrowserTool.ts
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { CancellationToken } from '../../../../../base/common/cancellation.js';6import { Codicon } from '../../../../../base/common/codicons.js';7import { MarkdownString } from '../../../../../base/common/htmlContent.js';8import { localize } from '../../../../../nls.js';9import { IPlaywrightService } from '../../../../../platform/browserView/common/playwrightService.js';10import { ToolDataSource, type CountTokensCallback, type IPreparedToolInvocation, type IToolData, type IToolImpl, type IToolInvocation, type IToolInvocationPreparationContext, type IToolResult, type ToolProgress } from '../../../chat/common/tools/languageModelToolsService.js';11import { createBrowserPageLink, errorResult } from './browserToolHelpers.js';12import { BrowserChatToolReferenceName } from '../../common/browserChatToolReferenceNames.js';13import { OpenPageToolId } from './openBrowserTool.js';1415export const HandleDialogBrowserToolData: IToolData = {16id: 'handle_dialog',17toolReferenceName: BrowserChatToolReferenceName.HandleDialog,18displayName: localize('handleDialogBrowserTool.displayName', 'Handle Dialog'),19userDescription: localize('handleDialogBrowserTool.userDescription', 'Respond to a dialog in a browser page'),20modelDescription: 'Respond to a pending modal (alert, confirm, prompt) or file chooser dialog on a browser page.',21icon: Codicon.comment,22source: ToolDataSource.Internal,23inputSchema: {24type: 'object',25properties: {26pageId: {27type: 'string',28description: `The browser page ID, acquired from context or the open tool.`29},30acceptModal: {31type: 'boolean',32description: 'Whether to accept (true) or dismiss (false) a modal dialog.'33},34promptText: {35type: 'string',36description: 'Text to enter into a prompt dialog.'37},38selectFiles: {39type: 'array',40items: { type: 'string' },41description: 'Absolute paths of files to select, or empty to dismiss. Required for file chooser dialogs.'42},43},44required: ['pageId'],45},46};4748interface IHandleDialogBrowserToolParams {49pageId: string;50acceptModal: boolean;51promptText?: string;52selectFiles?: string[];53}5455export class HandleDialogBrowserTool implements IToolImpl {56constructor(57@IPlaywrightService private readonly playwrightService: IPlaywrightService,58) { }5960async prepareToolInvocation(_context: IToolInvocationPreparationContext, _token: CancellationToken): Promise<IPreparedToolInvocation | undefined> {61const link = createBrowserPageLink(_context.parameters.pageId);62return {63invocationMessage: new MarkdownString(localize('browser.handleDialog.invocation', "Handling dialog in {0}", link)),64pastTenseMessage: new MarkdownString(localize('browser.handleDialog.past', "Handled dialog in {0}", link)),65};66}6768async invoke(invocation: IToolInvocation, _countTokens: CountTokensCallback, _progress: ToolProgress, _token: CancellationToken): Promise<IToolResult> {69const params = invocation.parameters as IHandleDialogBrowserToolParams;7071if (!params.pageId) {72return errorResult(`No page ID provided. Use '${OpenPageToolId}' first.`);73}7475if (params.selectFiles !== undefined && (params.acceptModal !== undefined || params.promptText !== undefined)) {76return errorResult(`Invalid parameters. 'selectFiles' cannot be used with 'acceptModal' or 'promptText'.`);77}7879if (!Array.isArray(params.selectFiles) && (params.acceptModal === undefined || params.acceptModal === null)) {80return errorResult(`Invalid parameters. Either 'selectFiles' or 'acceptModal' must be provided.`);81}8283try {84let result;85if (params.selectFiles !== undefined) {86result = await this.playwrightService.replyToFileChooser(params.pageId, params.selectFiles);87} else {88result = await this.playwrightService.replyToDialog(params.pageId, params.acceptModal, params.promptText);89}90return { content: [{ kind: 'text', value: result.summary }] };91} catch (e) {92return errorResult(e instanceof Error ? e.message : String(e));93}94}95}969798