Skip to content

Commit 002ec11

Browse files
committed
added modes
1 parent 820a635 commit 002ec11

File tree

4 files changed

+49
-42
lines changed

4 files changed

+49
-42
lines changed

packages/types/src/followup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export interface FollowUpData {
99
/** The question being asked by the LLM */
1010
question?: string
1111
/** Array of suggested answers that the user can select */
12-
suggest?: Array<string | SuggestionItem>
12+
suggest?: Array<SuggestionItem>
1313
}
1414

1515
/**
@@ -35,7 +35,7 @@ export const suggestionItemSchema = z.object({
3535
*/
3636
export const followUpDataSchema = z.object({
3737
question: z.string().optional(),
38-
suggest: z.array(z.union([z.string(), suggestionItemSchema])).optional(),
38+
suggest: z.array(suggestionItemSchema).optional(),
3939
})
4040

4141
export type FollowUpDataType = z.infer<typeof followUpDataSchema>

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { ClineMessage } from "@roo-code/types"
1010
import { ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "@roo/ExtensionMessage"
1111
import { COMMAND_OUTPUT_STRING } from "@roo/combineCommandSequences"
1212
import { safeJsonParse } from "@roo/safeJsonParse"
13-
import { FollowUpData } from "@roo-code/types"
13+
import { FollowUpData, SuggestionItem } from "@roo-code/types"
1414

1515
import { useCopyToClipboard } from "@src/utils/clipboard"
1616
import { useExtensionState } from "@src/context/ExtensionStateContext"
@@ -49,7 +49,7 @@ interface ChatRowProps {
4949
isStreaming: boolean
5050
onToggleExpand: (ts: number) => void
5151
onHeightChange: (isTaller: boolean) => void
52-
onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void
52+
onSuggestionClick?: (suggestion: SuggestionItem, event?: React.MouseEvent) => void
5353
onBatchFileResponse?: (response: { [key: string]: boolean }) => void
5454
onFollowUpUnmount?: () => void
5555
}

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { ClineAsk, ClineMessage } from "@roo-code/types"
1515
import { ClineSayBrowserAction, ClineSayTool, ExtensionMessage } from "@roo/ExtensionMessage"
1616
import { McpServer, McpTool } from "@roo/mcp"
1717
import { findLast } from "@roo/array"
18-
import { FollowUpData } from "@roo-code/types"
18+
import { FollowUpData, SuggestionItem } from "@roo-code/types"
1919
import { combineApiRequests } from "@roo/combineApiRequests"
2020
import { combineCommandSequences } from "@roo/combineCommandSequences"
2121
import { getApiMetrics } from "@roo/getApiMetrics"
@@ -1197,18 +1197,43 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
11971197

11981198
const placeholderText = task ? t("chat:typeMessage") : t("chat:typeTask")
11991199

1200+
// Function to switch to a specific mode
1201+
const switchToMode = useCallback(
1202+
(modeSlug: string): void => {
1203+
// Update local state and notify extension to sync mode change
1204+
setMode(modeSlug)
1205+
1206+
// Send the mode switch message
1207+
vscode.postMessage({
1208+
type: "mode",
1209+
text: modeSlug,
1210+
})
1211+
},
1212+
[setMode],
1213+
)
1214+
12001215
const handleSuggestionClickInRow = useCallback(
1201-
(answer: string, event?: React.MouseEvent) => {
1216+
(suggestion: SuggestionItem, event?: React.MouseEvent) => {
1217+
// Check if we need to switch modes
1218+
if (suggestion.mode) {
1219+
// Only switch modes if it's a manual click (event exists) or auto-approval is allowed
1220+
const isManualClick = !!event
1221+
if (isManualClick || alwaysAllowModeSwitch) {
1222+
// Switch mode without waiting
1223+
switchToMode(suggestion.mode)
1224+
}
1225+
}
1226+
12021227
if (event?.shiftKey) {
12031228
// Always append to existing text, don't overwrite
12041229
setInputValue((currentValue) => {
1205-
return currentValue !== "" ? `${currentValue} \n${answer}` : answer
1230+
return currentValue !== "" ? `${currentValue} \n${suggestion.answer}` : suggestion.answer
12061231
})
12071232
} else {
1208-
handleSendMessage(answer, [])
1233+
handleSendMessage(suggestion.answer, [])
12091234
}
12101235
},
1211-
[handleSendMessage, setInputValue], // setInputValue is stable, handleSendMessage depends on clineAsk
1236+
[handleSendMessage, setInputValue, switchToMode, alwaysAllowModeSwitch],
12121237
)
12131238

12141239
const handleBatchFileResponse = useCallback((response: { [key: string]: boolean }) => {
@@ -1308,11 +1333,9 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13081333

13091334
// Get the first suggestion
13101335
const firstSuggestion = followUpData.suggest[0]
1311-
const suggestionText =
1312-
typeof firstSuggestion === "string" ? firstSuggestion : firstSuggestion.answer
13131336

13141337
// Handle the suggestion click
1315-
handleSuggestionClickInRow(suggestionText)
1338+
handleSuggestionClickInRow(firstSuggestion)
13161339
return
13171340
}
13181341
} else if (lastMessage.ask === "tool" && isWriteToolAction(lastMessage)) {
@@ -1365,12 +1388,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13651388
const currentModeIndex = allModes.findIndex((m) => m.slug === mode)
13661389
const nextModeIndex = (currentModeIndex + 1) % allModes.length
13671390
// Update local state and notify extension to sync mode change
1368-
setMode(allModes[nextModeIndex].slug)
1369-
vscode.postMessage({
1370-
type: "mode",
1371-
text: allModes[nextModeIndex].slug,
1372-
})
1373-
}, [mode, setMode, customModes])
1391+
switchToMode(allModes[nextModeIndex].slug)
1392+
}, [mode, customModes, switchToMode])
13741393

