Skip to content

Commit 5c11f20

Browse files
committed
fix: resolve orchestrator subtask cancellation during API streaming error (#4896)
- Add setTimeout to prevent race condition when aborting streams - Enhance error logging with parent task ID for better debugging - Improve error handling to ensure parent task resumption - Make resumePausedTask more resilient to aborted states Fixes #4896
1 parent db334c1 commit 5c11f20

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

src/core/task/Task.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,14 @@ export class Task extends EventEmitter<ClineEvents> {
758758
// this is the result of what it has done add the message to the chat
759759
// history and to the webview ui.
760760
try {
761+
// Check if the task is aborted or abandoned before trying to add messages
762+
if (this.abort || this.abandoned) {
763+
this.providerRef
764+
.deref()
765+
?.log(`[subtasks] Parent task ${this.taskId} is aborted/abandoned, skipping resume message`)
766+
return
767+
}
768+
761769
await this.say("subtask_result", lastMessage)
762770

763771
await this.addToApiConversationHistory({
@@ -769,7 +777,8 @@ export class Task extends EventEmitter<ClineEvents> {
769777
.deref()
770778
?.log(`Error failed to add reply from subtask into conversation of parent task, error: ${error}`)
771779

772-
throw error
780+
// Don't throw the error - we still want the parent task to be unpaused
781+
// even if we couldn't add the message
773782
}
774783
}
775784

src/core/webview/webviewMessageHandler.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,21 @@ export const webviewMessageHandler = async (
204204
// Check if the current task actually has a parent task
205205
const currentTask = provider.getCurrentCline()
206206
if (currentTask && currentTask.parentTask) {
207-
await provider.finishSubTask(t("common:tasks.canceled"))
207+
// For subtasks, we need to ensure the parent task is resumed even if the subtask is in an error state
208+
try {
209+
// First abort the current subtask if it's still running
210+
if (currentTask.isStreaming || !currentTask.didFinishAbortingStream) {
211+
currentTask.abortTask()
212+
// Small delay to ensure abort signal is processed before cleanup
213+
// This prevents race conditions where the stream might still be processing
214+
await new Promise((resolve) => setTimeout(resolve, 100))
215+
}
216+
await provider.finishSubTask(t("common:tasks.canceled"))
217+
} catch (error) {
218+
// If there's an error, still try to resume the parent task
219+
provider.log(`Error during subtask cancellation: ${error}`)
220+
await provider.finishSubTask(t("common:tasks.canceled"))
221+
}
208222
} else {
209223
// Regular task - just clear it
210224
await provider.clearTask()

0 commit comments

Comments
 (0)