Skip to content

Commit bf77f46

Browse files
authored
Merge pull request #1331 from RooVetGit/browser_tool_enabled
Add a checkbox to enable/disable the browser tool
2 parents 82b6fe6 + 6b0347e commit bf77f46

File tree

9 files changed

+113
-49
lines changed

9 files changed

+113
-49
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Add a checkbox to disable the browser tool

src/core/Cline.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ export class Cline {
946946
preferredLanguage,
947947
experiments,
948948
enableMcpServerCreation,
949+
browserToolEnabled,
949950
} = (await this.providerRef.deref()?.getState()) ?? {}
950951
const { customModes } = (await this.providerRef.deref()?.getState()) ?? {}
951952
const systemPrompt = await (async () => {
@@ -956,7 +957,7 @@ export class Cline {
956957
return SYSTEM_PROMPT(
957958
provider.context,
958959
cwd,
959-
this.api.getModel().info.supportsComputerUse ?? false,
960+
(this.api.getModel().info.supportsComputerUse ?? false) && (browserToolEnabled ?? true),
960961
mcpHub,
961962
this.diffStrategy,
962963
browserViewportSize,

src/core/webview/ClineProvider.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
12241224
await this.updateGlobalState("maxOpenTabsContext", tabCount)
12251225
await this.postStateToWebview()
12261226
break
1227+
case "browserToolEnabled":
1228+
await this.updateGlobalState("browserToolEnabled", message.bool ?? true)
1229+
await this.postStateToWebview()
1230+
break
12271231
case "enhancementApiConfigId":
12281232
await this.updateGlobalState("enhancementApiConfigId", message.text)
12291233
await this.postStateToWebview()
@@ -2022,6 +2026,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
20222026
autoApprovalEnabled,
20232027
experiments,
20242028
maxOpenTabsContext,
2029+
browserToolEnabled,
20252030
} = await this.getState()
20262031

20272032
const allowedCommands = vscode.workspace.getConfiguration("roo-cline").get<string[]>("allowedCommands") || []
@@ -2075,6 +2080,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
20752080
mcpServers: this.mcpHub?.getAllServers() ?? [],
20762081
maxOpenTabsContext: maxOpenTabsContext ?? 20,
20772082
cwd: cwd,
2083+
browserToolEnabled: browserToolEnabled ?? true,
20782084
}
20792085
}
20802086

@@ -2214,6 +2220,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
22142220
modelMaxTokens,
22152221
modelMaxThinkingTokens,
22162222
maxOpenTabsContext,
2223+
browserToolEnabled,
22172224
] = await Promise.all([
22182225
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
22192226
this.getGlobalState("apiModelId") as Promise<string | undefined>,
@@ -2298,6 +2305,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
22982305
this.getGlobalState("modelMaxTokens") as Promise<number | undefined>,
22992306
this.getGlobalState("anthropicThinking") as Promise<number | undefined>,
23002307
this.getGlobalState("maxOpenTabsContext") as Promise<number | undefined>,
2308+
this.getGlobalState("browserToolEnabled") as Promise<boolean | undefined>,
23012309
])
23022310

23032311
let apiProvider: ApiProvider
@@ -2431,6 +2439,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
24312439
customModes,
24322440
maxOpenTabsContext: maxOpenTabsContext ?? 20,
24332441
openRouterUseMiddleOutTransform: openRouterUseMiddleOutTransform ?? true,
2442+
browserToolEnabled: browserToolEnabled ?? true,
24342443
}
24352444
}
24362445

