@@ -2,92 +2,73 @@ import * as assert from "assert"
22
33import { RooCodeEventName , type ClineMessage } from "@roo-code/types"
44
5- import { waitFor } from "./utils"
5+ import { sleep , waitFor , waitUntilCompleted } from "./utils"
66
7- suite ( "Roo Code Subtasks" , ( ) => {
8- test ( "Should create and complete a subtask successfully" , async function ( ) {
9- this . timeout ( 180_000 ) // 3 minutes for complex orchestration
7+ suite . skip ( "Roo Code Subtasks" , ( ) => {
8+ test ( "Should handle subtask cancellation and resumption correctly" , async ( ) => {
109 const api = globalThis . api
1110
12- const messages : ClineMessage [ ] = [ ]
13- let childTaskCompleted = false
14- let parentCompleted = false
11+ const messages : Record < string , ClineMessage [ ] > = { }
1512
16- // Listen for messages to detect subtask result
17- const messageHandler = ( { message } : { message : ClineMessage } ) => {
18- messages . push ( message )
19-
20- // Log completion messages
21- if ( message . type === "say" && message . say === "completion_result" ) {
22- console . log ( "Completion result:" , message . text ?. substring ( 0 , 100 ) )
23- }
24- }
25- api . on ( RooCodeEventName . Message , messageHandler )
26-
27- // Listen for task completion
28- const completionHandler = ( taskId : string ) => {
29- if ( taskId === parentTaskId ) {
30- parentCompleted = true
31- console . log ( "✓ Parent task completed" )
32- } else {
33- childTaskCompleted = true
34- console . log ( "✓ Child task completed:" , taskId )
13+ api . on ( RooCodeEventName . Message , ( { taskId, message } ) => {
14+ if ( message . type === "say" && message . partial === false ) {
15+ messages [ taskId ] = messages [ taskId ] || [ ]
16+ messages [ taskId ] . push ( message )
3517 }
36- }
37- api . on ( RooCodeEventName . TaskCompleted , completionHandler )
18+ } )
3819
39- const childPrompt = "What is 2 + 2? Respond with just the number. "
20+ const childPrompt = "You are a calculator. Respond only with numbers. What is the square root of 9? "
4021
41- // Start a parent task that will create a subtask
42- console . log ( "Starting parent task that will spawn subtask..." )
22+ // Start a parent task that will create a subtask.
4323 const parentTaskId = await api . startNewTask ( {
4424 configuration : {
45- mode : "code " ,
25+ mode : "ask " ,
4626 alwaysAllowModeSwitch : true ,
4727 alwaysAllowSubtasks : true ,
4828 autoApprovalEnabled : true ,
4929 enableCheckpoints : false ,
5030 } ,
51- text : `Create a subtask using the new_task tool with this message: "${ childPrompt } ". Wait for the subtask to complete, then tell me the result.` ,
31+ text :
32+ "You are the parent task. " +
33+ `Create a subtask by using the new_task tool with the message '${ childPrompt } '.` +
34+ "After creating the subtask, wait for it to complete and then respond 'Parent task resumed'." ,
5235 } )
5336
54- try {
55- // Wait for child task to complete
56- console . log ( "Waiting for child task to complete..." )
57- await waitFor ( ( ) => childTaskCompleted , { timeout : 90_000 } )
58- console . log ( "✓ Child task completed" )
37+ let spawnedTaskId : string | undefined = undefined
5938
60- // Wait for parent to complete
61- console . log ( "Waiting for parent task to complete..." )
62- await waitFor ( ( ) => parentCompleted , { timeout : 90_000 } )
63- console . log ( "✓ Parent task completed" )
39+ // Wait for the subtask to be spawned and then cancel it.
40+ api . on ( RooCodeEventName . TaskSpawned , ( _ , childTaskId ) => ( spawnedTaskId = childTaskId ) )
41+ await waitFor ( ( ) => ! ! spawnedTaskId )
42+ await sleep ( 1_000 ) // Give the task a chance to start and populate the history.
43+ await api . cancelCurrentTask ( )
6444
65- // Verify the parent task mentions the subtask result (should contain "4")
66- const hasSubtaskResult = messages . some (
67- ( m ) =>
68- m . type === "say" &&
69- m . say === "completion_result" &&
70- m . text ?. includes ( "4" ) &&
71- m . text ?. toLowerCase ( ) . includes ( "subtask" ) ,
72- )
45+ // Wait a bit to ensure any task resumption would have happened.
46+ await sleep ( 2_000 )
7347
74- // Verify all events occurred
75- assert . ok ( childTaskCompleted , "Child task should have completed" )
76- assert . ok ( parentCompleted , "Parent task should have completed" )
77- assert . ok ( hasSubtaskResult , "Parent task should mention the subtask result" )
48+ // The parent task should not have resumed yet, so we shouldn't see
49+ // "Parent task resumed".
50+ assert . ok (
51+ messages [ parentTaskId ] ?. find ( ( { type, text } ) => type === "say" && text === "Parent task resumed" ) ===
52+ undefined ,
53+ "Parent task should not have resumed after subtask cancellation" ,
54+ )
7855
79- console . log ( "Test passed! Subtask orchestration working correctly" )
80- } finally {
81- // Clean up
82- api . off ( RooCodeEventName . Message , messageHandler )
83- api . off ( RooCodeEventName . TaskCompleted , completionHandler )
56+ // Start a new task with the same message as the subtask.
57+ const anotherTaskId = await api . startNewTask ( { text : childPrompt } )
58+ await waitUntilCompleted ( { api, taskId : anotherTaskId } )
8459
85- // Cancel any remaining tasks
86- try {
87- await api . cancelCurrentTask ( )
88- } catch {
89- // Task might already be complete
90- }
91- }
60+ // Wait a bit to ensure any task resumption would have happened.
61+ await sleep ( 2_000 )
62+
63+ // The parent task should still not have resumed.
64+ assert . ok (
65+ messages [ parentTaskId ] ?. find ( ( { type, text } ) => type === "say" && text === "Parent task resumed" ) ===
66+ undefined ,
67+ "Parent task should not have resumed after subtask cancellation" ,
68+ )
69+
70+ // Clean up - cancel all tasks.
71+ await api . clearCurrentTask ( )
72+ await waitUntilCompleted ( { api, taskId : parentTaskId } )
9273 } )
9374} )
0 commit comments