mirror of
https://github.com/ChromeDevTools/chrome-devtools-mcp.git
synced 2026-09-14 19:45:30 +08:00
fix: add proactive tool rejection when dialog is open (#1978)
Adding proactive rejection of tool execution for tools which currently get blocked due to open dialogs (related to #1069 )
This commit is contained in:
@@ -81,6 +81,14 @@ export class McpPage implements ContextPage {
|
||||
this.#dialog = undefined;
|
||||
}
|
||||
|
||||
throwIfDialogOpen(): void {
|
||||
if (this.#dialog) {
|
||||
throw new Error(
|
||||
`A dialog is open (${this.#dialog.type()}: ${this.#dialog.message()}).`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getInPageTools(): ToolGroup<ToolDefinition> | undefined {
|
||||
return this.inPageTools;
|
||||
}
|
||||
|
||||
+10
-7
@@ -233,14 +233,17 @@ export async function createMcpServer(
|
||||
|
||||
response.setRedactNetworkHeaders(serverArgs.redactNetworkHeaders);
|
||||
try {
|
||||
const page =
|
||||
serverArgs.experimentalPageIdRouting &&
|
||||
params.pageId &&
|
||||
!serverArgs.slim
|
||||
? context.getPageById(params.pageId)
|
||||
: context.getSelectedMcpPage();
|
||||
response.setPage(page);
|
||||
if (tool.blockedByDialog) {
|
||||
page.throwIfDialogOpen();
|
||||
}
|
||||
if ('pageScoped' in tool && tool.pageScoped) {
|
||||
const page =
|
||||
serverArgs.experimentalPageIdRouting &&
|
||||
params.pageId &&
|
||||
!serverArgs.slim
|
||||
? context.getPageById(params.pageId)
|
||||
: context.getSelectedMcpPage();
|
||||
response.setPage(page);
|
||||
await tool.handler(
|
||||
{
|
||||
params,
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface BaseToolDefinition<
|
||||
conditions?: string[];
|
||||
};
|
||||
schema: Schema;
|
||||
blockedByDialog: boolean;
|
||||
}
|
||||
|
||||
export interface ToolDefinition<
|
||||
@@ -255,6 +256,7 @@ export type ContextPage = Readonly<{
|
||||
|
||||
getDialog(): Dialog | undefined;
|
||||
clearDialog(): void;
|
||||
throwIfDialogOpen(): void;
|
||||
waitForEventsAfterAction(
|
||||
action: () => Promise<unknown>,
|
||||
options?: {timeout?: number; handleDialog?: 'accept' | 'dismiss' | string},
|
||||
|
||||
@@ -78,6 +78,7 @@ export const listConsoleMessages = definePageTool(cliArgs => {
|
||||
'Set to true to return the preserved messages over the last 3 navigations.',
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response) => {
|
||||
response.setIncludeConsoleData(true, {
|
||||
pageSize: request.params.pageSize,
|
||||
@@ -103,6 +104,7 @@ export const getConsoleMessage = definePageTool({
|
||||
'The msgid of a console message on the page from the listed console messages',
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response) => {
|
||||
response.attachConsoleMessage(request.params.msgid);
|
||||
},
|
||||
|
||||
@@ -66,6 +66,7 @@ export const emulate = definePageTool({
|
||||
`Emulate device viewports '<width>x<height>x<devicePixelRatio>[,mobile][,touch][,landscape]'. 'touch' and 'mobile' to emulate mobile devices. 'landscape' to emulate landscape mode.`,
|
||||
),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, _response, context) => {
|
||||
const page = request.page;
|
||||
await context.emulate(request.params, page.pptrPage);
|
||||
|
||||
@@ -21,6 +21,7 @@ export const installExtension = defineTool({
|
||||
.string()
|
||||
.describe('Absolute path to the unpacked extension folder.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const {path} = request.params;
|
||||
const id = await context.installExtension(path);
|
||||
@@ -38,6 +39,7 @@ export const uninstallExtension = defineTool({
|
||||
schema: {
|
||||
id: zod.string().describe('ID of the extension to uninstall.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const {id} = request.params;
|
||||
await context.uninstallExtension(id);
|
||||
@@ -54,6 +56,7 @@ export const listExtensions = defineTool({
|
||||
readOnlyHint: true,
|
||||
},
|
||||
schema: {},
|
||||
blockedByDialog: false,
|
||||
handler: async (_request, response, _context) => {
|
||||
response.setListExtensions();
|
||||
},
|
||||
@@ -69,6 +72,7 @@ export const reloadExtension = defineTool({
|
||||
schema: {
|
||||
id: zod.string().describe('ID of the extension to reload.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const {id} = request.params;
|
||||
const extension = await context.getExtension(id);
|
||||
@@ -90,6 +94,7 @@ export const triggerExtensionAction = defineTool({
|
||||
schema: {
|
||||
id: zod.string().describe('ID of the extension to trigger the action for.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const {id} = request.params;
|
||||
await context.triggerExtensionAction(id);
|
||||
|
||||
@@ -51,6 +51,7 @@ export const listInPageTools = definePageTool({
|
||||
conditions: ['inPageTools'],
|
||||
},
|
||||
schema: {},
|
||||
blockedByDialog: false,
|
||||
handler: async (_request, response, _context) => {
|
||||
response.setListInPageTools();
|
||||
},
|
||||
@@ -71,6 +72,7 @@ export const executeInPageTool = definePageTool({
|
||||
.optional()
|
||||
.describe('The JSON-stringified parameters to pass to the tool'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response) => {
|
||||
const toolName = request.params.toolName;
|
||||
let params: Record<string, unknown> = {};
|
||||
|
||||
@@ -58,6 +58,7 @@ export const click = definePageTool({
|
||||
dblClick: dblClickSchema,
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const uid = request.params.uid;
|
||||
const handle = await request.page.getElementByUid(uid);
|
||||
@@ -97,6 +98,7 @@ export const clickAt = definePageTool({
|
||||
dblClick: dblClickSchema,
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
await page.waitForEventsAfterAction(async () => {
|
||||
@@ -130,6 +132,7 @@ export const hover = definePageTool({
|
||||
),
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const uid = request.params.uid;
|
||||
const handle = await request.page.getElementByUid(uid);
|
||||
@@ -233,6 +236,7 @@ export const fill = definePageTool({
|
||||
value: zod.string().describe('The value to fill in'),
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const page = request.page;
|
||||
await page.waitForEventsAfterAction(async () => {
|
||||
@@ -261,6 +265,7 @@ export const typeText = definePageTool({
|
||||
text: zod.string().describe('The text to type'),
|
||||
submitKey: submitKeySchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
await page.waitForEventsAfterAction(async () => {
|
||||
@@ -289,6 +294,7 @@ export const drag = definePageTool({
|
||||
to_uid: zod.string().describe('The uid of the element to drop into'),
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const fromHandle = await request.page.getElementByUid(
|
||||
request.params.from_uid,
|
||||
@@ -330,6 +336,7 @@ export const fillForm = definePageTool({
|
||||
.describe('Elements from snapshot to fill out.'),
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const page = request.page;
|
||||
for (const element of request.params.elements) {
|
||||
@@ -365,6 +372,7 @@ export const uploadFile = definePageTool({
|
||||
filePath: zod.string().describe('The local path of the file to upload'),
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const {uid, filePath} = request.params;
|
||||
context.validatePath(filePath);
|
||||
@@ -415,6 +423,7 @@ export const pressKey = definePageTool({
|
||||
),
|
||||
includeSnapshot: includeSnapshotSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
const tokens = parseKey(request.params.key);
|
||||
|
||||
@@ -43,6 +43,7 @@ export const lighthouseAudit = definePageTool({
|
||||
.optional()
|
||||
.describe('Directory for reports. If omitted, uses temporary files.'),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const page = request.page;
|
||||
const categories = ['accessibility', 'seo', 'best-practices'];
|
||||
|
||||
@@ -22,6 +22,7 @@ export const takeMemorySnapshot = definePageTool({
|
||||
.string()
|
||||
.describe('A path to a .heapsnapshot file to save the heapsnapshot to.'),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const page = request.page;
|
||||
context.validatePath(request.params.filePath);
|
||||
@@ -48,6 +49,7 @@ export const exploreMemorySnapshot = defineTool({
|
||||
schema: {
|
||||
filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
const stats = await context.getHeapSnapshotStats(request.params.filePath);
|
||||
@@ -79,6 +81,7 @@ export const getMemorySnapshotDetails = defineTool({
|
||||
.optional()
|
||||
.describe('The page size for pagination of aggregates.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
const aggregates = await context.getHeapSnapshotAggregates(
|
||||
@@ -111,6 +114,7 @@ export const getNodesByClass = defineTool({
|
||||
pageIdx: zod.number().optional().describe('The page index for pagination.'),
|
||||
pageSize: zod.number().optional().describe('The page size for pagination.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
const nodes = await context.getHeapSnapshotNodesByUid(
|
||||
|
||||
@@ -70,6 +70,7 @@ export const listNetworkRequests = definePageTool({
|
||||
'Set to true to return the preserved requests over the last 3 navigations.',
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const data = await request.page.getDevToolsData();
|
||||
response.attachDevToolsData(data);
|
||||
@@ -113,6 +114,7 @@ export const getNetworkRequest = definePageTool({
|
||||
'The absolute or relative path to a .network-response file to save the response body to. If omitted, the body is returned inline.',
|
||||
),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.requestFilePath);
|
||||
context.validatePath(request.params.responseFilePath);
|
||||
|
||||
@@ -84,6 +84,7 @@ export const listPages = defineTool(args => {
|
||||
readOnlyHint: true,
|
||||
},
|
||||
schema: {},
|
||||
blockedByDialog: false,
|
||||
handler: async (_request, response) => {
|
||||
response.setIncludePages(true);
|
||||
response.setListInPageTools();
|
||||
@@ -110,6 +111,7 @@ export const selectPage = defineTool({
|
||||
.optional()
|
||||
.describe('Whether to focus the page and bring it to the top.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const page = context.getPageById(request.params.pageId);
|
||||
context.selectPage(page);
|
||||
@@ -134,6 +136,7 @@ export const closePage = defineTool({
|
||||
.number()
|
||||
.describe('The ID of the page to close. Call list_pages to list pages.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
try {
|
||||
await context.closePage(request.params.pageId);
|
||||
@@ -185,6 +188,7 @@ export const newPage = defineTool(args => {
|
||||
: {}),
|
||||
...timeoutSchema,
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const page = await context.newPage(
|
||||
request.params.background,
|
||||
@@ -251,6 +255,7 @@ export const navigatePage = definePageTool(args => {
|
||||
: {}),
|
||||
...timeoutSchema,
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
const options = {
|
||||
@@ -385,6 +390,7 @@ export const resizePage = definePageTool({
|
||||
width: zod.number().describe('Page width'),
|
||||
height: zod.number().describe('Page height'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, _context) => {
|
||||
const page = request.page;
|
||||
|
||||
@@ -429,6 +435,7 @@ export const handleDialog = definePageTool({
|
||||
.optional()
|
||||
.describe('Optional prompt text to enter into the dialog.'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, _context) => {
|
||||
const page = request.page;
|
||||
const dialog = page.getDialog();
|
||||
@@ -479,6 +486,7 @@ export const getTabId = definePageTool({
|
||||
`The ID of the page to get the tab ID for. Call ${listPages().name} to get available pages.`,
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const page = context.getPageById(request.params.pageId);
|
||||
const tabId = (page.pptrPage as unknown as CdpPage)._tabId;
|
||||
|
||||
@@ -48,6 +48,7 @@ export const startTrace = definePageTool({
|
||||
),
|
||||
filePath: filePathSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
if (context.isRunningPerformanceTrace()) {
|
||||
@@ -126,6 +127,7 @@ export const stopTrace = definePageTool({
|
||||
schema: {
|
||||
filePath: filePathSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
if (!context.isRunningPerformanceTrace()) {
|
||||
@@ -161,6 +163,7 @@ export const analyzeInsight = definePageTool({
|
||||
'The name of the Insight you want more information on. For example: "DocumentLatency" or "LCPBreakdown"',
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
const lastRecording = context.recordedTraces().at(-1);
|
||||
if (!lastRecording) {
|
||||
|
||||
@@ -28,7 +28,6 @@ export const startScreencast = definePageTool(args => ({
|
||||
annotations: {
|
||||
category: ToolCategory.DEBUGGING,
|
||||
readOnlyHint: false,
|
||||
|
||||
conditions: ['screencast'],
|
||||
},
|
||||
schema: {
|
||||
@@ -39,6 +38,7 @@ export const startScreencast = definePageTool(args => ({
|
||||
`Output file path (${supportedExtensions.join(',')} are supported). Uses mkdtemp to generate a unique path if not provided.`,
|
||||
),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
if (context.getScreenRecorder() !== null) {
|
||||
@@ -102,6 +102,7 @@ export const stopScreencast = definePageTool({
|
||||
conditions: ['screencast'],
|
||||
},
|
||||
schema: {},
|
||||
blockedByDialog: false,
|
||||
handler: async (_request, response, context) => {
|
||||
const data = context.getScreenRecorder();
|
||||
if (!data) {
|
||||
|
||||
@@ -50,6 +50,7 @@ export const screenshot = definePageTool({
|
||||
'The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.',
|
||||
),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
if (request.params.uid && request.params.fullPage) {
|
||||
|
||||
@@ -64,6 +64,7 @@ Example with arguments: \`(el) => {
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const {
|
||||
serviceWorkerId,
|
||||
|
||||
@@ -18,6 +18,7 @@ export const screenshot = definePageTool({
|
||||
readOnlyHint: false,
|
||||
},
|
||||
schema: {},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const page = request.page;
|
||||
const screenshot = await page.pptrPage.screenshot({
|
||||
@@ -42,6 +43,7 @@ export const navigate = definePageTool({
|
||||
schema: {
|
||||
url: zod.string().describe('URL to navigate to'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
|
||||
@@ -79,6 +81,7 @@ export const evaluate = definePageTool({
|
||||
schema: {
|
||||
script: zod.string().describe(`JS script to run on the page`),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response) => {
|
||||
const page = request.page;
|
||||
try {
|
||||
|
||||
@@ -33,6 +33,7 @@ in the DevTools Elements panel (if any).`,
|
||||
'The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.',
|
||||
),
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
context.validatePath(request.params.filePath);
|
||||
response.includeSnapshot({
|
||||
@@ -58,6 +59,7 @@ export const waitFor = definePageTool({
|
||||
),
|
||||
...timeoutSchema,
|
||||
},
|
||||
blockedByDialog: true,
|
||||
handler: async (request, response, context) => {
|
||||
const page = request.page;
|
||||
await context.waitForTextOnPage(
|
||||
|
||||
@@ -18,6 +18,7 @@ export const listWebMcpTools = definePageTool({
|
||||
conditions: ['experimentalWebmcp'],
|
||||
},
|
||||
schema: {},
|
||||
blockedByDialog: false,
|
||||
handler: async (_request, response, _context) => {
|
||||
response.setListWebMcpTools();
|
||||
},
|
||||
@@ -38,6 +39,7 @@ export const executeWebMcpTool = definePageTool({
|
||||
.optional()
|
||||
.describe('The JSON-stringified parameters to pass to the WebMCP tool'),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async (request, response) => {
|
||||
const toolName = request.params.toolName;
|
||||
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
exports[`e2e > Dialogs > returns blocked message when dialog is opened during tool execution 1`] = `
|
||||
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\nError: Failed to interact with the element with uid 1_1. The element did not become interactive within the configured timeout."}],"isError":true}
|
||||
`;
|
||||
|
||||
exports[`e2e > Dialogs > when dialog is open and tool is blocked, returns an error 1`] = `
|
||||
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\nError: A dialog is open (alert: test dialog)."}],"isError":true}
|
||||
`;
|
||||
|
||||
exports[`e2e > Dialogs > when dialog is open and tool is not blocked, executes tool 1`] = `
|
||||
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\n## Pages\\n1: about:blank\\n2: data:text/html,<button id=\\"test\\" onclick=\\"alert('test dialog')\\">Click me</button>\\n3: data:text/html,<h1>New</h1> [selected]"}]}
|
||||
`;
|
||||
|
||||
exports[`e2e > calls a tool 1`] = `
|
||||
[{"type":"text","text":"## Pages\\n1: about:blank [selected]"}]
|
||||
`;
|
||||
@@ -5,7 +17,3 @@ exports[`e2e > calls a tool 1`] = `
|
||||
exports[`e2e > calls a tool multiple times 1`] = `
|
||||
[{"type":"text","text":"## Pages\\n1: about:blank [selected]"}]
|
||||
`;
|
||||
|
||||
exports[`e2e > returns blocked message when dialog is opened during tool execution 1`] = `
|
||||
{"content":[{"type":"text","text":"# Open dialog\\nalert: test dialog.\\nCall handle_dialog to handle it before continuing.\\nError: Failed to interact with the element with uid 1_1. The element did not become interactive within the configured timeout."}],"isError":true}
|
||||
`;
|
||||
|
||||
+38
-3
@@ -246,8 +246,8 @@ describe('e2e', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('returns blocked message when dialog is opened during tool execution', async t => {
|
||||
await withClient(async client => {
|
||||
describe('Dialogs', () => {
|
||||
async function createNewPageAndTriggerDialog(client: Client) {
|
||||
// Navigate to a page with a button that triggers a dialog on click
|
||||
await client.callTool({
|
||||
name: 'new_page',
|
||||
@@ -273,7 +273,42 @@ describe('e2e', () => {
|
||||
},
|
||||
});
|
||||
|
||||
t.assert.snapshot?.(JSON.stringify(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
it('returns blocked message when dialog is opened during tool execution', async t => {
|
||||
await withClient(async client => {
|
||||
const result = await createNewPageAndTriggerDialog(client);
|
||||
t.assert.snapshot?.(JSON.stringify(result));
|
||||
});
|
||||
});
|
||||
|
||||
it('when dialog is open and tool is blocked, returns an error', async t => {
|
||||
await withClient(async client => {
|
||||
await createNewPageAndTriggerDialog(client);
|
||||
const result = await client.callTool({
|
||||
name: 'take_screenshot',
|
||||
arguments: {
|
||||
filePath: '/tmp/test.png',
|
||||
},
|
||||
});
|
||||
|
||||
t.assert.snapshot?.(JSON.stringify(result));
|
||||
});
|
||||
});
|
||||
|
||||
it('when dialog is open and tool is not blocked, executes tool', async t => {
|
||||
await withClient(async client => {
|
||||
await createNewPageAndTriggerDialog(client);
|
||||
const result = await client.callTool({
|
||||
name: 'new_page',
|
||||
arguments: {
|
||||
url: `data:text/html,<h1>New</h1>`,
|
||||
},
|
||||
});
|
||||
|
||||
t.assert.snapshot?.(JSON.stringify(result));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@ describe('toolMetricsUtils', () => {
|
||||
argStr: zod.string(),
|
||||
uid: zod.string(), // Should be blocked
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async () => {
|
||||
// no-op
|
||||
},
|
||||
@@ -70,6 +71,7 @@ describe('toolMetricsUtils', () => {
|
||||
schema: {
|
||||
argEnum: zod.enum(['foo', 'bar']),
|
||||
},
|
||||
blockedByDialog: false,
|
||||
handler: async () => {
|
||||
// no-op
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user