diff --git a/src/context.ts b/src/context.ts index 8b0bc45..b2a2647 100644 --- a/src/context.ts +++ b/src/context.ts @@ -636,4 +636,28 @@ export class Context { this._lastSnapshotFingerprint = undefined; this._lastPageState = undefined; } + + updateSnapshotConfig(updates: { + includeSnapshots?: boolean; + maxSnapshotTokens?: number; + differentialSnapshots?: boolean; + }): void { + // Update configuration at runtime + if (updates.includeSnapshots !== undefined) + (this.config as any).includeSnapshots = updates.includeSnapshots; + + + if (updates.maxSnapshotTokens !== undefined) + (this.config as any).maxSnapshotTokens = updates.maxSnapshotTokens; + + + if (updates.differentialSnapshots !== undefined) { + (this.config as any).differentialSnapshots = updates.differentialSnapshots; + + // Reset differential state when toggling + if (updates.differentialSnapshots) + this.resetDifferentialSnapshot(); + + } + } } diff --git a/src/tools/configure.ts b/src/tools/configure.ts index e741d45..e925f02 100644 --- a/src/tools/configure.ts +++ b/src/tools/configure.ts @@ -74,6 +74,12 @@ const installPopularExtensionSchema = z.object({ version: z.string().optional().describe('Specific version to install (defaults to latest)') }); +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.'), + differentialSnapshots: z.boolean().optional().describe('Enable differential snapshots that show only changes since last snapshot instead of full page snapshots.') +}); + export default [ defineTool({ capability: 'core', @@ -524,6 +530,78 @@ export default [ } }, }), + defineTool({ + capability: 'core', + schema: { + name: 'browser_configure_snapshots', + title: 'Configure snapshot behavior', + description: 'Configure how page snapshots are handled during the session. Control automatic snapshots, size limits, and differential modes. Changes take effect immediately for subsequent tool calls.', + inputSchema: configureSnapshotsSchema, + type: 'destructive', + }, + handle: async (context: Context, params: z.output, response: Response) => { + try { + const changes: string[] = []; + + // Update snapshot configuration + if (params.includeSnapshots !== undefined) + changes.push(`📸 Auto-snapshots: ${params.includeSnapshots ? 'enabled' : 'disabled'}`); + + + if (params.maxSnapshotTokens !== undefined) { + if (params.maxSnapshotTokens === 0) + changes.push(`📏 Snapshot truncation: disabled (unlimited size)`); + else + changes.push(`📏 Max snapshot tokens: ${params.maxSnapshotTokens.toLocaleString()}`); + + } + + if (params.differentialSnapshots !== undefined) { + changes.push(`🔄 Differential snapshots: ${params.differentialSnapshots ? 'enabled' : 'disabled'}`); + + if (params.differentialSnapshots) + changes.push(` ↳ Reset differential state for fresh tracking`); + + } + + // Apply the updated configuration using the context method + context.updateSnapshotConfig(params); + + // Provide user feedback + if (changes.length === 0) { + response.addResult('No snapshot configuration changes specified.\n\n**Current settings:**\n' + + `📸 Auto-snapshots: ${context.config.includeSnapshots ? 'enabled' : 'disabled'}\n` + + `📏 Max snapshot tokens: ${context.config.maxSnapshotTokens === 0 ? 'unlimited' : context.config.maxSnapshotTokens.toLocaleString()}\n` + + `🔄 Differential snapshots: ${context.config.differentialSnapshots ? 'enabled' : 'disabled'}`); + return; + } + + let result = '✅ **Snapshot configuration updated:**\n\n'; + result += changes.map(change => `- ${change}`).join('\n'); + result += '\n\n**💡 Tips:**\n'; + + if (!context.config.includeSnapshots) + result += '- Use `browser_snapshot` tool when you need explicit page snapshots\n'; + + + if (context.config.differentialSnapshots) { + result += '- Differential mode shows only changes between operations\n'; + result += '- First snapshot after enabling will establish baseline\n'; + } + + if (context.config.maxSnapshotTokens > 0 && context.config.maxSnapshotTokens < 5000) + result += '- Consider increasing token limit if snapshots are frequently truncated\n'; + + + result += '\n**Changes take effect immediately for subsequent tool calls.**'; + + response.addResult(result); + + } catch (error) { + throw new Error(`Failed to configure snapshots: ${error}`); + } + }, + }), ]; // Helper functions for extension downloading diff --git a/src/tools/keyboard.ts b/src/tools/keyboard.ts index aab43ef..0d81cfd 100644 --- a/src/tools/keyboard.ts +++ b/src/tools/keyboard.ts @@ -27,7 +27,7 @@ const pressKey = defineTabTool({ schema: { name: 'browser_press_key', title: 'Press a key', - description: 'Press a key on the keyboard. Returns page snapshot after keypress unless disabled with --no-snapshots.', + description: 'Press a key on the keyboard. Returns page snapshot after keypress (configurable via browser_configure_snapshots).', inputSchema: z.object({ key: z.string().describe('Name of the key to press or a character to generate, such as `ArrowLeft` or `a`'), }), @@ -56,7 +56,7 @@ const type = defineTabTool({ schema: { name: 'browser_type', title: 'Type text', - description: 'Type text into editable element. Returns page snapshot after typing unless disabled with --no-snapshots.', + description: 'Type text into editable element. Returns page snapshot after typing (configurable via browser_configure_snapshots).', inputSchema: typeSchema, type: 'destructive', }, diff --git a/src/tools/navigate.ts b/src/tools/navigate.ts index 6b39f2c..31c8a97 100644 --- a/src/tools/navigate.ts +++ b/src/tools/navigate.ts @@ -23,7 +23,7 @@ const navigate = defineTool({ schema: { name: 'browser_navigate', title: 'Navigate to a URL', - description: 'Navigate to a URL. Returns page snapshot after navigation unless disabled with --no-snapshots.', + description: 'Navigate to a URL. Returns page snapshot after navigation (configurable via browser_configure_snapshots).', inputSchema: z.object({ url: z.string().describe('The URL to navigate to'), }), diff --git a/src/tools/snapshot.ts b/src/tools/snapshot.ts index e6366cb..ee8cac5 100644 --- a/src/tools/snapshot.ts +++ b/src/tools/snapshot.ts @@ -25,7 +25,7 @@ const snapshot = defineTool({ schema: { name: 'browser_snapshot', title: 'Page snapshot', - description: 'Capture complete accessibility snapshot of the current page. Always returns full snapshot regardless of --no-snapshots or size limits. Better than screenshot for understanding page structure.', + description: 'Capture complete accessibility snapshot of the current page. Always returns full snapshot regardless of session snapshot configuration. Better than screenshot for understanding page structure.', inputSchema: z.object({}), type: 'readOnly', }, @@ -51,7 +51,7 @@ const click = defineTabTool({ schema: { name: 'browser_click', title: 'Click', - description: 'Perform click on a web page. Returns page snapshot after click unless disabled with --no-snapshots. Large snapshots (>10k tokens) are truncated - use browser_snapshot for full capture.', + description: 'Perform click on a web page. Returns page snapshot after click (configurable via browser_configure_snapshots). Use browser_snapshot for explicit full snapshots.', inputSchema: clickSchema, type: 'destructive', }, @@ -85,7 +85,7 @@ const drag = defineTabTool({ schema: { name: 'browser_drag', title: 'Drag mouse', - description: 'Perform drag and drop between two elements. Returns page snapshot after drag unless disabled with --no-snapshots.', + description: 'Perform drag and drop between two elements. Returns page snapshot after drag (configurable via browser_configure_snapshots).', inputSchema: z.object({ startElement: z.string().describe('Human-readable source element description used to obtain the permission to interact with the element'), startRef: z.string().describe('Exact source element reference from the page snapshot'), @@ -116,7 +116,7 @@ const hover = defineTabTool({ schema: { name: 'browser_hover', title: 'Hover mouse', - description: 'Hover over element on page. Returns page snapshot after hover unless disabled with --no-snapshots.', + description: 'Hover over element on page. Returns page snapshot after hover (configurable via browser_configure_snapshots).', inputSchema: elementSchema, type: 'readOnly', }, @@ -142,7 +142,7 @@ const selectOption = defineTabTool({ schema: { name: 'browser_select_option', title: 'Select option', - description: 'Select an option in a dropdown. Returns page snapshot after selection unless disabled with --no-snapshots.', + description: 'Select an option in a dropdown. Returns page snapshot after selection (configurable via browser_configure_snapshots).', inputSchema: selectOptionSchema, type: 'destructive', },