@@ -2,73 +2,92 @@ import * as assert from "assert"
22
33import { RooCodeEventName , type ClineMessage } from "@roo-code/types"
44
5- import { sleep , waitFor , waitUntilCompleted } from "./utils"
5+ import { waitFor } from "./utils"
66
7- suite . skip ( "Roo Code Subtasks" , ( ) => {
8- test ( "Should handle subtask cancellation and resumption correctly" , async ( ) => {
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
910 const api = globalThis . api
1011
11- const messages : Record < string , ClineMessage [ ] > = { }
12+ const messages : ClineMessage [ ] = [ ]
13+ let childTaskCompleted = false
14+ let parentCompleted = false
1215
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 )
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 ) )
1723 }
18- } )
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 )
35+ }
36+ }
37+ api . on ( RooCodeEventName . TaskCompleted , completionHandler )
1938
20- const childPrompt = "You are a calculator. Respond only with numbers. What is the square root of 9? "
39+ const childPrompt = "What is 2 + 2? Respond with just the number. "
2140
22- // Start a parent task that will create a subtask.
41+ // Start a parent task that will create a subtask
42+ console . log ( "Starting parent task that will spawn subtask..." )
2343 const parentTaskId = await api . startNewTask ( {
2444 configuration : {
25- mode : "ask " ,
45+ mode : "code " ,
2646 alwaysAllowModeSwitch : true ,
2747 alwaysAllowSubtasks : true ,
2848 autoApprovalEnabled : true ,
2949 enableCheckpoints : false ,
3050 } ,
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'." ,
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.` ,
3552 } )
3653
37- let spawnedTaskId : string | undefined = undefined
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" )
3859
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 ( )
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" )
4464
45- // Wait a bit to ensure any task resumption would have happened.
46- await sleep ( 2_000 )
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+ )
4773
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- )
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" )
5578
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 } )
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 )
5984
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 } )
85+ // Cancel any remaining tasks
86+ try {
87+ await api . cancelCurrentTask ( )
88+ } catch {
89+ // Task might already be complete
90+ }
91+ }
7392 } )
7493} )
0 commit comments