1- import { describe , expect , it , beforeEach , afterEach , mock , spyOn } from 'bun:test'
2- import { handleSpawnAgents } from '../tools/handlers/tool/spawn-agents'
3- import { handleSpawnAgentInline } from '../tools/handlers/tool/spawn-agent-inline'
4- import { getMatchingSpawn } from '../tools/handlers/tool/spawn-agent-utils'
51import { TEST_USER_ID } from '@codebuff/common/constants'
62import { getInitialSessionState } from '@codebuff/common/types/session-state'
3+ import {
4+ describe ,
5+ expect ,
6+ it ,
7+ beforeEach ,
8+ afterEach ,
9+ mock ,
10+ spyOn ,
11+ } from 'bun:test'
12+
713import { mockFileContext , MockWebSocket } from './test-utils'
8- import * as loggerModule from '../util/logger'
914import * as runAgentStep from '../run-agent-step'
15+ import { handleSpawnAgentInline } from '../tools/handlers/tool/spawn-agent-inline'
16+ import { getMatchingSpawn } from '../tools/handlers/tool/spawn-agent-utils'
17+ import { handleSpawnAgents } from '../tools/handlers/tool/spawn-agents'
18+ import * as loggerModule from '../util/logger'
1019
11- import type { AgentTemplate } from '@codebuff/common/types/agent-template'
1220import type { CodebuffToolCall } from '@codebuff/common/tools/list'
21+ import type { AgentTemplate } from '@codebuff/common/types/agent-template'
1322import type { WebSocket } from 'ws'
1423
1524describe ( 'Spawn Agents Permissions' , ( ) => {
1625 let mockSendSubagentChunk : any
1726 let mockLoopAgentSteps : any
1827
19- const createMockAgent = ( id : string , spawnableAgents : string [ ] = [ ] ) : AgentTemplate => ( {
28+ const createMockAgent = (
29+ id : string ,
30+ spawnableAgents : string [ ] = [ ] ,
31+ ) : AgentTemplate => ( {
2032 id,
2133 displayName : `Mock ${ id } ` ,
2234 outputMode : 'last_message' as const ,
@@ -71,14 +83,23 @@ describe('Spawn Agents Permissions', () => {
7183 describe ( 'getMatchingSpawn function' , ( ) => {
7284 describe ( 'exact matches with publisher/agent@version format' , ( ) => {
7385 it ( 'should match exact publisher/agent@version' , ( ) => {
74- const spawnableAgents = [ 'codebuff/thinker@1.0.0' , 'codebuff/reviewer@2.1.0' ]
75- const result = getMatchingSpawn ( spawnableAgents , 'codebuff/thinker@1.0.0' )
86+ const spawnableAgents = [
87+ 'codebuff/thinker@1.0.0' ,
88+ 'codebuff/reviewer@2.1.0' ,
89+ ]
90+ const result = getMatchingSpawn (
91+ spawnableAgents ,
92+ 'codebuff/thinker@1.0.0' ,
93+ )
7694 expect ( result ) . toBe ( 'codebuff/thinker@1.0.0' )
7795 } )
7896
7997 it ( 'should not match different versions' , ( ) => {
8098 const spawnableAgents = [ 'codebuff/thinker@1.0.0' ]
81- const result = getMatchingSpawn ( spawnableAgents , 'codebuff/thinker@2.0.0' )
99+ const result = getMatchingSpawn (
100+ spawnableAgents ,
101+ 'codebuff/thinker@2.0.0' ,
102+ )
82103 expect ( result ) . toBeNull ( )
83104 } )
84105
@@ -90,7 +111,10 @@ describe('Spawn Agents Permissions', () => {
90111
91112 it ( 'should not match different agent names' , ( ) => {
92113 const spawnableAgents = [ 'codebuff/thinker@1.0.0' ]
93- const result = getMatchingSpawn ( spawnableAgents , 'codebuff/reviewer@1.0.0' )
114+ const result = getMatchingSpawn (
115+ spawnableAgents ,
116+ 'codebuff/reviewer@1.0.0' ,
117+ )
94118 expect ( result ) . toBeNull ( )
95119 } )
96120 } )
@@ -170,7 +194,10 @@ describe('Spawn Agents Permissions', () => {
170194
171195 it ( 'should return null for malformed agent ID' , ( ) => {
172196 const spawnableAgents = [ 'thinker' , 'reviewer' ]
173- const result = getMatchingSpawn ( spawnableAgents , 'invalid/agent/format/too/many/slashes' )
197+ const result = getMatchingSpawn (
198+ spawnableAgents ,
199+ 'invalid/agent/format/too/many/slashes' ,
200+ )
174201 expect ( result ) . toBeNull ( )
175202 } )
176203
@@ -195,7 +222,10 @@ describe('Spawn Agents Permissions', () => {
195222 } )
196223
197224 describe ( 'handleSpawnAgents permission validation' , ( ) => {
198- const createSpawnToolCall = ( agentType : string , prompt = 'test prompt' ) : CodebuffToolCall < 'spawn_agents' > => ( {
225+ const createSpawnToolCall = (
226+ agentType : string ,
227+ prompt = 'test prompt' ,
228+ ) : CodebuffToolCall < 'spawn_agents' > => ( {
199229 toolName : 'spawn_agents' as const ,
200230 toolCallId : 'test-tool-call-id' ,
201231 input : {
@@ -262,7 +292,9 @@ describe('Spawn Agents Permissions', () => {
262292
263293 const output = await result
264294 expect ( output ) . toContain ( 'Error spawning agent' )
265- expect ( output ) . toContain ( 'is not allowed to spawn child agent type reviewer' )
295+ expect ( output ) . toContain (
296+ 'is not allowed to spawn child agent type reviewer' ,
297+ )
266298 expect ( mockLoopAgentSteps ) . not . toHaveBeenCalled ( )
267299 } )
268300
@@ -347,8 +379,8 @@ describe('Spawn Agents Permissions', () => {
347379 fingerprintId : 'test-fingerprint' ,
348380 userId : TEST_USER_ID ,
349381 agentTemplate : parentAgent ,
350- localAgentTemplates : {
351- ' thinker' : childAgent ,
382+ localAgentTemplates : {
383+ thinker : childAgent ,
352384 'codebuff/thinker@1.0.0' : childAgent , // Register with both keys
353385 } ,
354386 sendSubagentChunk : mockSendSubagentChunk ,
@@ -400,7 +432,7 @@ describe('Spawn Agents Permissions', () => {
400432 const reviewerAgent = createMockAgent ( 'reviewer' )
401433 const ws = new MockWebSocket ( ) as unknown as WebSocket
402434 const sessionState = getInitialSessionState ( mockFileContext )
403-
435+
404436 const toolCall : CodebuffToolCall < 'spawn_agents' > = {
405437 toolName : 'spawn_agents' as const ,
406438 toolCallId : 'test-tool-call-id' ,
@@ -424,7 +456,10 @@ describe('Spawn Agents Permissions', () => {
424456 fingerprintId : 'test-fingerprint' ,
425457 userId : TEST_USER_ID ,
426458 agentTemplate : parentAgent ,
427- localAgentTemplates : { thinker : thinkerAgent , reviewer : reviewerAgent } ,
459+ localAgentTemplates : {
460+ thinker : thinkerAgent ,
461+ reviewer : reviewerAgent ,
462+ } ,
428463 sendSubagentChunk : mockSendSubagentChunk ,
429464 messages : [ ] ,
430465 agentState : sessionState . mainAgentState ,
@@ -434,13 +469,18 @@ describe('Spawn Agents Permissions', () => {
434469 const output = await result
435470 expect ( output ) . toContain ( 'Mock agent response' ) // Successful thinker spawn
436471 expect ( output ) . toContain ( 'Error spawning agent' ) // Failed reviewer spawn
437- expect ( output ) . toContain ( 'is not allowed to spawn child agent type reviewer' )
472+ expect ( output ) . toContain (
473+ 'is not allowed to spawn child agent type reviewer' ,
474+ )
438475 expect ( mockLoopAgentSteps ) . toHaveBeenCalledTimes ( 1 ) // Only thinker was spawned
439476 } )
440477 } )
441478
442479 describe ( 'handleSpawnAgentInline permission validation' , ( ) => {
443- const createInlineSpawnToolCall = ( agentType : string , prompt = 'test prompt' ) : CodebuffToolCall < 'spawn_agent_inline' > => ( {
480+ const createInlineSpawnToolCall = (
481+ agentType : string ,
482+ prompt = 'test prompt' ,
483+ ) : CodebuffToolCall < 'spawn_agent_inline' > => ( {
444484 toolName : 'spawn_agent_inline' as const ,
445485 toolCallId : 'test-tool-call-id' ,
446486 input : {
@@ -462,6 +502,7 @@ describe('Spawn Agents Permissions', () => {
462502 fileContext : mockFileContext ,
463503 clientSessionId : 'test-session' ,
464504 userInputId : 'test-input' ,
505+ writeToClient : ( ) => { } ,
465506 getLatestState : ( ) => ( { messages : [ ] } ) ,
466507 state : {
467508 ws,
@@ -491,6 +532,7 @@ describe('Spawn Agents Permissions', () => {
491532 fileContext : mockFileContext ,
492533 clientSessionId : 'test-session' ,
493534 userInputId : 'test-input' ,
535+ writeToClient : ( ) => { } ,
494536 getLatestState : ( ) => ( { messages : [ ] } ) ,
495537 state : {
496538 ws,
@@ -503,7 +545,9 @@ describe('Spawn Agents Permissions', () => {
503545 } ,
504546 } )
505547
506- await expect ( result ) . rejects . toThrow ( 'is not allowed to spawn child agent type reviewer' )
548+ await expect ( result ) . rejects . toThrow (
549+ 'is not allowed to spawn child agent type reviewer' ,
550+ )
507551 expect ( mockLoopAgentSteps ) . not . toHaveBeenCalled ( )
508552 } )
509553
@@ -519,6 +563,7 @@ describe('Spawn Agents Permissions', () => {
519563 fileContext : mockFileContext ,
520564 clientSessionId : 'test-session' ,
521565 userInputId : 'test-input' ,
566+ writeToClient : ( ) => { } ,
522567 getLatestState : ( ) => ( { messages : [ ] } ) ,
523568 state : {
524569 ws,
@@ -548,6 +593,7 @@ describe('Spawn Agents Permissions', () => {
548593 fileContext : mockFileContext ,
549594 clientSessionId : 'test-session' ,
550595 userInputId : 'test-input' ,
596+ writeToClient : ( ) => { } ,
551597 getLatestState : ( ) => ( { messages : [ ] } ) ,
552598 state : {
553599 ws,
@@ -577,14 +623,15 @@ describe('Spawn Agents Permissions', () => {
577623 fileContext : mockFileContext ,
578624 clientSessionId : 'test-session' ,
579625 userInputId : 'test-input' ,
626+ writeToClient : ( ) => { } ,
580627 getLatestState : ( ) => ( { messages : [ ] } ) ,
581628 state : {
582629 ws,
583630 fingerprintId : 'test-fingerprint' ,
584631 userId : TEST_USER_ID ,
585632 agentTemplate : parentAgent ,
586- localAgentTemplates : {
587- ' thinker' : childAgent ,
633+ localAgentTemplates : {
634+ thinker : childAgent ,
588635 'codebuff/thinker@1.0.0' : childAgent , // Register with both keys
589636 } ,
590637 messages : [ ] ,
@@ -609,6 +656,7 @@ describe('Spawn Agents Permissions', () => {
609656 fileContext : mockFileContext ,
610657 clientSessionId : 'test-session' ,
611658 userInputId : 'test-input' ,
659+ writeToClient : ( ) => { } ,
612660 getLatestState : ( ) => ( { messages : [ ] } ) ,
613661 state : {
614662 ws,
@@ -621,7 +669,9 @@ describe('Spawn Agents Permissions', () => {
621669 } ,
622670 } )
623671
624- await expect ( result ) . rejects . toThrow ( 'is not allowed to spawn child agent type' )
672+ await expect ( result ) . rejects . toThrow (
673+ 'is not allowed to spawn child agent type' ,
674+ )
625675 expect ( mockLoopAgentSteps ) . not . toHaveBeenCalled ( )
626676 } )
627677
@@ -636,6 +686,7 @@ describe('Spawn Agents Permissions', () => {
636686 fileContext : mockFileContext ,
637687 clientSessionId : 'test-session' ,
638688 userInputId : 'test-input' ,
689+ writeToClient : ( ) => { } ,
639690 getLatestState : ( ) => ( { messages : [ ] } ) ,
640691 state : {
641692 // Missing required fields like ws, fingerprintId, etc.
0 commit comments