Просмотр исходного кода

Improve error handling and messaging in Cline class and ClineProvider, removed unnecessary resume_task ask, added abandond=true flag to the abort() call. no more error in log due to resume task

ShayBC 10 месяцев назад
Родитель
Сommit
997f7bbe8a
2 измененных файлов с 25 добавлено и 37 удалено
  1. 17 25
      src/core/Cline.ts
  2. 8 12
      src/core/webview/ClineProvider.ts

+ 17 - 25
src/core/Cline.ts

@@ -374,7 +374,7 @@ export class Cline {
 	): Promise<{ response: ClineAskResponse; text?: string; images?: string[] }> {
 		// If this Cline instance was aborted by the provider, then the only thing keeping us alive is a promise still running in the background, in which case we don't want to send its result to the webview as it is attached to a new instance of Cline now. So we can safely ignore the result of any active promises, and this class will be deallocated. (Although we set Cline = undefined in provider, that simply removes the reference to this instance, but the instance is still alive until this promise resolves or rejects.)
 		if (this.abort) {
-			throw new Error("Roo Code instance aborted")
+			throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#1)`)
 		}
 		let askTs: number
 		if (partial !== undefined) {
@@ -392,7 +392,7 @@ export class Cline {
 					await this.providerRef
 						.deref()
 						?.postMessageToWebview({ type: "partialMessage", partialMessage: lastMessage })
-					throw new Error("Current ask promise was ignored 1")
+					throw new Error("Current ask promise was ignored (#1)")
 				} else {
 					// this is a new partial message, so add it with partial state
 					// this.askResponse = undefined
@@ -402,7 +402,7 @@ export class Cline {
 					this.lastMessageTs = askTs
 					await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text, partial })
 					await this.providerRef.deref()?.postStateToWebview()
-					throw new Error("Current ask promise was ignored 2")
+					throw new Error("Current ask promise was ignored (#2)")
 				}
 			} else {
 				// partial=false means its a complete version of a previously partial message
@@ -476,7 +476,7 @@ export class Cline {
 		checkpoint?: Record<string, unknown>,
 	): Promise<undefined> {
 		if (this.abort) {
-			throw new Error("Roo Code instance aborted")
+			throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#2)`)
 		}
 
 		if (partial !== undefined) {
@@ -568,8 +568,9 @@ export class Cline {
 		// release this Cline instance from paused state
 		this.isPaused = false
 
+		// fake an answer from the subtask that it has completed running and this is the result of what it has done
+		// add the message to the chat history and to the webview ui
 		try {
-			// This adds the completion message to conversation history
 			await this.say("text", `${lastMessage ?? "Please continue to the next task."}`)
 
 			await this.addToApiConversationHistory({
@@ -587,21 +588,6 @@ export class Cline {
 				?.log(`Error failed to add reply from subtast into conversation of parent task, error: ${error}`)
 			throw error
 		}
-
-		try {
-			// Resume parent task
-			await this.ask("resume_task")
-		} catch (error) {
-			if (error.message === "Current ask promise was ignored") {
-				// ignore the ignored promise, since it was performed by launching a subtask and it probably took more then 1 sec,
-				// also set the didAlreadyUseTool flag to indicate that the tool was already used, and there is no need to relaunch it
-				this.didAlreadyUseTool = true
-			} else {
-				// Handle error appropriately
-				console.error("Failed to resume task:", error)
-				throw error
-			}
-		}
 	}
 
 	private async resumeTaskFromHistory() {
@@ -1182,7 +1168,7 @@ export class Cline {
 
 	async presentAssistantMessage() {
 		if (this.abort) {
-			throw new Error("Roo Code instance aborted")
+			throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#3)`)
 		}
 
 		if (this.presentAssistantMessageLocked) {
@@ -2819,7 +2805,10 @@ export class Cline {
 										await this.say("completion_result", result, undefined, false)
 										if (this.isSubTask) {
 											// tell the provider to remove the current subtask and resume the previous task in the stack
-											this.providerRef.deref()?.finishSubTask(lastMessage?.text)
+											await this.providerRef
+												.deref()
+												?.finishSubTask(`new_task finished successfully! ${lastMessage?.text}`)
+											break
 										}
 									}
 
@@ -2840,7 +2829,10 @@ export class Cline {
 									await this.say("completion_result", result, undefined, false)
 									if (this.isSubTask) {
 										// tell the provider to remove the current subtask and resume the previous task in the stack
-										this.providerRef.deref()?.finishSubTask(lastMessage?.text)
+										await this.providerRef
+											.deref()
+											?.finishSubTask(`new_task finished successfully! ${lastMessage?.text}`)
+										break
 									}
 								}
 
@@ -2936,7 +2928,7 @@ export class Cline {
 		includeFileDetails: boolean = false,
 	): Promise<boolean> {
 		if (this.abort) {
-			throw new Error("Roo Code instance aborted")
+			throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#4)`)
 		}
 
 		if (this.consecutiveMistakeCount >= 3) {
@@ -3178,7 +3170,7 @@ export class Cline {
 
 			// need to call here in case the stream was aborted
 			if (this.abort || this.abandoned) {
-				throw new Error("Roo Code instance aborted")
+				throw new Error(`Task: ${this.taskNumber} Roo Code instance aborted (#5)`)
 			}
 
 			this.didCompleteReadingStream = true

+ 8 - 12
src/core/webview/ClineProvider.ts

@@ -152,7 +152,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 					const removedTaskNumber = clineToBeRemoved.getTaskNumber()
 
 					try {
-						await clineToBeRemoved.abortTask()
+						// abort the running task and set isAbandoned to true so all running promises will exit as well
+						await clineToBeRemoved.abortTask(true)
 					} catch (abortError) {
 						this.log(`Error failed aborting task ${removedTaskNumber}: ${abortError.message}`)
 					}
@@ -223,7 +224,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 			// remove the last cline instance from the stack (this is the finished sub task)
 			await this.removeClineFromStack()
 			// resume the last cline instance in the stack (if it exists - this is the 'parnt' calling task)
-			this.getCurrentCline()?.resumePausedTask(`new_task finished successfully! ${lastMessage}`)
+			this.getCurrentCline()?.resumePausedTask(lastMessage)
 		} catch (error) {
 			this.log(`Error in finishSubTask: ${error.message}`)
 			throw error
@@ -923,13 +924,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 						)
 						break
 					case "clearTask":
-						// newTask will start a new task with a given task text, while clear task resets the current session and allows for a new task to be started
-						await this.removeClineFromStack()
-						// resume previouse task with subtask failed error
-						this.getCurrentCline()?.resumePausedTask(
+						// clear task resets the current session and allows for a new task to be started, if this session is a subtask - it allows the parent task to be resumed
+						await this.finishSubTask(
 							`new_task finished with an error!, it was stopped and canceled by the user.`,
 						)
-
 						await this.postStateToWebview()
 						break
 					case "didShowAnnouncement":
@@ -2087,11 +2085,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
 
 		// remove task from stack if it's the current task
 		if (id === this.getCurrentCline()?.taskId) {
-			await this.removeClineWithIdFromStack(id)
-			// resume previouse task with subtask failed error
-			this.getCurrentCline()?.resumePausedTask(
-				`new_task finished with an error!, it was stopped and delted by the user.`,
-			)
+			// if we found the taskid to delete - call finish to abort this task and allow a new task to be started,
+			// if we are deleting a subtask and parent task is still waiting for subtask to finish - it allows the parent to resume (this case should neve exist)
+			await this.finishSubTask(`new_task finished with an error!, it was stopped and delted by the user.`)
 		}
 
 		// delete task from the task history state