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

This commit is contained in:
ShayBC 2025-03-01 16:30:46 +02:00
parent 41ddb7d583
commit 997f7bbe8a
2 changed files with 25 additions and 37 deletions

View file

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

View file

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