@@ -141,6 +141,7 @@ describe('loopAgentSteps - runAgentStep vs runProgrammaticStep behavior', () =>
141141 ancestorRunIds : [ ] ,
142142 onResponseChunk : ( ) => { } ,
143143 signal : new AbortController ( ) . signal ,
144+ tools : { } ,
144145 }
145146 } )
146147
@@ -418,32 +419,24 @@ describe('loopAgentSteps - runAgentStep vs runProgrammaticStep behavior', () =>
418419 } )
419420
420421 it ( 'should pass shouldEndTurn: true as stepsComplete when end_turn tool is called' , async ( ) => {
421- // Test that when LLM calls end_turn, shouldEndTurn is correctly passed to runProgrammaticStep
422-
423- let runProgrammaticStepCalls : any [ ] = [ ]
424-
425- // Mock runProgrammaticStep module to capture calls and verify stepsComplete parameter
426- const mockedRunProgrammaticStep = await mockModule (
427- '@codebuff/agent-runtime/run-programmatic-step' ,
428- ( ) => ( {
429- runProgrammaticStep : async ( params : any ) => {
430- runProgrammaticStepCalls . push ( params )
431- // First call: return endTurn false to continue
432- // Second call: return endTurn true to end the loop
433- const shouldEnd = runProgrammaticStepCalls . length >= 2
434- return {
435- agentState : params . agentState ,
436- endTurn : shouldEnd ,
437- stepNumber : params . stepNumber ,
438- }
439- } ,
440- clearAgentGeneratorCache : ( ) => { } ,
441- runIdToStepAll : new Set ( ) ,
442- } ) ,
443- )
422+ // Test that when LLM calls end_turn, shouldEndTurn (stepsComplete) is correctly passed
423+ // to the handleSteps generator via the step result.
424+ //
425+ // Flow:
426+ // 1. Generator yields 'STEP', runProgrammaticStep returns
427+ // 2. loopAgentSteps calls runAgentStep (LLM), which calls end_turn -> shouldEndTurn = true
428+ // 3. loopAgentSteps calls runProgrammaticStep again with stepsComplete: true
429+ // 4. Generator resumes from yield 'STEP' and receives { stepsComplete: true }
430+
431+ let stepsCompleteValues : boolean [ ] = [ ]
444432
445433 const mockGeneratorFunction = function * ( ) {
446- yield 'STEP' // Hand control to LLM
434+ // First STEP - after LLM runs and calls end_turn, we receive stepsComplete: true
435+ const result1 = yield 'STEP'
436+ stepsCompleteValues . push ( result1 . stepsComplete )
437+
438+ // Since stepsComplete was true, we should end gracefully
439+ yield { toolName : 'end_turn' , input : { } }
447440 } as ( ) => StepGenerator
448441
449442 mockTemplate . handleSteps = mockGeneratorFunction
@@ -458,18 +451,11 @@ describe('loopAgentSteps - runAgentStep vs runProgrammaticStep behavior', () =>
458451 localAgentTemplates,
459452 } )
460453
461- mockedRunProgrammaticStep . clear ( )
462-
463- // Verify that runProgrammaticStep was called twice:
464- // 1. First with stepsComplete: false (initial call)
465- // 2. Second with stepsComplete: true (after LLM called end_turn)
466- expect ( runProgrammaticStepCalls ) . toHaveLength ( 2 )
467-
468- // First call should have stepsComplete: false
469- expect ( runProgrammaticStepCalls [ 0 ] . stepsComplete ) . toBe ( false )
470-
471- // Second call should have stepsComplete: true (after end_turn tool was called)
472- expect ( runProgrammaticStepCalls [ 1 ] . stepsComplete ) . toBe ( true )
454+ // Verify that stepsComplete was passed correctly:
455+ // After yielding STEP and LLM running (which calls end_turn),
456+ // the generator receives stepsComplete: true
457+ expect ( stepsCompleteValues ) . toHaveLength ( 1 )
458+ expect ( stepsCompleteValues [ 0 ] ) . toBe ( true )
473459 } )
474460
475461 it ( 'should continue loop when handleSteps returns endTurn: false even if LLM calls end_turn' , async ( ) => {
0 commit comments