diff --git a/src/tools/codeInjection.ts b/src/tools/codeInjection.ts index 9fc1cdf..532c626 100644 --- a/src/tools/codeInjection.ts +++ b/src/tools/codeInjection.ts @@ -565,7 +565,7 @@ const enableDebugToolbarSchema = z.object({ theme: z.enum(['light', 'dark', 'transparent']).optional().describe('Visual theme: light (white), dark (gray), transparent (glass effect)'), minimized: z.boolean().optional().describe('Start in compact pill mode (default: false)'), showDetails: z.boolean().optional().describe('Show session details when expanded (default: true)'), - opacity: z.number().min(0.1).max(1.0).optional().describe('Toolbar opacity 0.1-1.0 (default: 0.95)') + opacity: z.coerce.number().min(0.1).max(1.0).optional().describe('Toolbar opacity 0.1-1.0 (default: 0.95)') }); const injectCustomCodeSchema = z.object({ @@ -580,13 +580,13 @@ const enableVoiceCollaborationSchema = z.object({ enabled: z.boolean().optional().describe('Enable voice collaboration features (default: true)'), autoInitialize: z.boolean().optional().describe('Automatically initialize voice on page load (default: true)'), voiceOptions: z.object({ - rate: z.number().min(0.1).max(10).optional().describe('Speech rate (0.1-10, default: 1.0)'), - pitch: z.number().min(0).max(2).optional().describe('Speech pitch (0-2, default: 1.0)'), - volume: z.number().min(0).max(1).optional().describe('Speech volume (0-1, default: 1.0)'), + rate: z.coerce.number().min(0.1).max(10).optional().describe('Speech rate (0.1-10, default: 1.0)'), + pitch: z.coerce.number().min(0).max(2).optional().describe('Speech pitch (0-2, default: 1.0)'), + volume: z.coerce.number().min(0).max(1).optional().describe('Speech volume (0-1, default: 1.0)'), lang: z.string().optional().describe('Language code (default: en-US)') }).optional().describe('Voice synthesis options'), listenOptions: z.object({ - timeout: z.number().min(1000).max(60000).optional().describe('Voice input timeout in milliseconds (default: 10000)'), + timeout: z.coerce.number().min(1000).max(60000).optional().describe('Voice input timeout in milliseconds (default: 10000)'), lang: z.string().optional().describe('Speech recognition language (default: en-US)'), continuous: z.boolean().optional().describe('Keep listening after first result (default: false)') }).optional().describe('Voice recognition options') diff --git a/src/tools/common.ts b/src/tools/common.ts index 337f4ba..d4fe084 100644 --- a/src/tools/common.ts +++ b/src/tools/common.ts @@ -40,10 +40,10 @@ const resize = defineTabTool({ schema: { name: 'browser_resize', title: 'Resize browser window', - description: 'Resize the browser window', + description: 'Resize the browser viewport to the specified width and height in pixels. Common sizes: 1920x1080 (Full HD), 1440x900 (laptop), 1280x720 (HD), 390x844 (mobile).', inputSchema: z.object({ - width: z.number().describe('Width of the browser window'), - height: z.number().describe('Height of the browser window'), + width: z.coerce.number().describe('Viewport width in pixels'), + height: z.coerce.number().describe('Viewport height in pixels'), }), type: 'readOnly', }, diff --git a/src/tools/configure.ts b/src/tools/configure.ts index ff40929..4c1f1d1 100644 --- a/src/tools/configure.ts +++ b/src/tools/configure.ts @@ -24,15 +24,15 @@ import type { Response } from '../response.js'; const configureSchema = z.object({ headless: z.boolean().optional().describe('Whether to run the browser in headless mode'), viewport: z.object({ - width: z.number(), - height: z.number(), + width: z.coerce.number(), + height: z.coerce.number(), }).optional().describe('Browser viewport size'), userAgent: z.string().optional().describe('User agent string for the browser'), device: z.string().optional().describe('Device to emulate (e.g., "iPhone 13", "iPad", "Pixel 5"). Use browser_list_devices to see available devices.'), geolocation: z.object({ - latitude: z.number().min(-90).max(90), - longitude: z.number().min(-180).max(180), - accuracy: z.number().min(0).optional().describe('Accuracy in meters (default: 100)') + latitude: z.coerce.number().min(-90).max(90), + longitude: z.coerce.number().min(-180).max(180), + accuracy: z.coerce.number().min(0).optional().describe('Accuracy in meters (default: 100)') }).optional().describe('Set geolocation coordinates'), locale: z.string().optional().describe('Browser locale (e.g., "en-US", "fr-FR", "ja-JP")'), timezone: z.string().optional().describe('Timezone ID (e.g., "America/New_York", "Europe/London", "Asia/Tokyo")'), @@ -46,7 +46,7 @@ const configureSchema = z.object({ // Browser UI Customization Options chromiumSandbox: z.boolean().optional().describe('Enable/disable Chromium sandbox (affects browser appearance)'), - slowMo: z.number().min(0).optional().describe('Slow down operations by specified milliseconds (helps with visual tracking)'), + slowMo: z.coerce.number().min(0).optional().describe('Slow down operations by specified milliseconds (helps with visual tracking)'), devtools: z.boolean().optional().describe('Open browser with DevTools panel open (Chromium only)'), args: z.array(z.string()).optional().describe('Additional browser launch arguments for UI customization (e.g., ["--force-color-profile=srgb", "--disable-features=VizDisplayCompositor"])'), }); @@ -93,7 +93,7 @@ const installPopularExtensionSchema = z.object({ const configureSnapshotsSchema = z.object({ includeSnapshots: z.boolean().optional().describe('Enable/disable automatic snapshots after interactive operations. When false, use browser_snapshot for explicit snapshots.'), - maxSnapshotTokens: z.number().min(0).optional().describe('Maximum tokens allowed in snapshots before truncation. Use 0 to disable truncation.'), + maxSnapshotTokens: z.coerce.number().min(0).optional().describe('Maximum tokens allowed in snapshots before truncation. Use 0 to disable truncation.'), differentialSnapshots: z.boolean().optional().describe('Enable differential snapshots that show only changes since last snapshot instead of full page snapshots.'), differentialMode: z.enum(['semantic', 'simple', 'both']).optional().describe('Type of differential analysis: "semantic" (React-style reconciliation), "simple" (text diff), or "both" (show comparison).'), consoleOutputFile: z.string().optional().describe('File path to write browser console output to. Set to empty string to disable console file output.'), @@ -104,9 +104,9 @@ const configureSnapshotsSchema = z.object({ filterMode: z.enum(['content', 'count', 'files']).optional().describe('Type of filtering output: "content" (filtered data), "count" (match statistics), "files" (matching items only)'), caseSensitive: z.boolean().optional().describe('Case sensitive pattern matching (default: true)'), wholeWords: z.boolean().optional().describe('Match whole words only (default: false)'), - contextLines: z.number().min(0).optional().describe('Number of context lines around matches'), + contextLines: z.coerce.number().min(0).optional().describe('Number of context lines around matches'), invertMatch: z.boolean().optional().describe('Invert match to show non-matches (default: false)'), - maxMatches: z.number().min(1).optional().describe('Maximum number of matches to return'), + maxMatches: z.coerce.number().min(1).optional().describe('Maximum number of matches to return'), // jq Structural Filtering Parameters jqExpression: z.string().optional().describe( diff --git a/src/tools/mouse.ts b/src/tools/mouse.ts index c1b597c..e418ec4 100644 --- a/src/tools/mouse.ts +++ b/src/tools/mouse.ts @@ -22,13 +22,13 @@ const elementSchema = z.object({ }); const coordinateSchema = z.object({ - x: z.number().describe('X coordinate'), - y: z.number().describe('Y coordinate'), + x: z.coerce.number().describe('X coordinate'), + y: z.coerce.number().describe('Y coordinate'), }); const advancedCoordinateSchema = coordinateSchema.extend({ precision: z.enum(['pixel', 'subpixel']).optional().default('pixel').describe('Coordinate precision level'), - delay: z.number().min(0).max(5000).optional().describe('Delay in milliseconds before action'), + delay: z.coerce.number().min(0).max(5000).optional().describe('Delay in milliseconds before action'), }); const mouseMove = defineTabTool({ @@ -64,8 +64,8 @@ const mouseClick = defineTabTool({ description: 'Click mouse button at a given position with advanced options', inputSchema: elementSchema.extend(advancedCoordinateSchema.shape).extend({ button: z.enum(['left', 'right', 'middle']).optional().default('left').describe('Mouse button to click'), - clickCount: z.number().min(1).max(3).optional().default(1).describe('Number of clicks (1=single, 2=double, 3=triple)'), - holdTime: z.number().min(0).max(2000).optional().default(0).describe('How long to hold button down in milliseconds'), + clickCount: z.coerce.number().min(1).max(3).optional().default(1).describe('Number of clicks (1=single, 2=double, 3=triple)'), + holdTime: z.coerce.number().min(0).max(2000).optional().default(0).describe('How long to hold button down in milliseconds'), }), type: 'destructive', }, @@ -111,16 +111,16 @@ const mouseDrag = defineTabTool({ title: 'Drag mouse', description: 'Drag mouse button from start to end position with advanced drag patterns', inputSchema: elementSchema.extend({ - startX: z.number().describe('Start X coordinate'), - startY: z.number().describe('Start Y coordinate'), - endX: z.number().describe('End X coordinate'), - endY: z.number().describe('End Y coordinate'), + startX: z.coerce.number().describe('Start X coordinate'), + startY: z.coerce.number().describe('Start Y coordinate'), + endX: z.coerce.number().describe('End X coordinate'), + endY: z.coerce.number().describe('End Y coordinate'), button: z.enum(['left', 'right', 'middle']).optional().default('left').describe('Mouse button to drag with'), precision: z.enum(['pixel', 'subpixel']).optional().default('pixel').describe('Coordinate precision level'), pattern: z.enum(['direct', 'smooth', 'bezier']).optional().default('direct').describe('Drag movement pattern'), - steps: z.number().min(1).max(50).optional().default(10).describe('Number of intermediate steps for smooth/bezier patterns'), - duration: z.number().min(100).max(10000).optional().describe('Total drag duration in milliseconds'), - delay: z.number().min(0).max(5000).optional().describe('Delay before starting drag'), + steps: z.coerce.number().min(1).max(50).optional().default(10).describe('Number of intermediate steps for smooth/bezier patterns'), + duration: z.coerce.number().min(100).max(10000).optional().describe('Total drag duration in milliseconds'), + delay: z.coerce.number().min(0).max(5000).optional().describe('Delay before starting drag'), }), type: 'destructive', }, @@ -209,8 +209,8 @@ const mouseScroll = defineTabTool({ title: 'Scroll at coordinates', description: 'Perform scroll action at specific coordinates with precision control', inputSchema: elementSchema.extend(advancedCoordinateSchema.shape).extend({ - deltaX: z.number().optional().default(0).describe('Horizontal scroll amount (positive = right, negative = left)'), - deltaY: z.number().describe('Vertical scroll amount (positive = down, negative = up)'), + deltaX: z.coerce.number().optional().default(0).describe('Horizontal scroll amount (positive = right, negative = left)'), + deltaY: z.coerce.number().describe('Vertical scroll amount (positive = down, negative = up)'), smooth: z.boolean().optional().default(false).describe('Use smooth scrolling animation'), }), type: 'destructive', @@ -256,9 +256,9 @@ const mouseGesture = defineTabTool({ description: 'Perform complex mouse gestures with multiple waypoints', inputSchema: elementSchema.extend({ points: z.array(z.object({ - x: z.number().describe('X coordinate'), - y: z.number().describe('Y coordinate'), - delay: z.number().min(0).max(5000).optional().describe('Delay at this point in milliseconds'), + x: z.coerce.number().describe('X coordinate'), + y: z.coerce.number().describe('Y coordinate'), + delay: z.coerce.number().min(0).max(5000).optional().describe('Delay at this point in milliseconds'), action: z.enum(['move', 'click', 'down', 'up']).optional().default('move').describe('Action at this point'), })).min(2).describe('Array of points defining the gesture path'), button: z.enum(['left', 'right', 'middle']).optional().default('left').describe('Mouse button for click actions'), diff --git a/src/tools/network-throttle.ts b/src/tools/network-throttle.ts index 45b9bb7..ed27fe3 100644 --- a/src/tools/network-throttle.ts +++ b/src/tools/network-throttle.ts @@ -98,11 +98,11 @@ const currentNetworkConditions = new WeakMap