Browse Source

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.
Roo Code 1 year ago
parent
commit
2a08c7c3db

+ 14 - 2
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
 	// Get all modes with their overrides from extension state
 	const allModes = await getAllModesWithPrompts(context)
 	const allModes = await getAllModesWithPrompts(context)
 
 
-	return `====
+	// Get enableCustomModeCreation setting from extension state
+	const enableCustomModeCreation = await context.globalState.get<boolean>("enableCustomModeCreation")
+	// Default to true if undefined
+	const shouldEnableCustomModeCreation = enableCustomModeCreation !== undefined ? enableCustomModeCreation : true
+
+	let modesContent = `====
 
 
 MODES
 MODES
 
 
 - These are the currently available 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:
 - Custom modes can be configured in two ways:
   1. Globally via '${customModesPath}' (created automatically on startup)
   1. Globally via '${customModesPath}' (created automatically on startup)
@@ -56,4 +65,7 @@ Both files should follow this structure:
     }
     }
   ]
   ]
 }`
 }`
+	}
+
+	return modesContent
 }
 }

+ 4 - 0
src/core/webview/ClineProvider.ts

@@ -1476,6 +1476,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 						await this.updateGlobalState("enhancementApiConfigId", message.text)
 						await this.updateGlobalState("enhancementApiConfigId", message.text)
 						await this.postStateToWebview()
 						await this.postStateToWebview()
 						break
 						break
+					case "enableCustomModeCreation":
+						await this.updateGlobalState("enableCustomModeCreation", message.bool ?? true)
+						await this.postStateToWebview()
+						break
 					case "autoApprovalEnabled":
 					case "autoApprovalEnabled":
 						await this.updateGlobalState("autoApprovalEnabled", message.bool ?? false)
 						await this.updateGlobalState("autoApprovalEnabled", message.bool ?? false)
 						await this.postStateToWebview()
 						await this.postStateToWebview()

+ 1 - 0
src/shared/ExtensionMessage.ts

@@ -128,6 +128,7 @@ export interface ExtensionState {
 	terminalOutputLimit?: number
 	terminalOutputLimit?: number
 	mcpEnabled: boolean
 	mcpEnabled: boolean
 	enableMcpServerCreation: boolean
 	enableMcpServerCreation: boolean
+	enableCustomModeCreation?: boolean
 	mode: Mode
 	mode: Mode
 	modeApiConfigs?: Record<Mode, string>
 	modeApiConfigs?: Record<Mode, string>
 	enhancementApiConfigId?: string
 	enhancementApiConfigId?: string

+ 1 - 0
src/shared/WebviewMessage.ts

@@ -71,6 +71,7 @@ export interface WebviewMessage {
 		| "terminalOutputLimit"
 		| "terminalOutputLimit"
 		| "mcpEnabled"
 		| "mcpEnabled"
 		| "enableMcpServerCreation"
 		| "enableMcpServerCreation"
+		| "enableCustomModeCreation"
 		| "searchCommits"
 		| "searchCommits"
 		| "alwaysApproveResubmit"
 		| "alwaysApproveResubmit"
 		| "requestDelaySeconds"
 		| "requestDelaySeconds"

+ 1 - 0
src/shared/globalState.ts

@@ -84,6 +84,7 @@ export const GLOBAL_STATE_KEYS = [
 	"enhancementApiConfigId",
 	"enhancementApiConfigId",
 	"experiments", // Map of experiment IDs to their enabled state
 	"experiments", // Map of experiment IDs to their enabled state
 	"autoApprovalEnabled",
 	"autoApprovalEnabled",
+	"enableCustomModeCreation", // Enable the ability to create custom modes
 	"customModes", // Array of custom modes
 	"customModes", // Array of custom modes
 	"unboundModelId",
 	"unboundModelId",
 	"requestyModelId",
 	"requestyModelId",

+ 39 - 1
webview-ui/src/components/prompts/PromptsView.tsx

@@ -71,6 +71,8 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 		preferredLanguage,
 		preferredLanguage,
 		setPreferredLanguage,
 		setPreferredLanguage,
 		customModes,
 		customModes,
+		enableCustomModeCreation,
+		setEnableCustomModeCreation,
 	} = useExtensionState()
 	} = useExtensionState()
 
 
 	// Memoize modes to preserve array order
 	// Memoize modes to preserve array order
@@ -341,6 +343,17 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 		return () => document.removeEventListener("click", handleClickOutside)
 		return () => document.removeEventListener("click", handleClickOutside)
 	}, [showConfigMenu])
 	}, [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(() => {
 	useEffect(() => {
 		const handler = (event: MessageEvent) => {
 		const handler = (event: MessageEvent) => {
 			const message = event.data
 			const message = event.data
@@ -541,8 +554,33 @@ const PromptsView = ({ onDone }: PromptsViewProps) => {
 						in your workspace.
 						in your workspace.
 					</div>
 					</div>
 				</div>
 				</div>
-
 				<div className="mt-5">
 				<div className="mt-5">
+					{/*
+	  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.
+	*/}
+					<div style={{ marginBottom: 15 }}>
+						<VSCodeCheckbox
+							checked={enableCustomModeCreation || false}
+							onChange={(e: any) => {
+								// Just update the local state through React context
+								// The React context will update the global state
+								setEnableCustomModeCreation(e.target.checked)
+							}}>
+							<span style={{ fontWeight: "500" }}>Enable Custom Mode Creation</span>
+						</VSCodeCheckbox>
+						<p
+							style={{
+								fontSize: "12px",
+								marginTop: "5px",
+								color: "var(--vscode-descriptionForeground)",
+							}}>
+							When enabled, Roo can help you create project-level custom modes. You can disable this to
+							reduce Roo's token usage.
+						</p>
+					</div>
 					<div onClick={(e) => e.stopPropagation()} className="flex justify-between items-center mb-3">
 					<div onClick={(e) => e.stopPropagation()} className="flex justify-between items-center mb-3">
 						<h3 className="text-vscode-foreground m-0">Modes</h3>
 						<h3 className="text-vscode-foreground m-0">Modes</h3>
 						<div className="flex gap-2">
 						<div className="flex gap-2">

+ 5 - 0
webview-ui/src/context/ExtensionStateContext.tsx

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