From 2a08c7c3dbbcaac5fc8b005109a0929a1ed8e9ef Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sat, 8 Mar 2025 22:05:27 -0700 Subject: [PATCH] feat: Add toggle for custom mode creation This commit adds a new setting to allow users to disable custom mode creation, which can help reduce token usage in Roo's prompts. Key changes: Add enableCustomModeCreation setting to global state Conditionally include custom modes documentation in prompt only when enabled Add UI toggle in PromptsView with explanatory text Default the setting to enabled (true) for backward compatibility Update necessary interfaces and message handlers for the new setting The setting is placed in PromptsView rather than SettingsView since it directly relates to the modes functionality managed in that component. --- src/core/prompts/sections/modes.ts | 16 +++++++- src/core/webview/ClineProvider.ts | 4 ++ src/shared/ExtensionMessage.ts | 1 + src/shared/WebviewMessage.ts | 1 + src/shared/globalState.ts | 1 + .../src/components/prompts/PromptsView.tsx | 40 ++++++++++++++++++- .../src/context/ExtensionStateContext.tsx | 5 +++ 7 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/core/prompts/sections/modes.ts b/src/core/prompts/sections/modes.ts index f3863870db..d561e47a84 100644 --- a/src/core/prompts/sections/modes.ts +++ b/src/core/prompts/sections/modes.ts @@ -11,12 +11,21 @@ export async function getModesSection(context: vscode.ExtensionContext): Promise // Get all modes with their overrides from extension state const allModes = await getAllModesWithPrompts(context) - return `==== + // Get enableCustomModeCreation setting from extension state + const enableCustomModeCreation = await context.globalState.get("enableCustomModeCreation") + // Default to true if undefined + const shouldEnableCustomModeCreation = enableCustomModeCreation !== undefined ? enableCustomModeCreation : true + + let modesContent = `==== MODES - These are the currently available modes: -${allModes.map((mode: ModeConfig) => ` * "${mode.name}" mode (${mode.slug}) - ${mode.roleDefinition.split(".")[0]}`).join("\n")} +${allModes.map((mode: ModeConfig) => ` * "${mode.name}" mode (${mode.slug}) - ${mode.roleDefinition.split(".")[0]}`).join("\n")}` + + // Only include custom modes documentation if the feature is enabled + if (shouldEnableCustomModeCreation) { + modesContent += ` - Custom modes can be configured in two ways: 1. Globally via '${customModesPath}' (created automatically on startup) @@ -56,4 +65,7 @@ Both files should follow this structure: } ] }` + } + + return modesContent } diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index e1d67b5a28..75689e2450 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1476,6 +1476,10 @@ export class ClineProvider implements vscode.WebviewViewProvider { await this.updateGlobalState("enhancementApiConfigId", message.text) await this.postStateToWebview() break + case "enableCustomModeCreation": + await this.updateGlobalState("enableCustomModeCreation", message.bool ?? true) + await this.postStateToWebview() + break case "autoApprovalEnabled": await this.updateGlobalState("autoApprovalEnabled", message.bool ?? false) await this.postStateToWebview() diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index 98ff9b36e1..78c60acc97 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -128,6 +128,7 @@ export interface ExtensionState { terminalOutputLimit?: number mcpEnabled: boolean enableMcpServerCreation: boolean + enableCustomModeCreation?: boolean mode: Mode modeApiConfigs?: Record enhancementApiConfigId?: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 10af6f7a94..37328cd95a 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -71,6 +71,7 @@ export interface WebviewMessage { | "terminalOutputLimit" | "mcpEnabled" | "enableMcpServerCreation" + | "enableCustomModeCreation" | "searchCommits" | "alwaysApproveResubmit" | "requestDelaySeconds" diff --git a/src/shared/globalState.ts b/src/shared/globalState.ts index bfd24f4298..579bf1df86 100644 --- a/src/shared/globalState.ts +++ b/src/shared/globalState.ts @@ -84,6 +84,7 @@ export const GLOBAL_STATE_KEYS = [ "enhancementApiConfigId", "experiments", // Map of experiment IDs to their enabled state "autoApprovalEnabled", + "enableCustomModeCreation", // Enable the ability to create custom modes "customModes", // Array of custom modes "unboundModelId", "requestyModelId", diff --git a/webview-ui/src/components/prompts/PromptsView.tsx b/webview-ui/src/components/prompts/PromptsView.tsx index ccf1e6d700..e14ce8f939 100644 --- a/webview-ui/src/components/prompts/PromptsView.tsx +++ b/webview-ui/src/components/prompts/PromptsView.tsx @@ -71,6 +71,8 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { preferredLanguage, setPreferredLanguage, customModes, + enableCustomModeCreation, + setEnableCustomModeCreation, } = useExtensionState() // Memoize modes to preserve array order @@ -341,6 +343,17 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { return () => document.removeEventListener("click", handleClickOutside) }, [showConfigMenu]) + // Add effect to sync enableCustomModeCreation with backend + useEffect(() => { + if (enableCustomModeCreation !== undefined) { + // Send the value to the extension's global state + vscode.postMessage({ + type: "enableCustomModeCreation", // Using dedicated message type + bool: enableCustomModeCreation, + }) + } + }, [enableCustomModeCreation]) + useEffect(() => { const handler = (event: MessageEvent) => { const message = event.data @@ -541,8 +554,33 @@ const PromptsView = ({ onDone }: PromptsViewProps) => { in your workspace. -
+ {/* + NOTE: This setting is placed in PromptsView rather than SettingsView since it + directly affects the functionality related to modes and custom mode creation, + which are managed in this component. This is an intentional deviation from + the standard pattern described in cline_docs/settings.md. + */} +
+ { + // Just update the local state through React context + // The React context will update the global state + setEnableCustomModeCreation(e.target.checked) + }}> + Enable Custom Mode Creation + +

+ When enabled, Roo can help you create project-level custom modes. You can disable this to + reduce Roo's token usage. +

+
e.stopPropagation()} className="flex justify-between items-center mb-3">

Modes

diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index c4daf426ca..3ed42b8586 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -52,6 +52,8 @@ export interface ExtensionStateContextType extends ExtensionState { setMcpEnabled: (value: boolean) => void enableMcpServerCreation: boolean setEnableMcpServerCreation: (value: boolean) => void + enableCustomModeCreation?: boolean + setEnableCustomModeCreation: (value: boolean) => void alwaysApproveResubmit?: boolean setAlwaysApproveResubmit: (value: boolean) => void requestDelaySeconds: number @@ -117,6 +119,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode checkpointStorage: "task", fuzzyMatchThreshold: 1.0, preferredLanguage: "English", + enableCustomModeCreation: true, writeDelayMs: 1000, browserViewportSize: "900x600", screenshotQuality: 75, @@ -273,6 +276,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setCustomSupportPrompts: (value) => setState((prevState) => ({ ...prevState, customSupportPrompts: value })), setEnhancementApiConfigId: (value) => setState((prevState) => ({ ...prevState, enhancementApiConfigId: value })), + setEnableCustomModeCreation: (value) => + setState((prevState) => ({ ...prevState, enableCustomModeCreation: value })), setAutoApprovalEnabled: (value) => setState((prevState) => ({ ...prevState, autoApprovalEnabled: value })), setCustomModes: (value) => setState((prevState) => ({ ...prevState, customModes: value })), setMaxOpenTabsContext: (value) => setState((prevState) => ({ ...prevState, maxOpenTabsContext: value })),