@@ -2,6 +2,7 @@ import { describe, expect, test } from 'bun:test'
22
33import {
44 processBlocks ,
5+ splitAgentsBySize ,
56 isReasoningTextBlock ,
67 type BlockProcessorHandlers ,
78} from '../block-processor'
@@ -447,23 +448,44 @@ describe('processBlocks', () => {
447448 expect ( calls [ 0 ] . handler ) . toBe ( 'onAgentGroup' )
448449 } )
449450
450- test ( 'groups consecutive non-implementor agents' , ( ) => {
451+ test ( 'groups consecutive small (collapsed-by-default) agents together ' , ( ) => {
451452 const { handlers, calls } = createMockHandlers ( )
452453 const blocks : ContentBlock [ ] = [
453454 createNonImplementorAgent ( 'fp-1' , 'file-picker' ) ,
454- createNonImplementorAgent ( 'cmd-1' , 'commander' ) ,
455+ createNonImplementorAgent ( 'b-1' , 'basher' ) ,
456+ createNonImplementorAgent ( 'cs-1' , 'code-searcher' ) ,
457+ ]
458+
459+ const result = processBlocks ( blocks , handlers )
460+
461+ expect ( result ) . toEqual ( [ 'agents-0-3' ] )
462+ expect ( calls ) . toHaveLength ( 1 )
463+ expect ( calls [ 0 ] . handler ) . toBe ( 'onAgentGroup' )
464+ const agentBlocks = calls [ 0 ] . args [ 0 ] as AgentContentBlock [ ]
465+ expect ( agentBlocks ) . toHaveLength ( 3 )
466+ expect ( agentBlocks [ 0 ] . agentType ) . toBe ( 'file-picker' )
467+ expect ( agentBlocks [ 1 ] . agentType ) . toBe ( 'basher' )
468+ expect ( agentBlocks [ 2 ] . agentType ) . toBe ( 'code-searcher' )
469+ } )
470+
471+ test ( 'groups consecutive non-implementor agents including mixed sizes' , ( ) => {
472+ const { handlers, calls } = createMockHandlers ( )
473+ const blocks : ContentBlock [ ] = [
474+ createNonImplementorAgent ( 'fp-1' , 'file-picker' ) ,
475+ createNonImplementorAgent ( 'cr-1' , 'code-reviewer' ) ,
455476 createNonImplementorAgent ( 'cs-1' , 'code-searcher' ) ,
456477 ]
457478
458479 const result = processBlocks ( blocks , handlers )
459480
481+ // All consecutive non-implementor agents go into a single onAgentGroup call
460482 expect ( result ) . toEqual ( [ 'agents-0-3' ] )
461483 expect ( calls ) . toHaveLength ( 1 )
462484 expect ( calls [ 0 ] . handler ) . toBe ( 'onAgentGroup' )
463485 const agentBlocks = calls [ 0 ] . args [ 0 ] as AgentContentBlock [ ]
464486 expect ( agentBlocks ) . toHaveLength ( 3 )
465487 expect ( agentBlocks [ 0 ] . agentType ) . toBe ( 'file-picker' )
466- expect ( agentBlocks [ 1 ] . agentType ) . toBe ( 'commander ' )
488+ expect ( agentBlocks [ 1 ] . agentType ) . toBe ( 'code-reviewer ' )
467489 expect ( agentBlocks [ 2 ] . agentType ) . toBe ( 'code-searcher' )
468490 } )
469491
@@ -687,8 +709,8 @@ describe('processBlocks', () => {
687709 createToolBlock ( 'tool-2' , 't2' ) ,
688710 createToolBlock ( 'tool-3' , 't3' ) , // group ends, nextIndex = 4
689711 createTextBlock ( 'text at 4' ) ,
690- createNonImplementorAgent ( 'a1' ) , // group starts at 5
691- createNonImplementorAgent ( 'a2' ) , // group ends, nextIndex = 7
712+ createNonImplementorAgent ( 'a1' ) , // group starts at 5 (file-picker = small)
713+ createNonImplementorAgent ( 'a2' ) , // group ends, nextIndex = 7 (file-picker = small)
692714 createTextBlock ( 'text at 7' ) ,
693715 ]
694716
@@ -703,5 +725,86 @@ describe('processBlocks', () => {
703725 expect ( calls [ 3 ] . args [ 2 ] ) . toBe ( 7 ) // agents next at 7
704726 expect ( calls [ 4 ] . args [ 1 ] ) . toBe ( 7 ) // single text at 7
705727 } )
728+
729+ test ( 'maintains correct indices for mixed-size agent groups' , ( ) => {
730+ const { handlers, calls } = createMockHandlers ( )
731+ const blocks : ContentBlock [ ] = [
732+ createTextBlock ( 'text at 0' ) ,
733+ createNonImplementorAgent ( 'fp-1' , 'file-picker' ) , // index 1
734+ createNonImplementorAgent ( 'b-1' , 'basher' ) , // index 2
735+ createNonImplementorAgent ( 'cr-1' , 'code-reviewer' ) , // index 3
736+ createNonImplementorAgent ( 'cs-1' , 'code-searcher' ) , // index 4
737+ createTextBlock ( 'text at 5' ) ,
738+ ]
739+
740+ processBlocks ( blocks , handlers )
741+
742+ // text at 0
743+ expect ( calls [ 0 ] . handler ) . toBe ( 'onSingleBlock' )
744+ expect ( calls [ 0 ] . args [ 1 ] ) . toBe ( 0 )
745+ // All non-implementor agents grouped together
746+ expect ( calls [ 1 ] . handler ) . toBe ( 'onAgentGroup' )
747+ expect ( calls [ 1 ] . args [ 1 ] ) . toBe ( 1 )
748+ expect ( calls [ 1 ] . args [ 2 ] ) . toBe ( 5 )
749+ expect ( ( calls [ 1 ] . args [ 0 ] as AgentContentBlock [ ] ) . length ) . toBe ( 4 )
750+ // text at 5
751+ expect ( calls [ 2 ] . handler ) . toBe ( 'onSingleBlock' )
752+ expect ( calls [ 2 ] . args [ 1 ] ) . toBe ( 5 )
753+ } )
754+ } )
755+ } )
756+
757+ // ============================================================================
758+ // Tests: splitAgentsBySize
759+ // ============================================================================
760+
761+ describe ( 'splitAgentsBySize' , ( ) => {
762+ test ( 'returns single group for empty array' , ( ) => {
763+ const result = splitAgentsBySize ( [ ] )
764+ expect ( result ) . toEqual ( [ [ ] ] )
765+ } )
766+
767+ test ( 'returns single group for one agent' , ( ) => {
768+ const agent = createNonImplementorAgent ( 'cr-1' , 'code-reviewer' )
769+ const result = splitAgentsBySize ( [ agent ] )
770+ expect ( result ) . toEqual ( [ [ agent ] ] )
771+ } )
772+
773+ test ( 'groups all small agents together' , ( ) => {
774+ const agents = [
775+ createNonImplementorAgent ( 'fp-1' , 'file-picker' ) ,
776+ createNonImplementorAgent ( 'b-1' , 'basher' ) ,
777+ createNonImplementorAgent ( 'cs-1' , 'code-searcher' ) ,
778+ ]
779+ const result = splitAgentsBySize ( agents )
780+ expect ( result ) . toEqual ( [ agents ] )
781+ } )
782+
783+ test ( 'gives each large agent its own group' , ( ) => {
784+ const agents = [
785+ createNonImplementorAgent ( 'cr-1' , 'code-reviewer' ) ,
786+ createNonImplementorAgent ( 'ed-1' , 'editor' ) ,
787+ ]
788+ const result = splitAgentsBySize ( agents )
789+ expect ( result ) . toEqual ( [ [ agents [ 0 ] ] , [ agents [ 1 ] ] ] )
790+ } )
791+
792+ test ( 'splits small and large agents correctly' , ( ) => {
793+ const agents = [
794+ createNonImplementorAgent ( 'fp-1' , 'file-picker' ) ,
795+ createNonImplementorAgent ( 'cr-1' , 'code-reviewer' ) ,
796+ createNonImplementorAgent ( 'b-1' , 'basher' ) ,
797+ createNonImplementorAgent ( 'b-2' , 'basher' ) ,
798+ createNonImplementorAgent ( 'ed-1' , 'editor' ) ,
799+ createNonImplementorAgent ( 'rw-1' , 'researcher-web' ) ,
800+ ]
801+ const result = splitAgentsBySize ( agents )
802+ expect ( result ) . toEqual ( [
803+ [ agents [ 0 ] ] , // file-picker (small)
804+ [ agents [ 1 ] ] , // code-reviewer (large)
805+ [ agents [ 2 ] , agents [ 3 ] ] , // basher + basher (small)
806+ [ agents [ 4 ] ] , // editor (large)
807+ [ agents [ 5 ] ] , // researcher-web (small)
808+ ] )
706809 } )
707810} )
0 commit comments