Skip to content

Commit 65f4c8e

Browse files
committed
feat: refactor parent-child task coordination to use event-driven architecture
- Add parentTaskId field to HistoryItem schema for persistent task relationships - Replace polling mechanism (waitForResume/pauseInterval) with event-driven approach using TaskUnpaused events - Update ClineProvider to persist parent task ID when creating child tasks - Update task metadata persistence to include parentTaskId - Add comprehensive tests for parent-child task coordination - Improve performance by eliminating 100ms polling intervals Fixes #6672
1 parent 4e8b174 commit 65f4c8e

File tree

4 files changed

+601
-14
lines changed

4 files changed

+601
-14
lines changed

packages/types/src/history.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const historyItemSchema = z.object({
1717
size: z.number().optional(),
1818
workspace: z.string().optional(),
1919
mode: z.string().optional(),
20+
parentTaskId: z.string().optional(),
2021
})
2122

2223
export type HistoryItem = z.infer<typeof historyItemSchema>

src/core/task-persistence/taskMetadata.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type TaskMetadataOptions = {
1919
globalStoragePath: string
2020
workspace: string
2121
mode?: string
22+
parentTaskId?: string
2223
}
2324

2425
export async function taskMetadata({
@@ -28,6 +29,7 @@ export async function taskMetadata({
2829
globalStoragePath,
2930
workspace,
3031
mode,
32+
parentTaskId,
3133
}: TaskMetadataOptions) {
3234
const taskDir = await getTaskDirectoryPath(globalStoragePath, taskId)
3335

@@ -95,6 +97,7 @@ export async function taskMetadata({
9597
size: taskDirSize,
9698
workspace,
9799
mode,
100+
parentTaskId,
98101
}
99102

100103
return { historyItem, tokenUsage }

src/core/task/Task.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
183183
isInitialized = false
184184
isPaused: boolean = false
185185
pausedModeSlug: string = defaultModeSlug
186-
private pauseInterval: NodeJS.Timeout | undefined
186+
private pauseResolve: (() => void) | undefined
187187

188188
// API
189189
readonly apiConfiguration: ProviderSettings
@@ -586,6 +586,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
586586
globalStoragePath: this.globalStoragePath,
587587
workspace: this.cwd,
588588
mode: this._taskMode || defaultModeSlug, // Use the task's own mode, not the current provider mode
589+
parentTaskId: this.parentTask?.taskId,
589590
})
590591

591592
this.emit(RooCodeEventName.TaskTokenUsageUpdated, this.taskId, tokenUsage)
@@ -1221,10 +1222,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
12211222
public dispose(): void {
12221223
console.log(`[Task] disposing task ${this.taskId}.${this.instanceId}`)
12231224

1224-
// Stop waiting for child task completion.
1225-
if (this.pauseInterval) {
1226-
clearInterval(this.pauseInterval)
1227-
this.pauseInterval = undefined
1225+
// If waiting for resume, resolve the promise to unblock
1226+
if (this.pauseResolve) {
1227+
this.pauseResolve()
1228+
this.pauseResolve = undefined
12281229
}
12291230

12301231
// Release any terminals associated with this task.
@@ -1300,18 +1301,18 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
13001301
}
13011302

13021303
// Used when a sub-task is launched and the parent task is waiting for it to
1303-
// finish.
1304-
// TBD: The 1s should be added to the settings, also should add a timeout to
1305-
// prevent infinite waiting.
1304+
// finish. Uses event-driven approach instead of polling.
13061305
public async waitForResume() {
13071306
await new Promise<void>((resolve) => {
1308-
this.pauseInterval = setInterval(() => {
1309-
if (!this.isPaused) {
1310-
clearInterval(this.pauseInterval)
1311-
this.pauseInterval = undefined
1312-
resolve()
1307+
this.pauseResolve = resolve
1308+
1309+
// Set up event listener for TaskUnpaused event
1310+
const unsubscribe = this.once(RooCodeEventName.TaskUnpaused, () => {
1311+
if (this.pauseResolve) {
1312+
this.pauseResolve()
1313+
this.pauseResolve = undefined
13131314
}
1314-
}, 1000)
1315+
})
13151316
})
13161317
}
13171318

0 commit comments

Comments
 (0)