From 5ef7c1ea7d3544486e66311bb2723988089d53f4 Mon Sep 17 00:00:00 2001 From: Will Li Date: Mon, 30 Jun 2025 14:44:07 -0700 Subject: [PATCH 1/7] UI working --- packages/types/src/global-settings.ts | 4 ++ src/core/webview/ClineProvider.ts | 6 ++ src/core/webview/webviewMessageHandler.ts | 8 +++ src/shared/WebviewMessage.ts | 2 + .../src/components/chat/AutoApproveMenu.tsx | 8 +++ webview-ui/src/components/chat/ChatView.tsx | 40 ++++++++++--- .../src/components/chat/FollowUpSuggest.tsx | 58 ++++++++++++++++++- .../settings/AutoApproveSettings.tsx | 34 +++++++++++ .../components/settings/AutoApproveToggle.tsx | 10 +++- .../src/components/settings/SettingsView.tsx | 6 ++ .../__tests__/AutoApproveToggle.spec.tsx | 1 + .../src/context/ExtensionStateContext.tsx | 19 ++++++ webview-ui/src/i18n/locales/en/chat.json | 3 +- webview-ui/src/i18n/locales/en/settings.json | 5 ++ 14 files changed, 193 insertions(+), 11 deletions(-) diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index e713cafa4c..7cd051c6bf 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -45,6 +45,8 @@ export const globalSettingsSchema = z.object({ alwaysAllowModeSwitch: z.boolean().optional(), alwaysAllowSubtasks: z.boolean().optional(), alwaysAllowExecute: z.boolean().optional(), + alwaysAllowFollowupQuestions: z.boolean().optional(), + followupAutoApproveTimeoutMs: z.number().optional(), allowedCommands: z.array(z.string()).optional(), allowedMaxRequests: z.number().nullish(), autoCondenseContext: z.boolean().optional(), @@ -189,6 +191,8 @@ export const EVALS_SETTINGS: RooCodeSettings = { alwaysAllowModeSwitch: true, alwaysAllowSubtasks: true, alwaysAllowExecute: true, + alwaysAllowFollowupQuestions: true, + followupAutoApproveTimeoutMs: 0, allowedCommands: ["*"], browserToolEnabled: false, diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 51cb9a275b..0e4a8cef93 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1411,6 +1411,8 @@ export class ClineProvider codebaseIndexConfig, codebaseIndexModels, profileThresholds, + alwaysAllowFollowupQuestions, + followupAutoApproveTimeoutMs, } = await this.getState() const telemetryKey = process.env.POSTHOG_API_KEY @@ -1521,6 +1523,8 @@ export class ClineProvider profileThresholds: profileThresholds ?? {}, cloudApiUrl: getRooCodeApiUrl(), hasOpenedModeSelector: this.getGlobalState("hasOpenedModeSelector") ?? false, + alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false, + followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 10000, } } @@ -1601,6 +1605,8 @@ export class ClineProvider alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false, alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false, alwaysAllowSubtasks: stateValues.alwaysAllowSubtasks ?? false, + alwaysAllowFollowupQuestions: stateValues.alwaysAllowFollowupQuestions ?? false, + followupAutoApproveTimeoutMs: stateValues.followupAutoApproveTimeoutMs ?? 10000, allowedMaxRequests: stateValues.allowedMaxRequests, autoCondenseContext: stateValues.autoCondenseContext ?? true, autoCondenseContextPercent: stateValues.autoCondenseContextPercent ?? 100, diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index cac94aa0ce..af053044b2 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -1100,6 +1100,14 @@ export const webviewMessageHandler = async ( await updateGlobalState("maxWorkspaceFiles", fileCount) await provider.postStateToWebview() break + case "alwaysAllowFollowupQuestions": + await updateGlobalState("alwaysAllowFollowupQuestions", message.bool ?? false) + await provider.postStateToWebview() + break + case "followupAutoApproveTimeoutMs": + await updateGlobalState("followupAutoApproveTimeoutMs", message.value) + await provider.postStateToWebview() + break case "browserToolEnabled": await updateGlobalState("browserToolEnabled", message.bool ?? true) await provider.postStateToWebview() diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 7efc97e8c7..42718595c3 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -37,6 +37,8 @@ export interface WebviewMessage { | "alwaysAllowWriteOutsideWorkspace" | "alwaysAllowWriteProtected" | "alwaysAllowExecute" + | "alwaysAllowFollowupQuestions" + | "followupAutoApproveTimeoutMs" | "webviewDidLaunch" | "newTask" | "askResponse" diff --git a/webview-ui/src/components/chat/AutoApproveMenu.tsx b/webview-ui/src/components/chat/AutoApproveMenu.tsx index ac02d6b8c4..8d838f0a18 100644 --- a/webview-ui/src/components/chat/AutoApproveMenu.tsx +++ b/webview-ui/src/components/chat/AutoApproveMenu.tsx @@ -25,6 +25,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysApproveResubmit, + alwaysAllowFollowupQuestions, allowedMaxRequests, setAlwaysAllowReadOnly, setAlwaysAllowWrite, @@ -34,6 +35,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { setAlwaysAllowModeSwitch, setAlwaysAllowSubtasks, setAlwaysApproveResubmit, + setAlwaysAllowFollowupQuestions, setAllowedMaxRequests, } = useExtensionState() @@ -68,6 +70,9 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { case "alwaysApproveResubmit": setAlwaysApproveResubmit(value) break + case "alwaysAllowFollowupQuestions": + setAlwaysAllowFollowupQuestions(value) + break } }, [ @@ -79,6 +84,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { setAlwaysAllowModeSwitch, setAlwaysAllowSubtasks, setAlwaysApproveResubmit, + setAlwaysAllowFollowupQuestions, ], ) @@ -94,6 +100,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { alwaysAllowModeSwitch: alwaysAllowModeSwitch, alwaysAllowSubtasks: alwaysAllowSubtasks, alwaysApproveResubmit: alwaysApproveResubmit, + alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions, }), [ alwaysAllowReadOnly, @@ -104,6 +111,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => { alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysApproveResubmit, + alwaysAllowFollowupQuestions, ], ) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index e9c5a17415..4e2f6fba98 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -88,11 +88,13 @@ const ChatViewComponent: React.ForwardRefRenderFunction { if (lastMessage?.ask && isAutoApproved(lastMessage)) { - if (lastMessage.ask === "tool" && isWriteToolAction(lastMessage)) { + // Special handling for follow-up questions + if (lastMessage.ask === "followup") { + const followUpData = JSON.parse(lastMessage.text || "{}") + if (followUpData && followUpData.suggest && followUpData.suggest.length > 0) { + // Wait for the configured timeout before auto-selecting the first suggestion + await new Promise((resolve) => { + autoApproveTimeoutRef.current = setTimeout(resolve, followupAutoApproveTimeoutMs) + }) + + // Get the first suggestion + const firstSuggestion = followUpData.suggest[0] + const suggestionText = + typeof firstSuggestion === "string" ? firstSuggestion : firstSuggestion.answer + + // Handle the suggestion click + handleSuggestionClickInRow(suggestionText) + return + } + } else if (lastMessage.ask === "tool" && isWriteToolAction(lastMessage)) { await new Promise((resolve) => { autoApproveTimeoutRef.current = setTimeout(resolve, writeDelayMs) }) } - if (autoApproveTimeoutRef.current === null || autoApproveTimeoutRef.current) { - vscode.postMessage({ type: "askResponse", askResponse: "yesButtonClicked" }) + vscode.postMessage({ type: "askResponse", askResponse: "yesButtonClicked" }) - setSendingDisabled(true) - setClineAsk(undefined) - setEnableButtons(false) - } + setSendingDisabled(true) + setClineAsk(undefined) + setEnableButtons(false) } } autoApprove() @@ -1303,6 +1326,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + const { autoApprovalEnabled, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs } = useExtensionState() + const [countdown, setCountdown] = useState(null) + const [suggestionSelected, setSuggestionSelected] = useState(false) const { t } = useAppTranslation() + + // Start countdown timer when auto-approval is enabled for follow-up questions + useEffect(() => { + // Only start countdown if auto-approval is enabled for follow-up questions and no suggestion has been selected + if (autoApprovalEnabled && alwaysAllowFollowupQuestions && suggestions.length > 0 && !suggestionSelected) { + // Start with the configured timeout in seconds + const timeoutMs = + typeof followupAutoApproveTimeoutMs === "number" && !isNaN(followupAutoApproveTimeoutMs) + ? followupAutoApproveTimeoutMs + : 10000 + + // Convert milliseconds to seconds for the countdown + setCountdown(Math.floor(timeoutMs / 1000)) + + // Update countdown every second + const intervalId = setInterval(() => { + setCountdown((prevCountdown) => { + if (prevCountdown === null || prevCountdown <= 1) { + clearInterval(intervalId) + return null + } + return prevCountdown - 1 + }) + }, 1000) + + // Clean up interval on unmount + return () => clearInterval(intervalId) + } else { + setCountdown(null) + } + }, [ + autoApprovalEnabled, + alwaysAllowFollowupQuestions, + suggestions, + followupAutoApproveTimeoutMs, + suggestionSelected, + ]) const handleSuggestionClick = useCallback( (suggestion: string | SuggestionItem, event: React.MouseEvent) => { const suggestionText = typeof suggestion === "string" ? suggestion : suggestion.answer @@ -32,6 +73,11 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: }) } + // Mark a suggestion as selected if it's not a shift-click (which just copies to input) + if (!event.shiftKey) { + setSuggestionSelected(true) + } + onSuggestionClick?.(suggestionText, event) }, [onSuggestionClick], @@ -44,9 +90,10 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: return (
- {suggestions.map((suggestion) => { + {suggestions.map((suggestion, index) => { const suggestionText = typeof suggestion === "string" ? suggestion : suggestion.answer const mode = typeof suggestion === "object" ? suggestion.mode : undefined + const isFirstSuggestion = index === 0 return (
@@ -56,6 +103,13 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: onClick={(event) => handleSuggestionClick(suggestion, event)} aria-label={suggestionText}> {suggestionText} + {isFirstSuggestion && countdown !== null && !suggestionSelected && ( + + {countdown}s + + )} {mode && (
diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx index e825ab8d7c..890d953437 100644 --- a/webview-ui/src/components/settings/AutoApproveSettings.tsx +++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx @@ -25,6 +25,8 @@ type AutoApproveSettingsProps = HTMLAttributes & { alwaysAllowModeSwitch?: boolean alwaysAllowSubtasks?: boolean alwaysAllowExecute?: boolean + alwaysAllowFollowupQuestions?: boolean + followupAutoApproveTimeoutMs?: number allowedCommands?: string[] setCachedStateField: SetCachedStateField< | "alwaysAllowReadOnly" @@ -40,6 +42,8 @@ type AutoApproveSettingsProps = HTMLAttributes & { | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" | "alwaysAllowExecute" + | "alwaysAllowFollowupQuestions" + | "followupAutoApproveTimeoutMs" | "allowedCommands" > } @@ -58,6 +62,8 @@ export const AutoApproveSettings = ({ alwaysAllowModeSwitch, alwaysAllowSubtasks, alwaysAllowExecute, + alwaysAllowFollowupQuestions, + followupAutoApproveTimeoutMs = 10000, allowedCommands, setCachedStateField, ...props @@ -95,6 +101,7 @@ export const AutoApproveSettings = ({ alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} + alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} onToggle={(key, value) => setCachedStateField(key, value)} /> @@ -202,6 +209,33 @@ export const AutoApproveSettings = ({
)} + {alwaysAllowFollowupQuestions && ( +
+
+ +
{t("settings:autoApprove.followupQuestions.label")}
+
+
+
+ + setCachedStateField("followupAutoApproveTimeoutMs", value) + } + data-testid="followup-timeout-slider" + /> + {followupAutoApproveTimeoutMs / 1000}s +
+
+ {t("settings:autoApprove.followupQuestions.timeoutLabel")} +
+
+
+ )} + {alwaysAllowExecute && (
diff --git a/webview-ui/src/components/settings/AutoApproveToggle.tsx b/webview-ui/src/components/settings/AutoApproveToggle.tsx index d2b6694f75..2cbe3e2952 100644 --- a/webview-ui/src/components/settings/AutoApproveToggle.tsx +++ b/webview-ui/src/components/settings/AutoApproveToggle.tsx @@ -14,6 +14,7 @@ type AutoApproveToggles = Pick< | "alwaysAllowModeSwitch" | "alwaysAllowSubtasks" | "alwaysAllowExecute" + | "alwaysAllowFollowupQuestions" > export type AutoApproveSetting = keyof AutoApproveToggles @@ -83,6 +84,13 @@ export const autoApproveSettingsConfig: Record diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 8712b81cf2..92d1b84fd9 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -174,6 +174,8 @@ const SettingsView = forwardRef(({ onDone, t codebaseIndexModels, customSupportPrompts, profileThresholds, + alwaysAllowFollowupQuestions, + followupAutoApproveTimeoutMs, } = cachedState const apiConfiguration = useMemo(() => cachedState.apiConfiguration ?? {}, [cachedState.apiConfiguration]) @@ -311,6 +313,8 @@ const SettingsView = forwardRef(({ onDone, t vscode.postMessage({ type: "updateExperimental", values: experiments }) vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: alwaysAllowModeSwitch }) vscode.postMessage({ type: "alwaysAllowSubtasks", bool: alwaysAllowSubtasks }) + vscode.postMessage({ type: "alwaysAllowFollowupQuestions", bool: alwaysAllowFollowupQuestions }) + vscode.postMessage({ type: "followupAutoApproveTimeoutMs", value: followupAutoApproveTimeoutMs }) vscode.postMessage({ type: "condensingApiConfigId", text: condensingApiConfigId || "" }) vscode.postMessage({ type: "updateCondensingPrompt", text: customCondensingPrompt || "" }) vscode.postMessage({ type: "updateSupportPrompt", values: customSupportPrompts || {} }) @@ -599,6 +603,8 @@ const SettingsView = forwardRef(({ onDone, t alwaysAllowModeSwitch={alwaysAllowModeSwitch} alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} + alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} + followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs || 10000} allowedCommands={allowedCommands} setCachedStateField={setCachedStateField} /> diff --git a/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx b/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx index 97e5dcc96b..ac8c054f65 100644 --- a/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/AutoApproveToggle.spec.tsx @@ -25,6 +25,7 @@ describe("AutoApproveToggle", () => { alwaysAllowModeSwitch: true, alwaysAllowSubtasks: false, alwaysAllowExecute: true, + alwaysAllowFollowupQuestions: false, onToggle: mockOnToggle, } diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index c87ccdb6e9..ea3c6208d7 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -40,6 +40,10 @@ export interface ExtensionStateContextType extends ExtensionState { mdmCompliant?: boolean hasOpenedModeSelector: boolean // New property to track if user has opened mode selector setHasOpenedModeSelector: (value: boolean) => void // Setter for the new property + alwaysAllowFollowupQuestions: boolean // New property for follow-up questions auto-approve + setAlwaysAllowFollowupQuestions: (value: boolean) => void // Setter for the new property + followupAutoApproveTimeoutMs: number | undefined // Timeout in ms for auto-approving follow-up questions + setFollowupAutoApproveTimeoutMs: (value: number) => void // Setter for the timeout condensingApiConfigId?: string setCondensingApiConfigId: (value: string) => void customCondensingPrompt?: string @@ -226,6 +230,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode const [currentCheckpoint, setCurrentCheckpoint] = useState() const [extensionRouterModels, setExtensionRouterModels] = useState(undefined) const [marketplaceItems, setMarketplaceItems] = useState([]) + const [alwaysAllowFollowupQuestions, setAlwaysAllowFollowupQuestions] = useState(false) // Add state for follow-up questions auto-approve + const [followupAutoApproveTimeoutMs, setFollowupAutoApproveTimeoutMs] = useState(undefined) // Will be set from global settings const [marketplaceInstalledMetadata, setMarketplaceInstalledMetadata] = useState({ project: {}, global: {}, @@ -255,6 +261,14 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setState((prevState) => mergeExtensionState(prevState, newState)) setShowWelcome(!checkExistKey(newState.apiConfiguration)) setDidHydrateState(true) + // Update alwaysAllowFollowupQuestions if present in state message + if ((newState as any).alwaysAllowFollowupQuestions !== undefined) { + setAlwaysAllowFollowupQuestions((newState as any).alwaysAllowFollowupQuestions) + } + // Update followupAutoApproveTimeoutMs if present in state message + if ((newState as any).followupAutoApproveTimeoutMs !== undefined) { + setFollowupAutoApproveTimeoutMs((newState as any).followupAutoApproveTimeoutMs) + } // Handle marketplace data if present in state message if (newState.marketplaceItems !== undefined) { setMarketplaceItems(newState.marketplaceItems) @@ -352,6 +366,8 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode marketplaceItems, marketplaceInstalledMetadata, profileThresholds: state.profileThresholds ?? {}, + alwaysAllowFollowupQuestions, + followupAutoApproveTimeoutMs, setExperimentEnabled: (id, enabled) => setState((prevState) => ({ ...prevState, experiments: { ...prevState.experiments, [id]: enabled } })), setApiConfiguration, @@ -367,6 +383,9 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })), setAlwaysAllowModeSwitch: (value) => setState((prevState) => ({ ...prevState, alwaysAllowModeSwitch: value })), setAlwaysAllowSubtasks: (value) => setState((prevState) => ({ ...prevState, alwaysAllowSubtasks: value })), + setAlwaysAllowFollowupQuestions, + setFollowupAutoApproveTimeoutMs: (value) => + setState((prevState) => ({ ...prevState, followupAutoApproveTimeoutMs: value })), setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })), setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })), setAllowedMaxRequests: (value) => setState((prevState) => ({ ...prevState, allowedMaxRequests: value })), diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 3e5c2bfc60..308ca6e63e 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -257,7 +257,8 @@ "seconds": "{{count}}s" }, "followUpSuggest": { - "copyToInput": "Copy to input (same as shift + click)" + "copyToInput": "Copy to input (same as shift + click)", + "autoSelectCountdown": "Auto-selecting in {{count}}s" }, "browser": { "rooWantsToUse": "Roo wants to use the browser:", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 14981ea499..f60f0487a6 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -110,6 +110,11 @@ "label": "Subtasks", "description": "Allow creation and completion of subtasks without requiring approval" }, + "followupQuestions": { + "label": "Question", + "description": "Automatically select the first suggested answer for follow-up questions after the configured timeout", + "timeoutLabel": "Time to wait before auto-selecting the first answer" + }, "execute": { "label": "Execute", "description": "Automatically execute allowed terminal commands without requiring approval", From c998cab16150bfea94de22fec11259fceca2deaa Mon Sep 17 00:00:00 2001 From: Will Li Date: Mon, 30 Jun 2025 14:49:39 -0700 Subject: [PATCH 2/7] translations --- webview-ui/src/i18n/locales/ca/chat.json | 3 ++- webview-ui/src/i18n/locales/ca/settings.json | 5 +++++ webview-ui/src/i18n/locales/de/chat.json | 3 ++- webview-ui/src/i18n/locales/de/settings.json | 5 +++++ webview-ui/src/i18n/locales/es/chat.json | 3 ++- webview-ui/src/i18n/locales/es/settings.json | 5 +++++ webview-ui/src/i18n/locales/fr/chat.json | 3 ++- webview-ui/src/i18n/locales/fr/settings.json | 5 +++++ webview-ui/src/i18n/locales/hi/chat.json | 3 ++- webview-ui/src/i18n/locales/hi/settings.json | 5 +++++ webview-ui/src/i18n/locales/id/chat.json | 3 ++- webview-ui/src/i18n/locales/id/settings.json | 5 +++++ webview-ui/src/i18n/locales/it/chat.json | 3 ++- webview-ui/src/i18n/locales/it/settings.json | 5 +++++ webview-ui/src/i18n/locales/ja/chat.json | 3 ++- webview-ui/src/i18n/locales/ja/settings.json | 5 +++++ webview-ui/src/i18n/locales/ko/chat.json | 3 ++- webview-ui/src/i18n/locales/ko/settings.json | 5 +++++ webview-ui/src/i18n/locales/nl/chat.json | 3 ++- webview-ui/src/i18n/locales/nl/settings.json | 5 +++++ webview-ui/src/i18n/locales/pl/chat.json | 3 ++- webview-ui/src/i18n/locales/pl/settings.json | 5 +++++ webview-ui/src/i18n/locales/pt-BR/chat.json | 3 ++- webview-ui/src/i18n/locales/pt-BR/settings.json | 5 +++++ webview-ui/src/i18n/locales/ru/chat.json | 3 ++- webview-ui/src/i18n/locales/ru/settings.json | 5 +++++ webview-ui/src/i18n/locales/tr/chat.json | 3 ++- webview-ui/src/i18n/locales/tr/settings.json | 5 +++++ webview-ui/src/i18n/locales/vi/chat.json | 3 ++- webview-ui/src/i18n/locales/vi/settings.json | 5 +++++ webview-ui/src/i18n/locales/zh-CN/chat.json | 3 ++- webview-ui/src/i18n/locales/zh-CN/settings.json | 5 +++++ webview-ui/src/i18n/locales/zh-TW/chat.json | 3 ++- webview-ui/src/i18n/locales/zh-TW/settings.json | 5 +++++ 34 files changed, 119 insertions(+), 17 deletions(-) diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 07f1e25b53..6b24d0724e 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -234,7 +234,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "Copiar a l'entrada (o Shift + clic)" + "copyToInput": "Copiar a l'entrada (o Shift + clic)", + "autoSelectCountdown": "Selecció automàtica en {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} publicat", diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index ea4f974149..e5c14126fb 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -110,6 +110,11 @@ "label": "Subtasques", "description": "Permetre la creació i finalització de subtasques sense requerir aprovació" }, + "followupQuestions": { + "label": "Pregunta", + "description": "Seleccionar automàticament la primera resposta suggerida per a preguntes de seguiment després del temps d'espera configurat", + "timeoutLabel": "Temps d'espera abans de seleccionar automàticament la primera resposta" + }, "execute": { "label": "Executar", "description": "Executar automàticament comandes de terminal permeses sense requerir aprovació", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index b5c2336e46..dd4f640b91 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -234,7 +234,8 @@ "tokens": "Tokens" }, "followUpSuggest": { - "copyToInput": "In Eingabefeld kopieren (oder Shift + Klick)" + "copyToInput": "In Eingabefeld kopieren (oder Shift + Klick)", + "autoSelectCountdown": "Automatische Auswahl in {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} veröffentlicht", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index c5e161bafe..3e473770bf 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -110,6 +110,11 @@ "label": "Teilaufgaben", "description": "Erstellung und Abschluss von Unteraufgaben ohne Genehmigung erlauben" }, + "followupQuestions": { + "label": "Frage", + "description": "Automatisch die erste vorgeschlagene Antwort für Folgefragen nach der konfigurierten Zeitüberschreitung auswählen", + "timeoutLabel": "Wartezeit vor der automatischen Auswahl der ersten Antwort" + }, "execute": { "label": "Ausführen", "description": "Erlaubte Terminal-Befehle automatisch ohne Genehmigung ausführen", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index db90a70057..93a8cc1ec0 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -234,7 +234,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "Copiar a la entrada (o Shift + clic)" + "copyToInput": "Copiar a la entrada (o Shift + clic)", + "autoSelectCountdown": "Selección automática en {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} publicado", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 3e3d20cce1..3354dd1c78 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -110,6 +110,11 @@ "label": "Subtareas", "description": "Permitir la creación y finalización de subtareas sin requerir aprobación" }, + "followupQuestions": { + "label": "Pregunta", + "description": "Seleccionar automáticamente la primera respuesta sugerida para preguntas de seguimiento después del tiempo de espera configurado", + "timeoutLabel": "Tiempo de espera antes de seleccionar automáticamente la primera respuesta" + }, "execute": { "label": "Ejecutar", "description": "Ejecutar automáticamente comandos de terminal permitidos sin requerir aprobación", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index b0d20bc7b2..8f4d4e4240 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -234,7 +234,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "Copier vers l'entrée (ou Shift + clic)" + "copyToInput": "Copier vers l'entrée (ou Shift + clic)", + "autoSelectCountdown": "Sélection automatique dans {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} est sortie", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 5635251876..da0cda88d3 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -110,6 +110,11 @@ "label": "Sous-tâches", "description": "Permettre la création et l'achèvement des sous-tâches sans nécessiter d'approbation" }, + "followupQuestions": { + "label": "Question", + "description": "Sélectionner automatiquement la première réponse suggérée pour les questions de suivi après le délai configuré", + "timeoutLabel": "Temps d'attente avant la sélection automatique de la première réponse" + }, "execute": { "label": "Exécuter", "description": "Exécuter automatiquement les commandes de terminal autorisées sans nécessiter d'approbation", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 24e2af1eb7..44017b937c 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -234,7 +234,8 @@ "tokens": "टोकन" }, "followUpSuggest": { - "copyToInput": "इनपुट में कॉपी करें (या Shift + क्लिक)" + "copyToInput": "इनपुट में कॉपी करें (या Shift + क्लिक)", + "autoSelectCountdown": "{{count}}s में स्वचालित रूप से चयन हो रहा है" }, "announcement": { "title": "🎉 Roo Code {{version}} रिलीज़ हुआ", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 8de5bd1a19..197498aab1 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -110,6 +110,11 @@ "label": "उप-कार्य", "description": "अनुमोदन की आवश्यकता के बिना उप-कार्यों के निर्माण और पूर्णता की अनुमति दें" }, + "followupQuestions": { + "label": "प्रश्न", + "description": "कॉन्फ़िगर किए गए टाइमआउट के बाद अनुवर्ती प्रश्नों के लिए पहले सुझाए गए उत्तर को स्वचालित रूप से चुनें", + "timeoutLabel": "पहले उत्तर को स्वचालित रूप से चुनने से पहले प्रतीक्षा करने का समय" + }, "execute": { "label": "निष्पादित करें", "description": "अनुमोदन की आवश्यकता के बिना स्वचालित रूप से अनुमत टर्मिनल कमांड निष्पादित करें", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index 0568b58913..ffb05a90a9 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -263,7 +263,8 @@ "seconds": "{{count}}d" }, "followUpSuggest": { - "copyToInput": "Salin ke input (sama dengan shift + klik)" + "copyToInput": "Salin ke input (sama dengan shift + klik)", + "autoSelectCountdown": "Pemilihan otomatis dalam {{count}}d" }, "browser": { "rooWantsToUse": "Roo ingin menggunakan browser:", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 8def303c05..1b5fa5de5e 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -110,6 +110,11 @@ "label": "Subtugas", "description": "Izinkan pembuatan dan penyelesaian subtugas tanpa memerlukan persetujuan" }, + "followupQuestions": { + "label": "Pertanyaan", + "description": "Secara otomatis memilih jawaban pertama yang disarankan untuk pertanyaan lanjutan setelah batas waktu yang dikonfigurasi", + "timeoutLabel": "Waktu tunggu sebelum otomatis memilih jawaban pertama" + }, "execute": { "label": "Eksekusi", "description": "Secara otomatis mengeksekusi perintah terminal yang diizinkan tanpa memerlukan persetujuan", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 1f7d6b463f..8dca230d2f 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -234,7 +234,8 @@ "tokens": "token" }, "followUpSuggest": { - "copyToInput": "Copia nell'input (o Shift + clic)" + "copyToInput": "Copia nell'input (o Shift + clic)", + "autoSelectCountdown": "Selezione automatica in {{count}}s" }, "announcement": { "title": "🎉 Rilasciato Roo Code {{version}}", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 572f99cbb0..8dc0c60040 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -110,6 +110,11 @@ "label": "Sottoattività", "description": "Consenti la creazione e il completamento di attività secondarie senza richiedere approvazione" }, + "followupQuestions": { + "label": "Domanda", + "description": "Seleziona automaticamente la prima risposta suggerita per le domande di follow-up dopo il timeout configurato", + "timeoutLabel": "Tempo di attesa prima di selezionare automaticamente la prima risposta" + }, "execute": { "label": "Esegui", "description": "Esegui automaticamente i comandi del terminale consentiti senza richiedere approvazione", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 255acb717f..3257fc66c8 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -234,7 +234,8 @@ "tokens": "トークン" }, "followUpSuggest": { - "copyToInput": "入力欄にコピー(またはShift + クリック)" + "copyToInput": "入力欄にコピー(またはShift + クリック)", + "autoSelectCountdown": "{{count}}秒後に自動選択します" }, "announcement": { "title": "🎉 Roo Code {{version}} リリース", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index c6a681e549..dcafa94aeb 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -110,6 +110,11 @@ "label": "サブタスク", "description": "承認なしでサブタスクの作成と完了を許可" }, + "followupQuestions": { + "label": "質問", + "description": "設定された時間が経過すると、フォローアップ質問の最初の提案回答を自動的に選択します", + "timeoutLabel": "最初の回答を自動選択するまでの待機時間" + }, "execute": { "label": "実行", "description": "承認なしで自動的に許可されたターミナルコマンドを実行", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index b83c400574..7f1132471c 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -234,7 +234,8 @@ "tokens": "토큰" }, "followUpSuggest": { - "copyToInput": "입력창에 복사 (또는 Shift + 클릭)" + "copyToInput": "입력창에 복사 (또는 Shift + 클릭)", + "autoSelectCountdown": "{{count}}초 후 자동 선택" }, "announcement": { "title": "🎉 Roo Code {{version}} 출시", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 6ae68428bd..a21ce5ea2f 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -110,6 +110,11 @@ "label": "하위 작업", "description": "승인 없이 하위 작업 생성 및 완료 허용" }, + "followupQuestions": { + "label": "질문", + "description": "설정된 시간이 지나면 후속 질문에 대한 첫 번째 제안 답변을 자동으로 선택합니다", + "timeoutLabel": "첫 번째 답변을 자동 선택하기 전 대기 시간" + }, "execute": { "label": "실행", "description": "승인 없이 자동으로 허용된 터미널 명령 실행", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index 4b6877389d..c932e61e4c 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -244,7 +244,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "Kopiëren naar invoer (zelfde als shift + klik)" + "copyToInput": "Kopiëren naar invoer (zelfde als shift + klik)", + "autoSelectCountdown": "Automatische selectie in {{count}}s" }, "browser": { "rooWantsToUse": "Roo wil de browser gebruiken:", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index c6d1bb7992..dfae50456e 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -110,6 +110,11 @@ "label": "Subtaken", "description": "Subtaken aanmaken en afronden zonder goedkeuring" }, + "followupQuestions": { + "label": "Vraag", + "description": "Selecteer automatisch het eerste voorgestelde antwoord voor vervolgvragen na de geconfigureerde time-out", + "timeoutLabel": "Wachttijd voordat het eerste antwoord automatisch wordt geselecteerd" + }, "execute": { "label": "Uitvoeren", "description": "Automatisch toegestane terminalcommando's uitvoeren zonder goedkeuring", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index fe1a47156a..72945ce784 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -234,7 +234,8 @@ "tokens": "tokeny" }, "followUpSuggest": { - "copyToInput": "Kopiuj do pola wprowadzania (lub Shift + kliknięcie)" + "copyToInput": "Kopiuj do pola wprowadzania (lub Shift + kliknięcie)", + "autoSelectCountdown": "Automatyczny wybór za {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} wydany", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index b702d7b5a5..a86c832322 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -110,6 +110,11 @@ "label": "Podzadania", "description": "Zezwalaj na tworzenie i ukończenie podzadań bez konieczności zatwierdzania" }, + "followupQuestions": { + "label": "Pytanie", + "description": "Automatycznie wybierz pierwszą sugerowaną odpowiedź na pytania uzupełniające po skonfigurowanym limicie czasu", + "timeoutLabel": "Czas oczekiwania przed automatycznym wybraniem pierwszej odpowiedzi" + }, "execute": { "label": "Wykonaj", "description": "Automatycznie wykonuj dozwolone polecenia terminala bez konieczności zatwierdzania", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index f8dd3542c0..a4b851b1a6 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -234,7 +234,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "Copiar para entrada (ou Shift + clique)" + "copyToInput": "Copiar para entrada (ou Shift + clique)", + "autoSelectCountdown": "Seleção automática em {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} Lançado", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index be7bfe2d0d..9a4ceeb561 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -110,6 +110,11 @@ "label": "Subtarefas", "description": "Permitir a criação e conclusão de subtarefas sem exigir aprovação" }, + "followupQuestions": { + "label": "Pergunta", + "description": "Selecionar automaticamente a primeira resposta sugerida para perguntas de acompanhamento após o tempo limite configurado", + "timeoutLabel": "Tempo de espera antes de selecionar automaticamente a primeira resposta" + }, "execute": { "label": "Executar", "description": "Executar automaticamente comandos de terminal permitidos sem exigir aprovação", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index b07d8d49f7..ee22201e06 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -244,7 +244,8 @@ "tokens": "токены" }, "followUpSuggest": { - "copyToInput": "Скопировать во ввод (то же, что shift + клик)" + "copyToInput": "Скопировать во ввод (то же, что shift + клик)", + "autoSelectCountdown": "Автовыбор через {{count}}с" }, "browser": { "rooWantsToUse": "Roo хочет использовать браузер:", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index b0693f4532..712e7f4e01 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -110,6 +110,11 @@ "label": "Подзадачи", "description": "Разрешить создание и выполнение подзадач без необходимости одобрения" }, + "followupQuestions": { + "label": "Вопрос", + "description": "Автоматически выбирать первый предложенный ответ на дополнительные вопросы после настроенного тайм-аута", + "timeoutLabel": "Время ожидания перед автоматическим выбором первого ответа" + }, "execute": { "label": "Выполнение", "description": "Автоматически выполнять разрешённые команды терминала без необходимости одобрения", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index f5625842b1..98b1eecd5c 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -234,7 +234,8 @@ "tokens": "token" }, "followUpSuggest": { - "copyToInput": "Giriş alanına kopyala (veya Shift + tıklama)" + "copyToInput": "Giriş alanına kopyala (veya Shift + tıklama)", + "autoSelectCountdown": "{{count}}s içinde otomatik seçilecek" }, "announcement": { "title": "🎉 Roo Code {{version}} Yayınlandı", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 06bd626406..93c14bd326 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -110,6 +110,11 @@ "label": "Alt Görevler", "description": "Onay gerektirmeden alt görevlerin oluşturulmasına ve tamamlanmasına izin ver" }, + "followupQuestions": { + "label": "Soru", + "description": "Yapılandırılan zaman aşımından sonra takip sorularına ilişkin ilk önerilen yanıtı otomatik olarak seç", + "timeoutLabel": "İlk yanıtı otomatik olarak seçmeden önce beklenecek süre" + }, "execute": { "label": "Yürüt", "description": "Onay gerektirmeden otomatik olarak izin verilen terminal komutlarını yürüt", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 05f9ed8a3d..88c310d249 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -234,7 +234,8 @@ "tokens": "token" }, "followUpSuggest": { - "copyToInput": "Sao chép vào ô nhập liệu (hoặc Shift + nhấp chuột)" + "copyToInput": "Sao chép vào ô nhập liệu (hoặc Shift + nhấp chuột)", + "autoSelectCountdown": "Tự động chọn sau {{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} Đã phát hành", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index c434276b3b..bbfc984261 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -110,6 +110,11 @@ "label": "Công việc phụ", "description": "Cho phép tạo và hoàn thành các công việc phụ mà không cần phê duyệt" }, + "followupQuestions": { + "label": "Câu hỏi", + "description": "Tự động chọn câu trả lời đầu tiên được đề xuất cho các câu hỏi tiếp theo sau thời gian chờ đã cấu hình", + "timeoutLabel": "Thời gian chờ trước khi tự động chọn câu trả lời đầu tiên" + }, "execute": { "label": "Thực thi", "description": "Tự động thực thi các lệnh terminal được phép mà không cần phê duyệt", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index d85c633699..4d5f791358 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -234,7 +234,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "复制到输入框(或按住Shift点击)" + "copyToInput": "复制到输入框(或按住Shift点击)", + "autoSelectCountdown": "{{count}}秒后自动选择" }, "announcement": { "title": "🎉 Roo Code {{version}} 已发布", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 80bcab26eb..999ba44351 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -110,6 +110,11 @@ "label": "子任务", "description": "允许创建和完成子任务而无需批准" }, + "followupQuestions": { + "label": "问题", + "description": "在配置的超时时间后自动选择后续问题的第一个建议答案", + "timeoutLabel": "自动选择第一个答案前的等待时间" + }, "execute": { "label": "执行", "description": "自动执行白名单中的命令而无需批准", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index b3659f6869..675cb3d2c5 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -234,7 +234,8 @@ "tokens": "tokens" }, "followUpSuggest": { - "copyToInput": "複製到輸入框(或按住 Shift 並點選)" + "copyToInput": "複製到輸入框(或按住 Shift 並點選)", + "autoSelectCountdown": "{{count}}秒後自動選擇" }, "announcement": { "title": "🎉 Roo Code {{version}} 已發布", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 033230ebb4..3b3a92991c 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -110,6 +110,11 @@ "label": "子工作", "description": "允許建立和完成子工作而無需核准" }, + "followupQuestions": { + "label": "問題", + "description": "在設定的逾時時間後自動選擇後續問題的第一個建議答案", + "timeoutLabel": "自動選擇第一個答案前的等待時間" + }, "execute": { "label": "執行", "description": "自動執行允許的終端機命令而無需核准", From 2a79f7ca20d8257e7c80b0dc18177f631f841a93 Mon Sep 17 00:00:00 2001 From: Will Li Date: Mon, 30 Jun 2025 15:07:23 -0700 Subject: [PATCH 3/7] fixed styling --- webview-ui/src/components/settings/AutoApproveToggle.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webview-ui/src/components/settings/AutoApproveToggle.tsx b/webview-ui/src/components/settings/AutoApproveToggle.tsx index 2cbe3e2952..6c82d3c984 100644 --- a/webview-ui/src/components/settings/AutoApproveToggle.tsx +++ b/webview-ui/src/components/settings/AutoApproveToggle.tsx @@ -103,9 +103,10 @@ export const AutoApproveToggle = ({ onToggle, ...props }: AutoApproveToggleProps return (
{Object.values(autoApproveSettingsConfig).map(({ key, descriptionKey, labelKey, icon, testId }) => ( From d86f15d8d561bf66918ad9f06e03374e98dbce8b Mon Sep 17 00:00:00 2001 From: Will Li Date: Tue, 1 Jul 2025 00:11:26 -0700 Subject: [PATCH 4/7] code review --- packages/types/src/followup.ts | 41 +++++++++++++++++++ packages/types/src/index.ts | 1 + src/core/webview/ClineProvider.ts | 4 +- webview-ui/src/components/chat/ChatRow.tsx | 6 ++- webview-ui/src/components/chat/ChatView.tsx | 22 +++++++++- .../src/components/chat/FollowUpSuggest.tsx | 28 ++++++++----- .../settings/AutoApproveSettings.tsx | 4 +- .../src/components/settings/SettingsView.tsx | 2 +- 8 files changed, 91 insertions(+), 17 deletions(-) create mode 100644 packages/types/src/followup.ts diff --git a/packages/types/src/followup.ts b/packages/types/src/followup.ts new file mode 100644 index 0000000000..a6e3408a96 --- /dev/null +++ b/packages/types/src/followup.ts @@ -0,0 +1,41 @@ +import { z } from "zod" + +/** + * Interface for follow-up data structure used in follow-up questions + * This represents the data structure for follow-up questions that the LLM can ask + * to gather more information needed to complete a task. + */ +export interface FollowUpData { + /** The question being asked by the LLM */ + question?: string + /** Array of suggested answers that the user can select */ + suggest?: Array +} + +/** + * Interface for a suggestion item with optional mode switching + */ +export interface SuggestionItem { + /** The text of the suggestion */ + answer: string + /** Optional mode to switch to when selecting this suggestion */ + mode?: string +} + +/** + * Zod schema for SuggestionItem + */ +export const suggestionItemSchema = z.object({ + answer: z.string(), + mode: z.string().optional(), +}) + +/** + * Zod schema for FollowUpData + */ +export const followUpDataSchema = z.object({ + question: z.string().optional(), + suggest: z.array(z.union([z.string(), suggestionItemSchema])).optional(), +}) + +export type FollowUpDataType = z.infer diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 345bc3e311..6c6db9ccd5 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -4,6 +4,7 @@ export * from "./api.js" export * from "./codebase-index.js" export * from "./cloud.js" export * from "./experiment.js" +export * from "./followup.js" export * from "./global-settings.js" export * from "./history.js" export * from "./ipc.js" diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 0e4a8cef93..9d99eea1d4 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -1524,7 +1524,7 @@ export class ClineProvider cloudApiUrl: getRooCodeApiUrl(), hasOpenedModeSelector: this.getGlobalState("hasOpenedModeSelector") ?? false, alwaysAllowFollowupQuestions: alwaysAllowFollowupQuestions ?? false, - followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 10000, + followupAutoApproveTimeoutMs: followupAutoApproveTimeoutMs ?? 60000, } } @@ -1606,7 +1606,7 @@ export class ClineProvider alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false, alwaysAllowSubtasks: stateValues.alwaysAllowSubtasks ?? false, alwaysAllowFollowupQuestions: stateValues.alwaysAllowFollowupQuestions ?? false, - followupAutoApproveTimeoutMs: stateValues.followupAutoApproveTimeoutMs ?? 10000, + followupAutoApproveTimeoutMs: stateValues.followupAutoApproveTimeoutMs ?? 60000, allowedMaxRequests: stateValues.allowedMaxRequests, autoCondenseContext: stateValues.autoCondenseContext ?? true, autoCondenseContextPercent: stateValues.autoCondenseContextPercent ?? 100, diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 43824c5902..18c5db9e6a 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -10,6 +10,7 @@ import type { ClineMessage } from "@roo-code/types" import { ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "@roo/ExtensionMessage" import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences" import { safeJsonParse } from "@roo/safeJsonParse" +import { FollowUpData, SuggestionItem } from "@roo-code/types" import { useCopyToClipboard } from "@src/utils/clipboard" import { useExtensionState } from "@src/context/ExtensionStateContext" @@ -50,6 +51,7 @@ interface ChatRowProps { onHeightChange: (isTaller: boolean) => void onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void onBatchFileResponse?: (response: { [key: string]: boolean }) => void + onFollowUpUnmount?: () => void } // eslint-disable-next-line @typescript-eslint/no-empty-object-type @@ -98,6 +100,7 @@ export const ChatRowContent = ({ isStreaming, onToggleExpand, onSuggestionClick, + onFollowUpUnmount, onBatchFileResponse, }: ChatRowContentProps) => { const { t } = useTranslation() @@ -279,7 +282,7 @@ export const ChatRowContent = ({ const followUpData = useMemo(() => { if (message.type === "ask" && message.ask === "followup" && !message.partial) { - return safeJsonParse(message.text) + return safeJsonParse(message.text) } return null }, [message.type, message.ask, message.partial, message.text]) @@ -1215,6 +1218,7 @@ export const ChatRowContent = ({ suggestions={followUpData?.suggest} onSuggestionClick={onSuggestionClick} ts={message?.ts} + onUnmount={onFollowUpUnmount} /> ) diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 4e2f6fba98..50a3394a2c 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -15,6 +15,7 @@ import type { ClineAsk, ClineMessage } from "@roo-code/types" import { ClineSayBrowserAction, ClineSayTool, ExtensionMessage } from "@roo/ExtensionMessage" import { McpServer, McpTool } from "@roo/mcp" import { findLast } from "@roo/array" +import { FollowUpData } from "@roo-code/types" import { combineApiRequests } from "@roo/combineApiRequests" import { combineCommandSequences } from "@roo/combineCommandSequences" import { getApiMetrics } from "@roo/getApiMetrics" @@ -1215,6 +1216,15 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + // Clear the auto-approve timeout to prevent race conditions + if (autoApproveTimeoutRef.current) { + clearTimeout(autoApproveTimeoutRef.current) + autoApproveTimeoutRef.current = null + } + }, []) + const itemContent = useCallback( (index: number, messageOrGroup: ClineMessage | ClineMessage[]) => { // browser session group @@ -1250,6 +1260,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction ) }, @@ -1262,6 +1273,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction 0) { // Wait for the configured timeout before auto-selecting the first suggestion await new Promise((resolve) => { diff --git a/webview-ui/src/components/chat/FollowUpSuggest.tsx b/webview-ui/src/components/chat/FollowUpSuggest.tsx index 9f41b90fa2..47f6735cb1 100644 --- a/webview-ui/src/components/chat/FollowUpSuggest.tsx +++ b/webview-ui/src/components/chat/FollowUpSuggest.tsx @@ -6,19 +6,19 @@ import { vscode } from "@/utils/vscode" import { useAppTranslation } from "@src/i18n/TranslationContext" import { useExtensionState } from "@src/context/ExtensionStateContext" +import { SuggestionItem } from "@roo-code/types" -interface SuggestionItem { - answer: string - mode?: string -} +const DEFAULT_FOLLOWUP_TIMEOUT_MS = 60000 +const COUNTDOWN_INTERVAL_MS = 1000 interface FollowUpSuggestProps { suggestions?: (string | SuggestionItem)[] onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void ts: number + onUnmount?: () => void } -export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: FollowUpSuggestProps) => { +export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, onUnmount }: FollowUpSuggestProps) => { const { autoApprovalEnabled, alwaysAllowFollowupQuestions, followupAutoApproveTimeoutMs } = useExtensionState() const [countdown, setCountdown] = useState(null) const [suggestionSelected, setSuggestionSelected] = useState(false) @@ -32,7 +32,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: const timeoutMs = typeof followupAutoApproveTimeoutMs === "number" && !isNaN(followupAutoApproveTimeoutMs) ? followupAutoApproveTimeoutMs - : 10000 + : DEFAULT_FOLLOWUP_TIMEOUT_MS // Convert milliseconds to seconds for the countdown setCountdown(Math.floor(timeoutMs / 1000)) @@ -46,10 +46,15 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: } return prevCountdown - 1 }) - }, 1000) + }, COUNTDOWN_INTERVAL_MS) - // Clean up interval on unmount - return () => clearInterval(intervalId) + // Clean up interval on unmount and notify parent component + return () => { + clearInterval(intervalId) + // Notify parent component that this component is unmounting + // so it can clear any related timeouts + onUnmount?.() + } } else { setCountdown(null) } @@ -76,11 +81,14 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: // Mark a suggestion as selected if it's not a shift-click (which just copies to input) if (!event.shiftKey) { setSuggestionSelected(true) + // Also notify parent component to cancel auto-approval timeout + // This prevents race conditions between visual countdown and actual timeout + onUnmount?.() } onSuggestionClick?.(suggestionText, event) }, - [onSuggestionClick], + [onSuggestionClick, onUnmount], ) // Don't render if there are no suggestions or no click handler. diff --git a/webview-ui/src/components/settings/AutoApproveSettings.tsx b/webview-ui/src/components/settings/AutoApproveSettings.tsx index 890d953437..1f9bb282a8 100644 --- a/webview-ui/src/components/settings/AutoApproveSettings.tsx +++ b/webview-ui/src/components/settings/AutoApproveSettings.tsx @@ -63,7 +63,7 @@ export const AutoApproveSettings = ({ alwaysAllowSubtasks, alwaysAllowExecute, alwaysAllowFollowupQuestions, - followupAutoApproveTimeoutMs = 10000, + followupAutoApproveTimeoutMs = 60000, allowedCommands, setCachedStateField, ...props @@ -219,7 +219,7 @@ export const AutoApproveSettings = ({
diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 92d1b84fd9..c3b9179e37 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -604,7 +604,7 @@ const SettingsView = forwardRef(({ onDone, t alwaysAllowSubtasks={alwaysAllowSubtasks} alwaysAllowExecute={alwaysAllowExecute} alwaysAllowFollowupQuestions={alwaysAllowFollowupQuestions} - followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs || 10000} + followupAutoApproveTimeoutMs={followupAutoApproveTimeoutMs} allowedCommands={allowedCommands} setCachedStateField={setCachedStateField} /> From 820a635b566267e42f7896511884807bf2292245 Mon Sep 17 00:00:00 2001 From: Will Li Date: Tue, 1 Jul 2025 00:11:43 -0700 Subject: [PATCH 5/7] fix types --- webview-ui/src/components/chat/ChatRow.tsx | 2 +- webview-ui/src/components/chat/FollowUpSuggest.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 18c5db9e6a..72eb699927 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -10,7 +10,7 @@ import type { ClineMessage } from "@roo-code/types" import { ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "@roo/ExtensionMessage" import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences" import { safeJsonParse } from "@roo/safeJsonParse" -import { FollowUpData, SuggestionItem } from "@roo-code/types" +import { FollowUpData } from "@roo-code/types" import { useCopyToClipboard } from "@src/utils/clipboard" import { useExtensionState } from "@src/context/ExtensionStateContext" diff --git a/webview-ui/src/components/chat/FollowUpSuggest.tsx b/webview-ui/src/components/chat/FollowUpSuggest.tsx index 47f6735cb1..3362f9a7eb 100644 --- a/webview-ui/src/components/chat/FollowUpSuggest.tsx +++ b/webview-ui/src/components/chat/FollowUpSuggest.tsx @@ -64,6 +64,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o suggestions, followupAutoApproveTimeoutMs, suggestionSelected, + onUnmount, ]) const handleSuggestionClick = useCallback( (suggestion: string | SuggestionItem, event: React.MouseEvent) => { From 002ec11b8946c5dd8b728a3151551145024feed0 Mon Sep 17 00:00:00 2001 From: Will Li Date: Tue, 1 Jul 2025 10:33:54 -0700 Subject: [PATCH 6/7] added modes --- packages/types/src/followup.ts | 4 +- webview-ui/src/components/chat/ChatRow.tsx | 4 +- webview-ui/src/components/chat/ChatView.tsx | 47 +++++++++++++------ .../src/components/chat/FollowUpSuggest.tsx | 36 +++++--------- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/packages/types/src/followup.ts b/packages/types/src/followup.ts index a6e3408a96..1a5424cd11 100644 --- a/packages/types/src/followup.ts +++ b/packages/types/src/followup.ts @@ -9,7 +9,7 @@ export interface FollowUpData { /** The question being asked by the LLM */ question?: string /** Array of suggested answers that the user can select */ - suggest?: Array + suggest?: Array } /** @@ -35,7 +35,7 @@ export const suggestionItemSchema = z.object({ */ export const followUpDataSchema = z.object({ question: z.string().optional(), - suggest: z.array(z.union([z.string(), suggestionItemSchema])).optional(), + suggest: z.array(suggestionItemSchema).optional(), }) export type FollowUpDataType = z.infer diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 72eb699927..f61eb8c5e0 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -10,7 +10,7 @@ import type { ClineMessage } from "@roo-code/types" import { ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "@roo/ExtensionMessage" import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences" import { safeJsonParse } from "@roo/safeJsonParse" -import { FollowUpData } from "@roo-code/types" +import { FollowUpData, SuggestionItem } from "@roo-code/types" import { useCopyToClipboard } from "@src/utils/clipboard" import { useExtensionState } from "@src/context/ExtensionStateContext" @@ -49,7 +49,7 @@ interface ChatRowProps { isStreaming: boolean onToggleExpand: (ts: number) => void onHeightChange: (isTaller: boolean) => void - onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void + onSuggestionClick?: (suggestion: SuggestionItem, event?: React.MouseEvent) => void onBatchFileResponse?: (response: { [key: string]: boolean }) => void onFollowUpUnmount?: () => void } diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index 50a3394a2c..5c2e2277fb 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -15,7 +15,7 @@ import type { ClineAsk, ClineMessage } from "@roo-code/types" import { ClineSayBrowserAction, ClineSayTool, ExtensionMessage } from "@roo/ExtensionMessage" import { McpServer, McpTool } from "@roo/mcp" import { findLast } from "@roo/array" -import { FollowUpData } from "@roo-code/types" +import { FollowUpData, SuggestionItem } from "@roo-code/types" import { combineApiRequests } from "@roo/combineApiRequests" import { combineCommandSequences } from "@roo/combineCommandSequences" import { getApiMetrics } from "@roo/getApiMetrics" @@ -1197,18 +1197,43 @@ const ChatViewComponent: React.ForwardRefRenderFunction { + // Update local state and notify extension to sync mode change + setMode(modeSlug) + + // Send the mode switch message + vscode.postMessage({ + type: "mode", + text: modeSlug, + }) + }, + [setMode], + ) + const handleSuggestionClickInRow = useCallback( - (answer: string, event?: React.MouseEvent) => { + (suggestion: SuggestionItem, event?: React.MouseEvent) => { + // Check if we need to switch modes + if (suggestion.mode) { + // Only switch modes if it's a manual click (event exists) or auto-approval is allowed + const isManualClick = !!event + if (isManualClick || alwaysAllowModeSwitch) { + // Switch mode without waiting + switchToMode(suggestion.mode) + } + } + if (event?.shiftKey) { // Always append to existing text, don't overwrite setInputValue((currentValue) => { - return currentValue !== "" ? `${currentValue} \n${answer}` : answer + return currentValue !== "" ? `${currentValue} \n${suggestion.answer}` : suggestion.answer }) } else { - handleSendMessage(answer, []) + handleSendMessage(suggestion.answer, []) } }, - [handleSendMessage, setInputValue], // setInputValue is stable, handleSendMessage depends on clineAsk + [handleSendMessage, setInputValue, switchToMode, alwaysAllowModeSwitch], ) const handleBatchFileResponse = useCallback((response: { [key: string]: boolean }) => { @@ -1308,11 +1333,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction m.slug === mode) const nextModeIndex = (currentModeIndex + 1) % allModes.length // Update local state and notify extension to sync mode change - setMode(allModes[nextModeIndex].slug) - vscode.postMessage({ - type: "mode", - text: allModes[nextModeIndex].slug, - }) - }, [mode, setMode, customModes]) + switchToMode(allModes[nextModeIndex].slug) + }, [mode, customModes, switchToMode]) // Add keyboard event handler const handleKeyDown = useCallback( diff --git a/webview-ui/src/components/chat/FollowUpSuggest.tsx b/webview-ui/src/components/chat/FollowUpSuggest.tsx index 3362f9a7eb..73fbfcde87 100644 --- a/webview-ui/src/components/chat/FollowUpSuggest.tsx +++ b/webview-ui/src/components/chat/FollowUpSuggest.tsx @@ -2,7 +2,6 @@ import { useCallback, useEffect, useState } from "react" import { Edit } from "lucide-react" import { Button, StandardTooltip } from "@/components/ui" -import { vscode } from "@/utils/vscode" import { useAppTranslation } from "@src/i18n/TranslationContext" import { useExtensionState } from "@src/context/ExtensionStateContext" @@ -12,8 +11,8 @@ const DEFAULT_FOLLOWUP_TIMEOUT_MS = 60000 const COUNTDOWN_INTERVAL_MS = 1000 interface FollowUpSuggestProps { - suggestions?: (string | SuggestionItem)[] - onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void + suggestions?: SuggestionItem[] + onSuggestionClick?: (suggestion: SuggestionItem, event?: React.MouseEvent) => void ts: number onUnmount?: () => void } @@ -67,18 +66,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o onUnmount, ]) const handleSuggestionClick = useCallback( - (suggestion: string | SuggestionItem, event: React.MouseEvent) => { - const suggestionText = typeof suggestion === "string" ? suggestion : suggestion.answer - const mode = typeof suggestion === "object" ? suggestion.mode : undefined - - // If there's a mode switch and it's not a shift-click (which just copies to input), switch modes first - if (mode && !event.shiftKey) { - vscode.postMessage({ - type: "mode", - text: mode, - }) - } - + (suggestion: SuggestionItem, event: React.MouseEvent) => { // Mark a suggestion as selected if it's not a shift-click (which just copies to input) if (!event.shiftKey) { setSuggestionSelected(true) @@ -87,7 +75,9 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o onUnmount?.() } - onSuggestionClick?.(suggestionText, event) + // Pass the suggestion object to the parent component + // The parent component will handle mode switching if needed + onSuggestionClick?.(suggestion, event) }, [onSuggestionClick, onUnmount], ) @@ -100,18 +90,16 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o return (
{suggestions.map((suggestion, index) => { - const suggestionText = typeof suggestion === "string" ? suggestion : suggestion.answer - const mode = typeof suggestion === "object" ? suggestion.mode : undefined const isFirstSuggestion = index === 0 return ( -
+
- {mode && ( + {suggestion.mode && (
- {mode} + {suggestion.mode}
)} @@ -132,7 +120,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o onClick={(e) => { e.stopPropagation() // Simulate shift-click by directly calling the handler with shiftKey=true. - onSuggestionClick?.(suggestionText, { ...e, shiftKey: true }) + onSuggestionClick?.(suggestion, { ...e, shiftKey: true }) }}> diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json index 6b24d0724e..74f3c5b972 100644 --- a/webview-ui/src/i18n/locales/ca/chat.json +++ b/webview-ui/src/i18n/locales/ca/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Copiar a l'entrada (o Shift + clic)", - "autoSelectCountdown": "Selecció automàtica en {{count}}s" + "autoSelectCountdown": "Selecció automàtica en {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} publicat", diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json index dd4f640b91..c944ff1afd 100644 --- a/webview-ui/src/i18n/locales/de/chat.json +++ b/webview-ui/src/i18n/locales/de/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "In Eingabefeld kopieren (oder Shift + Klick)", - "autoSelectCountdown": "Automatische Auswahl in {{count}}s" + "autoSelectCountdown": "Automatische Auswahl in {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} veröffentlicht", diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json index 308ca6e63e..838a4b4e52 100644 --- a/webview-ui/src/i18n/locales/en/chat.json +++ b/webview-ui/src/i18n/locales/en/chat.json @@ -258,7 +258,8 @@ }, "followUpSuggest": { "copyToInput": "Copy to input (same as shift + click)", - "autoSelectCountdown": "Auto-selecting in {{count}}s" + "autoSelectCountdown": "Auto-selecting in {{count}}s", + "countdownDisplay": "{{count}}s" }, "browser": { "rooWantsToUse": "Roo wants to use the browser:", diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json index 93a8cc1ec0..269f9a12f7 100644 --- a/webview-ui/src/i18n/locales/es/chat.json +++ b/webview-ui/src/i18n/locales/es/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Copiar a la entrada (o Shift + clic)", - "autoSelectCountdown": "Selección automática en {{count}}s" + "autoSelectCountdown": "Selección automática en {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} publicado", diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json index 8f4d4e4240..3eaf0692f9 100644 --- a/webview-ui/src/i18n/locales/fr/chat.json +++ b/webview-ui/src/i18n/locales/fr/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Copier vers l'entrée (ou Shift + clic)", - "autoSelectCountdown": "Sélection automatique dans {{count}}s" + "autoSelectCountdown": "Sélection automatique dans {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} est sortie", diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json index 44017b937c..2f99ab36a3 100644 --- a/webview-ui/src/i18n/locales/hi/chat.json +++ b/webview-ui/src/i18n/locales/hi/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "इनपुट में कॉपी करें (या Shift + क्लिक)", - "autoSelectCountdown": "{{count}}s में स्वचालित रूप से चयन हो रहा है" + "autoSelectCountdown": "{{count}}s में स्वचालित रूप से चयन हो रहा है", + "countdownDisplay": "{{count}}सेकंड" }, "announcement": { "title": "🎉 Roo Code {{version}} रिलीज़ हुआ", diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json index ffb05a90a9..0c8ed69279 100644 --- a/webview-ui/src/i18n/locales/id/chat.json +++ b/webview-ui/src/i18n/locales/id/chat.json @@ -264,7 +264,8 @@ }, "followUpSuggest": { "copyToInput": "Salin ke input (sama dengan shift + klik)", - "autoSelectCountdown": "Pemilihan otomatis dalam {{count}}d" + "autoSelectCountdown": "Pemilihan otomatis dalam {{count}}dtk", + "countdownDisplay": "{{count}}dtk" }, "browser": { "rooWantsToUse": "Roo ingin menggunakan browser:", diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json index 8dca230d2f..fd3680f968 100644 --- a/webview-ui/src/i18n/locales/it/chat.json +++ b/webview-ui/src/i18n/locales/it/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Copia nell'input (o Shift + clic)", - "autoSelectCountdown": "Selezione automatica in {{count}}s" + "autoSelectCountdown": "Selezione automatica in {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Rilasciato Roo Code {{version}}", diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json index 3257fc66c8..1fe357d973 100644 --- a/webview-ui/src/i18n/locales/ja/chat.json +++ b/webview-ui/src/i18n/locales/ja/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "入力欄にコピー(またはShift + クリック)", - "autoSelectCountdown": "{{count}}秒後に自動選択します" + "autoSelectCountdown": "{{count}}秒後に自動選択します", + "countdownDisplay": "{{count}}秒" }, "announcement": { "title": "🎉 Roo Code {{version}} リリース", diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json index 7f1132471c..5e46b95dee 100644 --- a/webview-ui/src/i18n/locales/ko/chat.json +++ b/webview-ui/src/i18n/locales/ko/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "입력창에 복사 (또는 Shift + 클릭)", - "autoSelectCountdown": "{{count}}초 후 자동 선택" + "autoSelectCountdown": "{{count}}초 후 자동 선택", + "countdownDisplay": "{{count}}초" }, "announcement": { "title": "🎉 Roo Code {{version}} 출시", diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json index c932e61e4c..0863f0e497 100644 --- a/webview-ui/src/i18n/locales/nl/chat.json +++ b/webview-ui/src/i18n/locales/nl/chat.json @@ -245,7 +245,8 @@ }, "followUpSuggest": { "copyToInput": "Kopiëren naar invoer (zelfde als shift + klik)", - "autoSelectCountdown": "Automatische selectie in {{count}}s" + "autoSelectCountdown": "Automatische selectie in {{count}}s", + "countdownDisplay": "{{count}}s" }, "browser": { "rooWantsToUse": "Roo wil de browser gebruiken:", diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json index 72945ce784..df042806bf 100644 --- a/webview-ui/src/i18n/locales/pl/chat.json +++ b/webview-ui/src/i18n/locales/pl/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Kopiuj do pola wprowadzania (lub Shift + kliknięcie)", - "autoSelectCountdown": "Automatyczny wybór za {{count}}s" + "autoSelectCountdown": "Automatyczny wybór za {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} wydany", diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json index a4b851b1a6..f77ace0249 100644 --- a/webview-ui/src/i18n/locales/pt-BR/chat.json +++ b/webview-ui/src/i18n/locales/pt-BR/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Copiar para entrada (ou Shift + clique)", - "autoSelectCountdown": "Seleção automática em {{count}}s" + "autoSelectCountdown": "Seleção automática em {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} Lançado", diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json index ee22201e06..4cf6b3937d 100644 --- a/webview-ui/src/i18n/locales/ru/chat.json +++ b/webview-ui/src/i18n/locales/ru/chat.json @@ -245,7 +245,8 @@ }, "followUpSuggest": { "copyToInput": "Скопировать во ввод (то же, что shift + клик)", - "autoSelectCountdown": "Автовыбор через {{count}}с" + "autoSelectCountdown": "Автовыбор через {{count}}с", + "countdownDisplay": "{{count}}с" }, "browser": { "rooWantsToUse": "Roo хочет использовать браузер:", diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json index 98b1eecd5c..e0a6bdd701 100644 --- a/webview-ui/src/i18n/locales/tr/chat.json +++ b/webview-ui/src/i18n/locales/tr/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Giriş alanına kopyala (veya Shift + tıklama)", - "autoSelectCountdown": "{{count}}s içinde otomatik seçilecek" + "autoSelectCountdown": "{{count}}s içinde otomatik seçilecek", + "countdownDisplay": "{{count}}sn" }, "announcement": { "title": "🎉 Roo Code {{version}} Yayınlandı", diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json index 88c310d249..f936bcd56f 100644 --- a/webview-ui/src/i18n/locales/vi/chat.json +++ b/webview-ui/src/i18n/locales/vi/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "Sao chép vào ô nhập liệu (hoặc Shift + nhấp chuột)", - "autoSelectCountdown": "Tự động chọn sau {{count}}s" + "autoSelectCountdown": "Tự động chọn sau {{count}}s", + "countdownDisplay": "{{count}}s" }, "announcement": { "title": "🎉 Roo Code {{version}} Đã phát hành", diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json index 4d5f791358..6b3b40c2d6 100644 --- a/webview-ui/src/i18n/locales/zh-CN/chat.json +++ b/webview-ui/src/i18n/locales/zh-CN/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "复制到输入框(或按住Shift点击)", - "autoSelectCountdown": "{{count}}秒后自动选择" + "autoSelectCountdown": "{{count}}秒后自动选择", + "countdownDisplay": "{{count}}秒" }, "announcement": { "title": "🎉 Roo Code {{version}} 已发布", diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json index 675cb3d2c5..ac7688adde 100644 --- a/webview-ui/src/i18n/locales/zh-TW/chat.json +++ b/webview-ui/src/i18n/locales/zh-TW/chat.json @@ -235,7 +235,8 @@ }, "followUpSuggest": { "copyToInput": "複製到輸入框(或按住 Shift 並點選)", - "autoSelectCountdown": "{{count}}秒後自動選擇" + "autoSelectCountdown": "{{count}}秒後自動選擇", + "countdownDisplay": "{{count}}秒" }, "announcement": { "title": "🎉 Roo Code {{version}} 已發布",