mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Merge pull request #1491 from shaybc/sbc_subtasks_approve_btn
Sbc subtasks approve button
This commit is contained in:
commit
e945dcf94f
11 changed files with 90 additions and 13 deletions
|
|
@ -1417,6 +1417,18 @@ export class Cline {
|
|||
return true
|
||||
}
|
||||
|
||||
const askFinishSubTaskApproval = async () => {
|
||||
// ask the user to approve this task has completed, and he has reviewd it, and we can declare task is finished
|
||||
// and return control to the parent task to continue running the rest of the sub-tasks
|
||||
const toolMessage = JSON.stringify({
|
||||
tool: "finishTask",
|
||||
content:
|
||||
"Task completed! You can review the results and suggest any corrections or next steps. If everything looks good, confirm to continue with the next task.",
|
||||
})
|
||||
|
||||
return await askApproval("tool", toolMessage)
|
||||
}
|
||||
|
||||
const handleError = async (action: string, error: Error) => {
|
||||
const errorString = `Error ${action}: ${JSON.stringify(serializeError(error))}`
|
||||
await this.say(
|
||||
|
|
@ -2945,13 +2957,6 @@ export class Cline {
|
|||
// havent sent a command message yet so first send completion_result then command
|
||||
await this.say("completion_result", result, undefined, false)
|
||||
telemetryService.captureTaskCompleted(this.taskId)
|
||||
if (this.isSubTask) {
|
||||
// tell the provider to remove the current subtask and resume the previous task in the stack
|
||||
await this.providerRef
|
||||
.deref()
|
||||
?.finishSubTask(`Task complete: ${lastMessage?.text}`)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// complete command message
|
||||
|
|
@ -2970,13 +2975,17 @@ export class Cline {
|
|||
} else {
|
||||
await this.say("completion_result", result, undefined, false)
|
||||
telemetryService.captureTaskCompleted(this.taskId)
|
||||
if (this.isSubTask) {
|
||||
// tell the provider to remove the current subtask and resume the previous task in the stack
|
||||
await this.providerRef
|
||||
.deref()
|
||||
?.finishSubTask(`Task complete: ${lastMessage?.text}`)
|
||||
}
|
||||
|
||||
if (this.isSubTask) {
|
||||
const didApprove = await askFinishSubTaskApproval()
|
||||
if (!didApprove) {
|
||||
break
|
||||
}
|
||||
|
||||
// tell the provider to remove the current subtask and resume the previous task in the stack
|
||||
await this.providerRef.deref()?.finishSubTask(`Task complete: ${lastMessage?.text}`)
|
||||
break
|
||||
}
|
||||
|
||||
// we already sent completion_result says, an empty string asks relinquishes control over button and field
|
||||
|
|
|
|||
|
|
@ -984,6 +984,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
await this.updateGlobalState("alwaysAllowModeSwitch", message.bool)
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
case "alwaysAllowFinishTask":
|
||||
await this.updateGlobalState("alwaysAllowFinishTask", message.bool)
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
case "askResponse":
|
||||
this.getCurrentCline()?.handleWebviewAskResponse(
|
||||
message.askResponse!,
|
||||
|
|
@ -2177,6 +2181,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
alwaysAllowBrowser,
|
||||
alwaysAllowMcp,
|
||||
alwaysAllowModeSwitch,
|
||||
alwaysAllowFinishTask,
|
||||
soundEnabled,
|
||||
diffEnabled,
|
||||
enableCheckpoints,
|
||||
|
|
@ -2224,6 +2229,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
alwaysAllowBrowser: alwaysAllowBrowser ?? false,
|
||||
alwaysAllowMcp: alwaysAllowMcp ?? false,
|
||||
alwaysAllowModeSwitch: alwaysAllowModeSwitch ?? false,
|
||||
alwaysAllowFinishTask: alwaysAllowFinishTask ?? false,
|
||||
uriScheme: vscode.env.uriScheme,
|
||||
currentTaskItem: this.getCurrentCline()?.taskId
|
||||
? (taskHistory || []).find((item: HistoryItem) => item.id === this.getCurrentCline()?.taskId)
|
||||
|
|
@ -2385,6 +2391,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
alwaysAllowBrowser: stateValues.alwaysAllowBrowser ?? false,
|
||||
alwaysAllowMcp: stateValues.alwaysAllowMcp ?? false,
|
||||
alwaysAllowModeSwitch: stateValues.alwaysAllowModeSwitch ?? false,
|
||||
alwaysAllowFinishTask: stateValues.alwaysAllowFinishTask ?? false,
|
||||
taskHistory: stateValues.taskHistory,
|
||||
allowedCommands: stateValues.allowedCommands,
|
||||
soundEnabled: stateValues.soundEnabled ?? false,
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ export interface ExtensionState {
|
|||
alwaysAllowMcp?: boolean
|
||||
alwaysApproveResubmit?: boolean
|
||||
alwaysAllowModeSwitch?: boolean
|
||||
alwaysAllowFinishTask?: boolean
|
||||
browserToolEnabled?: boolean
|
||||
requestDelaySeconds: number
|
||||
rateLimitSeconds: number // Minimum time between successive requests (0 = disabled)
|
||||
|
|
@ -168,6 +169,7 @@ export type ClineAsk =
|
|||
| "mistake_limit_reached"
|
||||
| "browser_action_launch"
|
||||
| "use_mcp_server"
|
||||
| "finishTask"
|
||||
|
||||
export type ClineSay =
|
||||
| "task"
|
||||
|
|
@ -207,6 +209,7 @@ export interface ClineSayTool {
|
|||
| "searchFiles"
|
||||
| "switchMode"
|
||||
| "newTask"
|
||||
| "finishTask"
|
||||
path?: string
|
||||
diff?: string
|
||||
content?: string
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export interface WebviewMessage {
|
|||
| "alwaysAllowBrowser"
|
||||
| "alwaysAllowMcp"
|
||||
| "alwaysAllowModeSwitch"
|
||||
| "alwaysAllowFinishTask"
|
||||
| "playSound"
|
||||
| "soundEnabled"
|
||||
| "soundVolume"
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export const GLOBAL_STATE_KEYS = [
|
|||
"alwaysAllowBrowser",
|
||||
"alwaysAllowMcp",
|
||||
"alwaysAllowModeSwitch",
|
||||
"alwaysAllowFinishTask",
|
||||
"taskHistory",
|
||||
"openAiBaseUrl",
|
||||
"openAiModelId",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
setAlwaysAllowMcp,
|
||||
alwaysAllowModeSwitch,
|
||||
setAlwaysAllowModeSwitch,
|
||||
alwaysAllowFinishTask,
|
||||
setAlwaysAllowFinishTask,
|
||||
alwaysApproveResubmit,
|
||||
setAlwaysApproveResubmit,
|
||||
autoApprovalEnabled,
|
||||
|
|
@ -81,6 +83,13 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
description:
|
||||
"Allows automatic switching between different AI modes and creating new tasks without requiring approval.",
|
||||
},
|
||||
{
|
||||
id: "finishTask",
|
||||
label: "Continue to next task",
|
||||
shortName: "Continue",
|
||||
enabled: alwaysAllowFinishTask ?? false,
|
||||
description: "Allow tasks to end execution and continue to the next task, without user review or approval.",
|
||||
},
|
||||
{
|
||||
id: "retryRequests",
|
||||
label: "Retry failed requests",
|
||||
|
|
@ -136,6 +145,12 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: newValue })
|
||||
}, [alwaysAllowModeSwitch, setAlwaysAllowModeSwitch])
|
||||
|
||||
const handleFinishTaskChange = useCallback(() => {
|
||||
const newValue = !(alwaysAllowFinishTask ?? false)
|
||||
setAlwaysAllowFinishTask(newValue)
|
||||
vscode.postMessage({ type: "alwaysAllowFinishTask", bool: newValue })
|
||||
}, [alwaysAllowFinishTask, setAlwaysAllowFinishTask])
|
||||
|
||||
const handleRetryChange = useCallback(() => {
|
||||
const newValue = !(alwaysApproveResubmit ?? false)
|
||||
setAlwaysApproveResubmit(newValue)
|
||||
|
|
@ -150,6 +165,7 @@ const AutoApproveMenu = ({ style }: AutoApproveMenuProps) => {
|
|||
useBrowser: handleBrowserChange,
|
||||
useMcp: handleMcpChange,
|
||||
switchModes: handleModeSwitchChange,
|
||||
finishTask: handleFinishTaskChange,
|
||||
retryRequests: handleRetryChange,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -459,6 +459,18 @@ export const ChatRowContent = ({
|
|||
</div>
|
||||
</>
|
||||
)
|
||||
case "finishTask":
|
||||
return (
|
||||
<>
|
||||
<div style={headerStyle}>
|
||||
{toolIcon("new-file")}
|
||||
<span style={{ fontWeight: "bold" }}>Roo wants to finish this task</span>
|
||||
</div>
|
||||
<div style={{ paddingLeft: "26px", marginTop: "4px" }}>
|
||||
<code>{tool.content}</code>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||
setMode,
|
||||
autoApprovalEnabled,
|
||||
alwaysAllowModeSwitch,
|
||||
alwaysAllowFinishTask,
|
||||
customModes,
|
||||
telemetrySetting,
|
||||
} = useExtensionState()
|
||||
|
|
@ -148,6 +149,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||
setPrimaryButtonText("Save")
|
||||
setSecondaryButtonText("Reject")
|
||||
break
|
||||
case "finishTask":
|
||||
setPrimaryButtonText("Approve & Continue to the next Task")
|
||||
setSecondaryButtonText(undefined)
|
||||
break
|
||||
default:
|
||||
setPrimaryButtonText("Approve")
|
||||
setSecondaryButtonText("Reject")
|
||||
|
|
@ -642,7 +647,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||
(alwaysAllowModeSwitch &&
|
||||
message.ask === "tool" &&
|
||||
(JSON.parse(message.text || "{}")?.tool === "switchMode" ||
|
||||
JSON.parse(message.text || "{}")?.tool === "newTask"))
|
||||
JSON.parse(message.text || "{}")?.tool === "newTask")) ||
|
||||
(alwaysAllowFinishTask &&
|
||||
message.ask === "tool" &&
|
||||
JSON.parse(message.text || "{}")?.tool === "finishTask")
|
||||
)
|
||||
},
|
||||
[
|
||||
|
|
@ -657,6 +665,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||
alwaysAllowMcp,
|
||||
isMcpToolAlwaysAllowed,
|
||||
alwaysAllowModeSwitch,
|
||||
alwaysAllowFinishTask,
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ type AutoApproveSettingsProps = HTMLAttributes<HTMLDivElement> & {
|
|||
requestDelaySeconds: number
|
||||
alwaysAllowMcp?: boolean
|
||||
alwaysAllowModeSwitch?: boolean
|
||||
alwaysAllowFinishTask?: boolean
|
||||
alwaysAllowExecute?: boolean
|
||||
allowedCommands?: string[]
|
||||
setCachedStateField: SetCachedStateField<keyof ExtensionStateContextType>
|
||||
|
|
@ -32,6 +33,7 @@ export const AutoApproveSettings = ({
|
|||
requestDelaySeconds,
|
||||
alwaysAllowMcp,
|
||||
alwaysAllowModeSwitch,
|
||||
alwaysAllowFinishTask,
|
||||
alwaysAllowExecute,
|
||||
allowedCommands,
|
||||
setCachedStateField,
|
||||
|
|
@ -180,6 +182,18 @@ export const AutoApproveSettings = ({
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<VSCodeCheckbox
|
||||
checked={alwaysAllowFinishTask}
|
||||
onChange={(e: any) => setCachedStateField("alwaysAllowFinishTask", e.target.checked)}>
|
||||
<span className="font-medium">Always approve finish & continue to next task</span>
|
||||
</VSCodeCheckbox>
|
||||
<p className="text-vscode-descriptionForeground text-sm mt-0">
|
||||
Automatically approve tasks to finish execution and continue to the next task, without user
|
||||
review or approval
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<VSCodeCheckbox
|
||||
checked={alwaysAllowExecute}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
|
|||
alwaysAllowExecute,
|
||||
alwaysAllowMcp,
|
||||
alwaysAllowModeSwitch,
|
||||
alwaysAllowFinishTask,
|
||||
alwaysAllowWrite,
|
||||
alwaysApproveResubmit,
|
||||
browserToolEnabled,
|
||||
|
|
@ -184,6 +185,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
|
|||
vscode.postMessage({ type: "currentApiConfigName", text: currentApiConfigName })
|
||||
vscode.postMessage({ type: "updateExperimental", values: experiments })
|
||||
vscode.postMessage({ type: "alwaysAllowModeSwitch", bool: alwaysAllowModeSwitch })
|
||||
vscode.postMessage({ type: "alwaysAllowFinishTask", bool: alwaysAllowFinishTask })
|
||||
vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration })
|
||||
vscode.postMessage({ type: "telemetrySetting", text: telemetrySetting })
|
||||
setChangeDetected(false)
|
||||
|
|
@ -364,6 +366,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
|
|||
requestDelaySeconds={requestDelaySeconds}
|
||||
alwaysAllowMcp={alwaysAllowMcp}
|
||||
alwaysAllowModeSwitch={alwaysAllowModeSwitch}
|
||||
alwaysAllowFinishTask={alwaysAllowFinishTask}
|
||||
alwaysAllowExecute={alwaysAllowExecute}
|
||||
allowedCommands={allowedCommands}
|
||||
setCachedStateField={setCachedStateField}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export interface ExtensionStateContextType extends ExtensionState {
|
|||
setAlwaysAllowBrowser: (value: boolean) => void
|
||||
setAlwaysAllowMcp: (value: boolean) => void
|
||||
setAlwaysAllowModeSwitch: (value: boolean) => void
|
||||
setAlwaysAllowFinishTask: (value: boolean) => void
|
||||
setBrowserToolEnabled: (value: boolean) => void
|
||||
setShowRooIgnoredFiles: (value: boolean) => void
|
||||
setShowAnnouncement: (value: boolean) => void
|
||||
|
|
@ -247,6 +248,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
setAlwaysAllowBrowser: (value) => setState((prevState) => ({ ...prevState, alwaysAllowBrowser: value })),
|
||||
setAlwaysAllowMcp: (value) => setState((prevState) => ({ ...prevState, alwaysAllowMcp: value })),
|
||||
setAlwaysAllowModeSwitch: (value) => setState((prevState) => ({ ...prevState, alwaysAllowModeSwitch: value })),
|
||||
setAlwaysAllowFinishTask: (value) => setState((prevState) => ({ ...prevState, alwaysAllowFinishTask: value })),
|
||||
setShowAnnouncement: (value) => setState((prevState) => ({ ...prevState, shouldShowAnnouncement: value })),
|
||||
setAllowedCommands: (value) => setState((prevState) => ({ ...prevState, allowedCommands: value })),
|
||||
setSoundEnabled: (value) => setState((prevState) => ({ ...prevState, soundEnabled: value })),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue