Browse Source

added approve finish task button and auto approve button for subtasks

ShayBC 1 year ago
parent
commit
1456db9502

+ 24 - 2
src/core/Cline.ts

@@ -1414,6 +1414,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(
@@ -2941,8 +2953,13 @@ export class Cline {
 									if (lastMessage && lastMessage.ask !== "command") {
 										// 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)
+										// telemetryService.captureTaskCompleted(this.taskId)
 										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()
@@ -2966,8 +2983,13 @@ export class Cline {
 									commandResult = execCommandResult
 								} else {
 									await this.say("completion_result", result, undefined, false)
-									telemetryService.captureTaskCompleted(this.taskId)
+									// telemetryService.captureTaskCompleted(this.taskId)
 									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()

+ 3 - 0
src/shared/ExtensionMessage.ts

@@ -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

+ 1 - 0
src/shared/WebviewMessage.ts

@@ -48,6 +48,7 @@ export interface WebviewMessage {
 		| "alwaysAllowBrowser"
 		| "alwaysAllowMcp"
 		| "alwaysAllowModeSwitch"
+		| "alwaysAllowFinishTask"
 		| "playSound"
 		| "soundEnabled"
 		| "soundVolume"

+ 16 - 0
webview-ui/src/components/chat/AutoApproveMenu.tsx

@@ -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: "Finish subtasks tasks",
+			shortName: "Finish",
+			enabled: alwaysAllowFinishTask ?? false,
+			description: "Allows automatic completeing a sub-task without requiring 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,
 	}
 

+ 12 - 0
webview-ui/src/components/chat/ChatRow.tsx

@@ -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
 		}

+ 4 - 1
webview-ui/src/components/chat/ChatView.tsx

@@ -61,6 +61,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 		setMode,
 		autoApprovalEnabled,
 		alwaysAllowModeSwitch,
+		alwaysAllowFinishTask,
 		customModes,
 		telemetrySetting,
 	} = useExtensionState()
@@ -642,7 +643,8 @@ 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 === "finishTask")
 			)
 		},
 		[
@@ -657,6 +659,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
 			alwaysAllowMcp,
 			isMcpToolAlwaysAllowed,
 			alwaysAllowModeSwitch,
+			alwaysAllowFinishTask,
 		],
 	)
 

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

@@ -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 })),