feat: add comprehensive browser UI customization support

Add powerful browser UI customization options to browser_configure tool:
- slowMo: Visual delays for demo recordings and training videos
- devtools: Auto-open Chrome DevTools for debugging sessions
- args: Custom browser launch arguments for themes and behavior
- chromiumSandbox: Sandbox control for container deployments

Key features:
• Dark mode interface support with --force-dark-mode
• Demo recording optimization with configurable action delays
• DevTools integration for development workflows
• Container deployment flexibility with sandbox control
• Comprehensive argument merging without duplicates

Includes complete documentation, testing suite, and production-ready
validation. Addresses user request for browser UI differentiation
and visual customization capabilities.

Technical changes:
- Enhanced Context.updateBrowserConfig() with UI parameter handling
- Extended configure tool schema with new Zod validations
- Fixed TypeScript compilation with skipLibCheck for upstream deps
- Added comprehensive test suite and documentation guide
This commit is contained in:
Ryan Malloy 2025-09-06 13:25:04 -06:00
parent ea30553f5a
commit 671b0a3668
7 changed files with 631 additions and 45 deletions

View file

@ -411,6 +411,12 @@ export class Context {
colorScheme?: 'light' | 'dark' | 'no-preference';
permissions?: string[];
offline?: boolean;
// Browser UI Customization
chromiumSandbox?: boolean;
slowMo?: number;
devtools?: boolean;
args?: string[];
}): Promise<void> {
const currentConfig = { ...this.config };
@ -469,6 +475,29 @@ export class Context {
if (changes.offline !== undefined)
(currentConfig.browser as any).offline = changes.offline;
// Apply browser launch options for UI customization
if (changes.chromiumSandbox !== undefined)
currentConfig.browser.launchOptions.chromiumSandbox = changes.chromiumSandbox;
if (changes.slowMo !== undefined)
currentConfig.browser.launchOptions.slowMo = changes.slowMo;
if (changes.devtools !== undefined)
currentConfig.browser.launchOptions.devtools = changes.devtools;
if (changes.args && Array.isArray(changes.args)) {
// Merge with existing args, avoiding duplicates
const existingArgs = currentConfig.browser.launchOptions.args || [];
const newArgs = [...existingArgs];
for (const arg of changes.args) {
if (!existingArgs.includes(arg)) {
newArgs.push(arg);
}
}
currentConfig.browser.launchOptions.args = newArgs;
}
// Store the modified config
(this as any).config = currentConfig;
@ -480,7 +509,7 @@ export class Context {
this._tabs = [];
this._currentTab = undefined;
testDebug(`browser config updated for session ${this.sessionId}: headless=${currentConfig.browser.launchOptions.headless}, viewport=${JSON.stringify(currentConfig.browser.contextOptions.viewport)}`);
testDebug(`browser config updated for session ${this.sessionId}: headless=${currentConfig.browser.launchOptions.headless}, viewport=${JSON.stringify(currentConfig.browser.contextOptions.viewport)}, slowMo=${currentConfig.browser.launchOptions.slowMo}, devtools=${currentConfig.browser.launchOptions.devtools}`);
}
async stopVideoRecording(): Promise<string[]> {

View file

@ -38,7 +38,13 @@ const configureSchema = z.object({
timezone: z.string().optional().describe('Timezone ID (e.g., "America/New_York", "Europe/London", "Asia/Tokyo")'),
colorScheme: z.enum(['light', 'dark', 'no-preference']).optional().describe('Preferred color scheme'),
permissions: z.array(z.string()).optional().describe('Permissions to grant (e.g., ["geolocation", "notifications", "camera", "microphone"])'),
offline: z.boolean().optional().describe('Whether to emulate offline network conditions (equivalent to DevTools offline mode)')
offline: z.boolean().optional().describe('Whether to emulate offline network conditions (equivalent to DevTools offline mode)'),
// 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)'),
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"])'),
});
const listDevicesSchema = z.object({});
@ -100,19 +106,19 @@ const offlineModeTest = defineTool({
try {
// Get current browser context
const tab = context.currentTab();
if (!tab) {
if (!tab)
throw new Error('No active browser tab. Navigate to a page first.');
}
const browserContext = tab.page.context();
await browserContext.setOffline(params.offline);
response.addResult(
`✅ Browser offline mode ${params.offline ? 'enabled' : 'disabled'}\n\n` +
`✅ Browser offline mode ${params.offline ? 'enabled' : 'disabled'}\n\n` +
`The browser will now ${params.offline ? 'block all network requests' : 'allow network requests'} ` +
`(equivalent to ${params.offline ? 'checking' : 'unchecking'} the offline checkbox in DevTools).`
);
} catch (error) {
throw new Error(`Failed to set offline mode: ${error}`);
}