src/core/webview/__tests__/ClineProvider.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ describe("ClineProvider", () => {
381381
customModes: [],
382382
experiments: experimentDefault,
383383
maxOpenTabsContext: 20,
384+
browserToolEnabled: true,
384385
}
385386

386387
const message: ExtensionMessage = {
@@ -591,6 +592,21 @@ describe("ClineProvider", () => {
591592
expect(provider.configManager.setModeConfig).toHaveBeenCalledWith("architect", "new-id")
592593
})
593594

595+
test("handles browserToolEnabled setting", async () => {
596+
await provider.resolveWebviewView(mockWebviewView)
597+
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]
598+
599+
// Test browserToolEnabled
600+
await messageHandler({ type: "browserToolEnabled", bool: true })
601+
expect(mockContext.globalState.update).toHaveBeenCalledWith("browserToolEnabled", true)
602+
expect(mockPostMessage).toHaveBeenCalled()
603+
604+
// Verify state includes browserToolEnabled
605+
const state = await provider.getState()
606+
expect(state).toHaveProperty("browserToolEnabled")
607+
expect(state.browserToolEnabled).toBe(true) // Default value should be true
608+
})
609+
594610
test("handles request delay settings messages", async () => {
595611
await provider.resolveWebviewView(mockWebviewView)
596612
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as jest.Mock).mock.calls[0][0]

src/shared/ExtensionMessage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export interface ExtensionMessage {
4545
| "updateCustomMode"
4646
| "deleteCustomMode"
4747
| "currentCheckpointUpdated"
48+
| "browserToolEnabled"
4849
text?: string
4950
action?:
5051
| "chatButtonClicked"
@@ -103,6 +104,7 @@ export interface ExtensionState {
103104
alwaysAllowMcp?: boolean
104105
alwaysApproveResubmit?: boolean
105106
alwaysAllowModeSwitch?: boolean
107+
browserToolEnabled?: boolean
106108
requestDelaySeconds: number
107109
rateLimitSeconds: number // Minimum time between successive requests (0 = disabled)
108110
uriScheme?: string

src/shared/WebviewMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export interface WebviewMessage {
9494
| "checkpointRestore"
9595
| "deleteMcpServer"
9696
| "maxOpenTabsContext"
97+
| "browserToolEnabled"
9798
text?: string
9899
disabled?: boolean
99100
askResponse?: ClineAskResponse

src/shared/globalState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,4 @@ export type GlobalStateKey =
8484
| "anthropicThinking" // TODO: Rename to `modelMaxThinkingTokens`.
8585
| "mistralCodestralUrl"
8686
| "maxOpenTabsContext"
87+
| "browserToolEnabled" // Setting to enable/disable the browser tool

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
5151
alwaysAllowModeSwitch,
5252
alwaysAllowWrite,
5353
alwaysApproveResubmit,
54+
browserToolEnabled,
5455
browserViewportSize,
5556
enableCheckpoints,
5657
diffEnabled,
@@ -140,6 +141,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
140141
vscode.postMessage({ type: "alwaysAllowBrowser", bool: alwaysAllowBrowser })
141142
vscode.postMessage({ type: "alwaysAllowMcp", bool: alwaysAllowMcp })
142143
vscode.postMessage({ type: "allowedCommands", commands: allowedCommands ?? [] })
144+
vscode.postMessage({ type: "browserToolEnabled", bool: browserToolEnabled })
143145
vscode.postMessage({ type: "soundEnabled", bool: soundEnabled })
144146
vscode.postMessage({ type: "soundVolume", value: soundVolume })
145147
vscode.postMessage({ type: "diffEnabled", bool: diffEnabled })
@@ -537,59 +539,83 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
537539
<div style={{ marginBottom: 40 }}>
538540
<h3 style={{ color: "var(--vscode-foreground)", margin: "0 0 15px 0" }}>Browser Settings</h3>
539541
<div style={{ marginBottom: 15 }}>
540-
<label style={{ fontWeight: "500", display: "block", marginBottom: 5 }}>Viewport size</label>
541-
<div className="dropdown-container">
542-
<Dropdown
543-
value={browserViewportSize}
544-
onChange={(value: unknown) => {
545-
setCachedStateField("browserViewportSize", (value as DropdownOption).value)
546-
}}
547-
style={{ width: "100%" }}
548-
options={[
549-
{ value: "1280x800", label: "Large Desktop (1280x800)" },
550-
{ value: "900x600", label: "Small Desktop (900x600)" },
551-
{ value: "768x1024", label: "Tablet (768x1024)" },
552-
{ value: "360x640", label: "Mobile (360x640)" },
553-
]}
554-
/>
555-
</div>
556-
<p
557-
style={{
558-
fontSize: "12px",
559-
marginTop: "5px",
560-
color: "var(--vscode-descriptionForeground)",
561-
}}>
562-
Select the viewport size for browser interactions. This affects how websites are displayed
563-
and interacted with.
542+
<VSCodeCheckbox
543+
checked={browserToolEnabled}
544+
onChange={(e: any) => setCachedStateField("browserToolEnabled", e.target.checked)}>
545+
<span style={{ fontWeight: "500" }}>Enable browser tool</span>
546+
</VSCodeCheckbox>
547+
<p style={{ fontSize: "12px", marginTop: "5px", color: "var(--vscode-descriptionForeground)" }}>
548+
When enabled, Roo can use a browser to interact with websites when using models that support
549+
computer use.
564550
</p>
565551
</div>
552+
{browserToolEnabled && (
553+
<div
554+
style={{
555+
marginLeft: 0,
556+
paddingLeft: 10,
557+
borderLeft: "2px solid var(--vscode-button-background)",
558+
}}>
559+
<div style={{ marginBottom: 15 }}>
560+
<label style={{ fontWeight: "500", display: "block", marginBottom: 5 }}>
561+
Viewport size
562+
</label>
563+
<div className="dropdown-container">
564+
<Dropdown
565+
value={browserViewportSize}
566+
onChange={(value: unknown) => {
567+
setCachedStateField("browserViewportSize", (value as DropdownOption).value)
568+
}}
569+
style={{ width: "100%" }}
570+
options={[
571+
{ value: "1280x800", label: "Large Desktop (1280x800)" },
572+
{ value: "900x600", label: "Small Desktop (900x600)" },
573+
{ value: "768x1024", label: "Tablet (768x1024)" },
574+
{ value: "360x640", label: "Mobile (360x640)" },
575+
]}
576+
/>
577+
</div>
578+
<p
579+
style={{
580+
fontSize: "12px",
581+
marginTop: "5px",
582+
color: "var(--vscode-descriptionForeground)",
583+
}}>
584+
Select the viewport size for browser interactions. This affects how websites are
585+
displayed and interacted with.
586+
</p>
587+
</div>
566588

567-
<div style={{ marginBottom: 15 }}>
568-
<div style={{ display: "flex", flexDirection: "column", gap: "5px" }}>
569-
<span style={{ fontWeight: "500" }}>Screenshot quality</span>
570-
<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
571-
<input
572-
type="range"
573-
min="1"
574-
max="100"
575-
step="1"
576-
value={screenshotQuality ?? 75}
577-
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
578-
onChange={(e) => setCachedStateField("screenshotQuality", parseInt(e.target.value))}
579-
/>
580-
<span style={{ ...sliderLabelStyle }}>{screenshotQuality ?? 75}%</span>
589+
<div style={{ marginBottom: 15 }}>
590+
<div style={{ display: "flex", flexDirection: "column", gap: "5px" }}>
591+
<span style={{ fontWeight: "500" }}>Screenshot quality</span>
592+
<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
593+
<input
594+
type="range"
595+
min="1"
596+
max="100"
597+
step="1"
598+
value={screenshotQuality ?? 75}
599+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
600+
onChange={(e) =>
601+
setCachedStateField("screenshotQuality", parseInt(e.target.value))
602+
}
603+
/>
604+
<span style={{ ...sliderLabelStyle }}>{screenshotQuality ?? 75}%</span>
605+
</div>
606+
</div>
607+
<p
608+
style={{
609+
fontSize: "12px",
610+
marginTop: "5px",
611+
color: "var(--vscode-descriptionForeground)",
612+
}}>
613+
Adjust the WebP quality of browser screenshots. Higher values provide clearer
614+
screenshots but increase token usage.
615+
</p>
581616
</div>
582617
</div>
583-
<p
584-
style={{
585-
fontSize: "12px",
586-
marginTop: "5px",
587-
color: "var(--vscode-descriptionForeground)",
588-
}}>
589-
Adjust the WebP quality of browser screenshots. Higher values provide clearer screenshots
590-
but increase token usage.
591-
</p>
592-
</div>
618+
)}
593619
</div>
594620

595621
<div style={{ marginBottom: 40 }}>

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface ExtensionStateContextType extends ExtensionState {
2727
setAlwaysAllowBrowser: (value: boolean) => void
2828
setAlwaysAllowMcp: (value: boolean) => void
2929
setAlwaysAllowModeSwitch: (value: boolean) => void
30+
setBrowserToolEnabled: (value: boolean) => void
3031
setShowAnnouncement: (value: boolean) => void
3132
setAllowedCommands: (value: string[]) => void
3233
setSoundEnabled: (value: boolean) => void
@@ -128,6 +129,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
128129
customModes: [],
129130
maxOpenTabsContext: 20,
130131
cwd: "",
132+
browserToolEnabled: true,
131133
})
132134

133135
const [didHydrateState, setDidHydrateState] = useState(false)
@@ -265,6 +267,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
265267
setAutoApprovalEnabled: (value) => setState((prevState) => ({ ...prevState, autoApprovalEnabled: value })),
266268
setCustomModes: (value) => setState((prevState) => ({ ...prevState, customModes: value })),
267269
setMaxOpenTabsContext: (value) => setState((prevState) => ({ ...prevState, maxOpenTabsContext: value })),
270+
setBrowserToolEnabled: (value) => setState((prevState) => ({ ...prevState, browserToolEnabled: value })),
268271
}
269272

270273
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>

0 commit comments

Comments
 (0)