fix: use z.coerce.number() for all numeric tool parameters
MCP clients may send numbers as strings in JSON parameters. Using z.coerce.number() instead of z.number() across all 13 tool files ensures string-to-number coercion happens automatically, preventing "Expected number, received string" validation errors.
This commit is contained in:
parent
a65f00667a
commit
6cbc5f6bc1
@ -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')
|
||||
|
||||
@ -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',
|
||||
},
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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'),
|
||||
|
||||
@ -98,11 +98,11 @@ const currentNetworkConditions = new WeakMap<Context, {
|
||||
const setNetworkConditionsSchema = z.object({
|
||||
preset: z.enum(['offline', 'slow-3g', 'fast-3g', 'regular-4g', 'wifi', 'no-throttle']).optional()
|
||||
.describe('Network condition preset. Use "offline" to block all requests, "slow-3g" for poor mobile, "fast-3g" for typical mobile, "regular-4g" for LTE, "wifi" for home WiFi, or "no-throttle" to remove throttling.'),
|
||||
downloadThroughput: z.number().min(-1).optional()
|
||||
downloadThroughput: z.coerce.number().min(-1).optional()
|
||||
.describe('Custom download speed in bytes/second. Use -1 for no throttling. Overrides preset if specified.'),
|
||||
uploadThroughput: z.number().min(-1).optional()
|
||||
uploadThroughput: z.coerce.number().min(-1).optional()
|
||||
.describe('Custom upload speed in bytes/second. Use -1 for no throttling. Overrides preset if specified.'),
|
||||
latency: z.number().min(0).optional()
|
||||
latency: z.coerce.number().min(0).optional()
|
||||
.describe('Custom latency in milliseconds to add to each request. Overrides preset if specified.'),
|
||||
offline: z.boolean().optional()
|
||||
.describe('Set to true to simulate offline mode. Overrides preset if specified.')
|
||||
|
||||
@ -166,7 +166,7 @@ const waitForNotification = defineTabTool({
|
||||
title: z.string().optional().describe('Wait for notification with this exact title'),
|
||||
titleContains: z.string().optional().describe('Wait for notification with title containing this text'),
|
||||
origin: z.string().optional().describe('Wait for notification from this origin'),
|
||||
timeout: z.number().optional().describe('Maximum time to wait in milliseconds (default: 30000)'),
|
||||
timeout: z.coerce.number().optional().describe('Maximum time to wait in milliseconds (default: 30000)'),
|
||||
}),
|
||||
type: 'readOnly',
|
||||
},
|
||||
@ -354,9 +354,9 @@ const setGeolocation = defineTool({
|
||||
title: 'Set geolocation at runtime',
|
||||
description: 'Set the browser\'s geolocation at runtime without restarting. Automatically grants geolocation permission.',
|
||||
inputSchema: z.object({
|
||||
latitude: z.number().min(-90).max(90).describe('Latitude coordinate (-90 to 90)'),
|
||||
longitude: z.number().min(-180).max(180).describe('Longitude coordinate (-180 to 180)'),
|
||||
accuracy: z.number().optional().describe('Accuracy in meters (default: 100)'),
|
||||
latitude: z.coerce.number().min(-90).max(90).describe('Latitude coordinate (-90 to 90)'),
|
||||
longitude: z.coerce.number().min(-180).max(180).describe('Longitude coordinate (-180 to 180)'),
|
||||
accuracy: z.coerce.number().optional().describe('Accuracy in meters (default: 100)'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
@ -307,7 +307,7 @@ const pwaDownload = defineTabTool({
|
||||
includeIcons: z.boolean().optional().default(true).describe('Download all icon sizes from manifest (default: true)'),
|
||||
includeCache: z.boolean().optional().default(true).describe('Download cached resources from CacheStorage (default: true)'),
|
||||
createZip: z.boolean().optional().default(false).describe('Create zip archive of downloaded content (default: false)'),
|
||||
maxCacheSize: z.number().optional().default(100).describe('Maximum total cache size to download in MB (default: 100)'),
|
||||
maxCacheSize: z.coerce.number().optional().default(100).describe('Maximum total cache size to download in MB (default: 100)'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
@ -31,7 +31,7 @@ const startMonitoringSchema = z.object({
|
||||
|
||||
captureBody: z.boolean().optional().default(true).describe('Whether to capture request and response bodies (default: true)'),
|
||||
|
||||
maxBodySize: z.number().optional().default(10485760).describe('Maximum body size to capture in bytes (default: 10MB). Larger bodies will be truncated'),
|
||||
maxBodySize: z.coerce.number().optional().default(10485760).describe('Maximum body size to capture in bytes (default: 10MB). Larger bodies will be truncated'),
|
||||
|
||||
autoSave: z.boolean().optional().default(false).describe('Automatically save captured requests after each response (default: false for performance)'),
|
||||
|
||||
@ -45,11 +45,11 @@ const getRequestsSchema = paginationParamsSchema.extend({
|
||||
|
||||
method: z.string().optional().describe('Filter requests by HTTP method (GET, POST, etc.)'),
|
||||
|
||||
status: z.number().optional().describe('Filter requests by HTTP status code'),
|
||||
status: z.coerce.number().optional().describe('Filter requests by HTTP status code'),
|
||||
|
||||
format: z.enum(['summary', 'detailed', 'stats']).optional().default('summary').describe('Response format: summary (basic info), detailed (full data), stats (statistics only)'),
|
||||
|
||||
slowThreshold: z.number().optional().default(1000).describe('Threshold in milliseconds for considering requests "slow" (default: 1000ms)')
|
||||
slowThreshold: z.coerce.number().optional().default(1000).describe('Threshold in milliseconds for considering requests "slow" (default: 1000ms)')
|
||||
});
|
||||
|
||||
const exportRequestsSchema = z.object({
|
||||
|
||||
@ -42,9 +42,9 @@ const setDeviceOrientation = defineTabTool({
|
||||
|
||||
**Note:** Requires Chromium-based browser. This overrides the DeviceOrientationEvent.`,
|
||||
inputSchema: z.object({
|
||||
alpha: z.number().min(0).max(360).describe('Compass heading (0-360 degrees). 0=North, 90=East, 180=South, 270=West'),
|
||||
beta: z.number().min(-180).max(180).describe('Front-to-back tilt (-180 to 180 degrees). Positive=tilted backward'),
|
||||
gamma: z.number().min(-90).max(90).describe('Left-to-right tilt (-90 to 90 degrees). Positive=tilted right'),
|
||||
alpha: z.coerce.number().min(0).max(360).describe('Compass heading (0-360 degrees). 0=North, 90=East, 180=South, 270=West'),
|
||||
beta: z.coerce.number().min(-180).max(180).describe('Front-to-back tilt (-180 to 180 degrees). Positive=tilted backward'),
|
||||
gamma: z.coerce.number().min(-90).max(90).describe('Left-to-right tilt (-90 to 90 degrees). Positive=tilted right'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
@ -144,21 +144,21 @@ const setDeviceMotion = defineTabTool({
|
||||
**Note:** Requires Chromium-based browser.`,
|
||||
inputSchema: z.object({
|
||||
acceleration: z.object({
|
||||
x: z.number().describe('Acceleration on x-axis (m/s²)'),
|
||||
y: z.number().describe('Acceleration on y-axis (m/s²)'),
|
||||
z: z.number().describe('Acceleration on z-axis (m/s²)'),
|
||||
x: z.coerce.number().describe('Acceleration on x-axis (m/s²)'),
|
||||
y: z.coerce.number().describe('Acceleration on y-axis (m/s²)'),
|
||||
z: z.coerce.number().describe('Acceleration on z-axis (m/s²)'),
|
||||
}).optional().describe('Linear acceleration excluding gravity'),
|
||||
accelerationIncludingGravity: z.object({
|
||||
x: z.number().describe('Acceleration on x-axis including gravity (m/s²)'),
|
||||
y: z.number().describe('Acceleration on y-axis including gravity (m/s²)'),
|
||||
z: z.number().describe('Acceleration on z-axis including gravity (m/s²)'),
|
||||
x: z.coerce.number().describe('Acceleration on x-axis including gravity (m/s²)'),
|
||||
y: z.coerce.number().describe('Acceleration on y-axis including gravity (m/s²)'),
|
||||
z: z.coerce.number().describe('Acceleration on z-axis including gravity (m/s²)'),
|
||||
}).optional().describe('Total acceleration including gravity'),
|
||||
rotationRate: z.object({
|
||||
alpha: z.number().describe('Rotation rate around z-axis (deg/s)'),
|
||||
beta: z.number().describe('Rotation rate around x-axis (deg/s)'),
|
||||
gamma: z.number().describe('Rotation rate around y-axis (deg/s)'),
|
||||
alpha: z.coerce.number().describe('Rotation rate around z-axis (deg/s)'),
|
||||
beta: z.coerce.number().describe('Rotation rate around x-axis (deg/s)'),
|
||||
gamma: z.coerce.number().describe('Rotation rate around y-axis (deg/s)'),
|
||||
}).optional().describe('Angular velocity around each axis'),
|
||||
interval: z.number().optional().describe('Interval between samples in milliseconds (default: 16)'),
|
||||
interval: z.coerce.number().optional().describe('Interval between samples in milliseconds (default: 16)'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
@ -83,7 +83,7 @@ const setCookie = defineTool({
|
||||
url: z.string().optional().describe('URL to associate with the cookie. Either url or domain must be specified.'),
|
||||
domain: z.string().optional().describe('Cookie domain. Either url or domain must be specified.'),
|
||||
path: z.string().optional().describe('Cookie path (default: "/")'),
|
||||
expires: z.number().optional().describe('Unix timestamp in seconds for cookie expiration. -1 for session cookie.'),
|
||||
expires: z.coerce.number().optional().describe('Unix timestamp in seconds for cookie expiration. -1 for session cookie.'),
|
||||
httpOnly: z.boolean().optional().describe('Whether the cookie is HTTP only (default: false)'),
|
||||
secure: z.boolean().optional().describe('Whether the cookie is secure (default: false)'),
|
||||
sameSite: z.enum(['Strict', 'Lax', 'None']).optional().describe('SameSite attribute (default: "Lax")'),
|
||||
|
||||
@ -42,7 +42,7 @@ const selectTab = defineTool({
|
||||
title: 'Select a tab',
|
||||
description: 'Select a tab by index. Returns page snapshot after selecting tab (configurable via browser_configure_snapshots).',
|
||||
inputSchema: z.object({
|
||||
index: z.number().describe('The index of the tab to select'),
|
||||
index: z.coerce.number().describe('The index of the tab to select'),
|
||||
}),
|
||||
type: 'readOnly',
|
||||
},
|
||||
@ -82,7 +82,7 @@ const closeTab = defineTool({
|
||||
title: 'Close a tab',
|
||||
description: 'Close a tab. Returns page snapshot after closing tab (configurable via browser_configure_snapshots).',
|
||||
inputSchema: z.object({
|
||||
index: z.number().optional().describe('The index of the tab to close. Closes current tab if not provided.'),
|
||||
index: z.coerce.number().optional().describe('The index of the tab to close. Closes current tab if not provided.'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
@ -28,8 +28,8 @@ const startRecording = defineTool({
|
||||
description: 'Start recording browser session video with intelligent viewport matching. For best results, the browser viewport size should match the video recording size to avoid gray space around content. Use browser_configure to set viewport size before recording.',
|
||||
inputSchema: z.object({
|
||||
size: z.object({
|
||||
width: z.number().optional().describe('Video width in pixels (default: 1280). For full-frame content, set browser viewport to match this width.'),
|
||||
height: z.number().optional().describe('Video height in pixels (default: 720). For full-frame content, set browser viewport to match this height.'),
|
||||
width: z.coerce.number().optional().describe('Video width in pixels (default: 1280). For full-frame content, set browser viewport to match this width.'),
|
||||
height: z.coerce.number().optional().describe('Video height in pixels (default: 720). For full-frame content, set browser viewport to match this height.'),
|
||||
}).optional().describe('Video recording dimensions. IMPORTANT: Browser viewport should match these dimensions to avoid gray borders around content.'),
|
||||
filename: z.string().optional().describe('Base filename for video files (default: session-{timestamp}.webm)'),
|
||||
autoSetViewport: z.boolean().optional().default(true).describe('Automatically set browser viewport to match video recording size (recommended for full-frame content)'),
|
||||
|
||||
@ -25,7 +25,7 @@ const wait = defineTool({
|
||||
title: 'Wait for',
|
||||
description: 'Wait for text to appear or disappear or a specified time to pass. In smart recording mode, video recording is automatically paused during waits unless recordDuringWait is true.',
|
||||
inputSchema: z.object({
|
||||
time: z.number().optional().describe('The time to wait in seconds'),
|
||||
time: z.coerce.number().optional().describe('The time to wait in seconds'),
|
||||
text: z.string().optional().describe('The text to wait for'),
|
||||
textGone: z.string().optional().describe('The text to wait for to disappear'),
|
||||
recordDuringWait: z.boolean().optional().default(false).describe('Whether to keep video recording active during the wait (default: false in smart mode, true in continuous mode)'),
|
||||
|
||||
@ -28,7 +28,7 @@ const startWebRTCMonitoring = defineTabTool({
|
||||
title: 'Start WebRTC monitoring',
|
||||
description: 'Enable real-time WebRTC connection monitoring. Intercepts RTCPeerConnection API to track connection states and collect statistics. Required before using other WebRTC tools.',
|
||||
inputSchema: z.object({
|
||||
statsPollingInterval: z.number().optional().describe('Stats collection interval in milliseconds (default: 1000ms). Lower values give more frequent updates but use more CPU.'),
|
||||
statsPollingInterval: z.coerce.number().optional().describe('Stats collection interval in milliseconds (default: 1000ms). Lower values give more frequent updates but use more CPU.'),
|
||||
}),
|
||||
type: 'destructive',
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user