13751394
// Add keyboard event handler
13761395
const handleKeyDown = useCallback(

webview-ui/src/components/chat/FollowUpSuggest.tsx

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useCallback, useEffect, useState } from "react"
22
import { Edit } from "lucide-react"
33

44
import { Button, StandardTooltip } from "@/components/ui"
5-
import { vscode } from "@/utils/vscode"
65

76
import { useAppTranslation } from "@src/i18n/TranslationContext"
87
import { useExtensionState } from "@src/context/ExtensionStateContext"
@@ -12,8 +11,8 @@ const DEFAULT_FOLLOWUP_TIMEOUT_MS = 60000
1211
const COUNTDOWN_INTERVAL_MS = 1000
1312

1413
interface FollowUpSuggestProps {
15-
suggestions?: (string | SuggestionItem)[]
16-
onSuggestionClick?: (answer: string, event?: React.MouseEvent) => void
14+
suggestions?: SuggestionItem[]
15+
onSuggestionClick?: (suggestion: SuggestionItem, event?: React.MouseEvent) => void
1716
ts: number
1817
onUnmount?: () => void
1918
}
@@ -67,18 +66,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
6766
onUnmount,
6867
])
6968
const handleSuggestionClick = useCallback(
70-
(suggestion: string | SuggestionItem, event: React.MouseEvent) => {
71-
const suggestionText = typeof suggestion === "string" ? suggestion : suggestion.answer
72-
const mode = typeof suggestion === "object" ? suggestion.mode : undefined
73-
74-
// If there's a mode switch and it's not a shift-click (which just copies to input), switch modes first
75-
if (mode && !event.shiftKey) {
76-
vscode.postMessage({
77-
type: "mode",
78-
text: mode,
79-
})
80-
}
81-
69+
(suggestion: SuggestionItem, event: React.MouseEvent) => {
8270
// Mark a suggestion as selected if it's not a shift-click (which just copies to input)
8371
if (!event.shiftKey) {
8472
setSuggestionSelected(true)
@@ -87,7 +75,9 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
8775
onUnmount?.()
8876
}
8977

90-
onSuggestionClick?.(suggestionText, event)
78+
// Pass the suggestion object to the parent component
79+
// The parent component will handle mode switching if needed
80+
onSuggestionClick?.(suggestion, event)
9181
},
9282
[onSuggestionClick, onUnmount],
9383
)
@@ -100,18 +90,16 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
10090
return (
10191
<div className="flex mb-2 flex-col h-full gap-2">
10292
{suggestions.map((suggestion, index) => {
103-
const suggestionText = typeof suggestion === "string" ? suggestion : suggestion.answer
104-
const mode = typeof suggestion === "object" ? suggestion.mode : undefined
10593
const isFirstSuggestion = index === 0
10694

10795
return (
108-
<div key={`${suggestionText}-${ts}`} className="w-full relative group">
96+
<div key={`${suggestion.answer}-${ts}`} className="w-full relative group">
10997
<Button
11098
variant="outline"
11199
className="text-left whitespace-normal break-words w-full h-auto py-3 justify-start pr-8"
112100
onClick={(event) => handleSuggestionClick(suggestion, event)}
113-
aria-label={suggestionText}>
114-
{suggestionText}
101+
aria-label={suggestion.answer}>
102+
{suggestion.answer}
115103
{isFirstSuggestion && countdown !== null && !suggestionSelected && (
116104
<span
117105
className="ml-2 px-1.5 py-0.5 text-xs rounded-full bg-vscode-badge-background text-vscode-badge-foreground"
@@ -120,10 +108,10 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
120108
</span>
121109
)}
122110
</Button>
123-
{mode && (
111+
{suggestion.mode && (
124112
<div className="absolute bottom-0 right-0 text-[10px] bg-vscode-badge-background text-vscode-badge-foreground px-1 py-0.5 border border-vscode-badge-background flex items-center gap-0.5">
125113
<span className="codicon codicon-arrow-right" style={{ fontSize: "8px" }} />
126-
{mode}
114+
{suggestion.mode}
127115
</div>
128116
)}
129117
<StandardTooltip content={t("chat:followUpSuggest.copyToInput")}>
@@ -132,7 +120,7 @@ export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1, o
132120
onClick={(e) => {
133121
e.stopPropagation()
134122
// Simulate shift-click by directly calling the handler with shiftKey=true.
135-
onSuggestionClick?.(suggestionText, { ...e, shiftKey: true })
123+
onSuggestionClick?.(suggestion, { ...e, shiftKey: true })
136124
}}>
137125
<Button variant="ghost" size="icon">
138126
<Edit />

0 commit comments

Comments
 (0)