From 0e1c968fba8129b21598ed10676b32faa3368a78 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Fri, 25 Jul 2025 09:26:13 +0000 Subject: [PATCH] feat: make enhance prompt button optional through experimental setting - Add SHOW_ENHANCE_PROMPT_BUTTON experiment ID - Update ChatTextArea to conditionally render button based on experiment - Add translation keys for the new experimental setting - Update tests to handle the new experiment configuration - Default the setting to enabled to maintain current behavior Fixes #6207 --- packages/types/src/experiment.ts | 3 +- src/shared/experiments.ts | 2 + .../src/components/chat/ChatTextArea.tsx | 50 ++++++----- .../chat/__tests__/ChatTextArea.spec.tsx | 84 +++++++++++++++++++ .../settings/ExperimentalSettings.tsx | 29 ++----- webview-ui/src/i18n/locales/en/settings.json | 4 + 6 files changed, 127 insertions(+), 45 deletions(-) diff --git a/packages/types/src/experiment.ts b/packages/types/src/experiment.ts index 10384db8ed..7eec19ea6a 100644 --- a/packages/types/src/experiment.ts +++ b/packages/types/src/experiment.ts @@ -6,7 +6,7 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js" * ExperimentId */ -export const experimentIds = ["powerSteering", "multiFileApplyDiff"] as const +export const experimentIds = ["powerSteering", "multiFileApplyDiff", "showEnhancePromptButton"] as const export const experimentIdsSchema = z.enum(experimentIds) @@ -19,6 +19,7 @@ export type ExperimentId = z.infer export const experimentsSchema = z.object({ powerSteering: z.boolean().optional(), multiFileApplyDiff: z.boolean().optional(), + showEnhancePromptButton: z.boolean().optional(), }) export type Experiments = z.infer diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index 1edadf654f..4e9196311c 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -3,6 +3,7 @@ import type { AssertEqual, Equals, Keys, Values, ExperimentId, Experiments } fro export const EXPERIMENT_IDS = { MULTI_FILE_APPLY_DIFF: "multiFileApplyDiff", POWER_STEERING: "powerSteering", + SHOW_ENHANCE_PROMPT_BUTTON: "showEnhancePromptButton", } as const satisfies Record type _AssertExperimentIds = AssertEqual>> @@ -16,6 +17,7 @@ interface ExperimentConfig { export const experimentConfigsMap: Record = { MULTI_FILE_APPLY_DIFF: { enabled: false }, POWER_STEERING: { enabled: false }, + SHOW_ENHANCE_PROMPT_BUTTON: { enabled: true }, } export const experimentDefault = Object.fromEntries( diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 6c541353eb..69f3b95369 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -10,6 +10,7 @@ import { ExtensionMessage } from "@roo/ExtensionMessage" import { vscode } from "@/utils/vscode" import { useExtensionState } from "@/context/ExtensionStateContext" import { useAppTranslation } from "@/i18n/TranslationContext" +import { EXPERIMENT_IDS, experiments } from "@roo/experiments" import { ContextMenuOptionType, getContextMenuOptions, @@ -86,6 +87,7 @@ const ChatTextArea = forwardRef( togglePinnedApiConfig, taskHistory, clineMessages, + experiments: experimentsConfig, } = useExtensionState() // Find the ID and display text for the currently selected API configuration @@ -1109,29 +1111,31 @@ const ChatTextArea = forwardRef( onScroll={() => updateHighlights()} /> -
- - - -
+ {experiments.isEnabled(experimentsConfig, EXPERIMENT_IDS.SHOW_ENHANCE_PROMPT_BUTTON) && ( +
+ + + +
+ )} {!isEditMode && (
diff --git a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx index f53bab76a4..60576cc16f 100644 --- a/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/ChatTextArea.spec.tsx @@ -73,6 +73,9 @@ describe("ChatTextArea", () => { }, taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) }) @@ -83,11 +86,50 @@ describe("ChatTextArea", () => { openedTabs: [], taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) render() const enhanceButton = getEnhancePromptButton() expect(enhanceButton).toHaveClass("cursor-not-allowed") }) + + it("should not be visible when experiment is disabled", () => { + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + taskHistory: [], + cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: false, + }, + }) + render() + + // The button should not exist in the DOM + const enhanceButton = screen.queryByRole("button", { + name: (_, element) => { + return element.querySelector(".lucide-wand-sparkles") !== null + }, + }) + expect(enhanceButton).not.toBeInTheDocument() + }) + + it("should be visible when experiment is enabled", () => { + ;(useExtensionState as ReturnType).mockReturnValue({ + filePaths: [], + openedTabs: [], + taskHistory: [], + cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, + }) + render() + const enhanceButton = getEnhancePromptButton() + expect(enhanceButton).toBeInTheDocument() + }) }) describe("handleEnhancePrompt", () => { @@ -103,6 +145,9 @@ describe("ChatTextArea", () => { apiConfiguration, taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) render() @@ -125,6 +170,9 @@ describe("ChatTextArea", () => { }, taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) render() @@ -147,6 +195,9 @@ describe("ChatTextArea", () => { }, taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) render() @@ -174,6 +225,9 @@ describe("ChatTextArea", () => { }, taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) rerender() @@ -275,6 +329,9 @@ describe("ChatTextArea", () => { filePaths: [], openedTabs: [], cwd: mockCwd, + experiments: { + showEnhancePromptButton: true, + }, }) mockConvertToMentionPath.mockClear() }) @@ -506,6 +563,9 @@ describe("ChatTextArea", () => { taskHistory: [], clineMessages: mockClineMessages, cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) }) @@ -659,6 +719,9 @@ describe("ChatTextArea", () => { taskHistory: [], clineMessages: mixedClineMessages, cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) const setInputValue = vi.fn() @@ -687,6 +750,9 @@ describe("ChatTextArea", () => { taskHistory: [], clineMessages: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) const setInputValue = vi.fn() @@ -718,6 +784,9 @@ describe("ChatTextArea", () => { taskHistory: [], clineMessages: clineMessagesWithEmpty, cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) const setInputValue = vi.fn() @@ -752,6 +821,9 @@ describe("ChatTextArea", () => { taskHistory: mockTaskHistory, clineMessages: [], // No conversation messages cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) const setInputValue = vi.fn() @@ -789,6 +861,9 @@ describe("ChatTextArea", () => { ], clineMessages: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) rerender() @@ -812,6 +887,9 @@ describe("ChatTextArea", () => { { type: "say", say: "user_feedback", text: "Message 2", ts: 2000 }, ], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) setInputValue.mockClear() @@ -929,6 +1007,9 @@ describe("ChatTextArea", () => { cwd: "/test/workspace", customModes: [], customModePrompts: {}, + experiments: { + showEnhancePromptButton: true, + }, }) render() @@ -953,6 +1034,9 @@ describe("ChatTextArea", () => { openedTabs: [], taskHistory: [], cwd: "/test/workspace", + experiments: { + showEnhancePromptButton: true, + }, }) render() diff --git a/webview-ui/src/components/settings/ExperimentalSettings.tsx b/webview-ui/src/components/settings/ExperimentalSettings.tsx index 53801232ec..262e9568d3 100644 --- a/webview-ui/src/components/settings/ExperimentalSettings.tsx +++ b/webview-ui/src/components/settings/ExperimentalSettings.tsx @@ -39,29 +39,16 @@ export const ExperimentalSettings = ({ {Object.entries(experimentConfigsMap) .filter(([key]) => key in EXPERIMENT_IDS) .map((config) => { - if (config[0] === "MULTI_FILE_APPLY_DIFF") { - return ( - - setExperimentEnabled(EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF, enabled) - } - /> - ) - } + const experimentKey = config[0] as keyof typeof EXPERIMENT_IDS + const experimentId = EXPERIMENT_IDS[experimentKey] + const defaultEnabled = experimentConfigsMap[experimentKey].enabled + return ( - setExperimentEnabled( - EXPERIMENT_IDS[config[0] as keyof typeof EXPERIMENT_IDS], - enabled, - ) - } + key={experimentKey} + experimentKey={experimentKey} + enabled={experiments[experimentId] ?? defaultEnabled} + onChange={(enabled) => setExperimentEnabled(experimentId, enabled)} /> ) })} diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index cfd5b04286..745de6a43b 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -648,6 +648,10 @@ "MULTI_FILE_APPLY_DIFF": { "name": "Enable concurrent file edits", "description": "When enabled, Roo can edit multiple files in a single request. When disabled, Roo must edit files one at a time. Disabling this can help when working with less capable models or when you want more control over file modifications." + }, + "SHOW_ENHANCE_PROMPT_BUTTON": { + "name": "Show enhance prompt button", + "description": "When enabled, displays the enhance prompt button in the chat input area. This button allows you to improve your prompts using AI assistance." } }, "promptCaching": {