@@ -39,6 +39,13 @@ import {
3939 type SubAgentProvider ,
4040 type SubAgentSessionStore ,
4141} from "../subagent/index.js" ;
42+ import { createFleetRecords , createSpawnAgentTool , createWaitAgentsTool } from "../subagent/agent-fleet.js" ;
43+ import {
44+ createCloseAgentTool ,
45+ createResumeAgentTool ,
46+ createInterruptAgentTool ,
47+ createFollowupTaskTool ,
48+ } from "../subagent/lifecycle-tools.js" ;
4249import { parseManageTasksArgs } from "./tasks.js" ;
4350import { createListDirTool } from "../util/list-dir.js" ;
4451import { createWebFetchTool } from "../tools/web-fetch.js" ;
@@ -263,6 +270,84 @@ export async function createAgentToolset(args: AgentToolsetArgs): Promise<AgentT
263270
264271 // Align the advertised run_shell timeout with shell-guard (no built-in default;
265272 // advertise settings.shell.timeoutMs when set).
273+ // Orchestrator tools (task / search / trace / fleet) are assembled once so the
274+ // fleet verbs can reuse the same sessions store the task tool already holds —
275+ // never a private mailbox allocated only for spawn_agent/wait_agents.
276+ const orchestratorTools : AgentTool [ ] = [ ] ;
277+ if ( subAgentsEnabled && args . subAgent !== undefined ) {
278+ const sa = args . subAgent ;
279+ orchestratorTools . push (
280+ createTaskTool ( {
281+ cwd,
282+ getWorkdirBase : sa . getWorkdirBase ,
283+ provider : sa . provider ,
284+ permissionGate,
285+ inheritMcpTools : ( ) => inheritedMcpTools ,
286+ run : runSubAgent ,
287+ ...( shellTimeout !== undefined ? { shellTimeout } : { } ) ,
288+ ...( shellEnv !== undefined ? { shellEnv } : { } ) ,
289+ ...( extraToolPlugins . length > 0 ? { extraToolPlugins } : { } ) ,
290+ ...( sa . onEvent !== undefined ? { onEvent : sa . onEvent } : { } ) ,
291+ ...( sa . onProgress !== undefined ? { onProgress : sa . onProgress } : { } ) ,
292+ ...( sa . sessions !== undefined ? { sessions : sa . sessions } : { } ) ,
293+ ...( sa . settings !== undefined ? { settings : sa . settings } : { } ) ,
294+ ...( sa . catalog !== undefined ? { catalog : sa . catalog } : { } ) ,
295+ ...( sa . profiles !== undefined ? { profiles : sa . profiles } : { } ) ,
296+ ...( args . getBlobReader !== undefined ? { getBlobReader : args . getBlobReader } : { } ) ,
297+ ...( sa . useWorktree !== undefined ? { useWorktree : sa . useWorktree } : { } ) ,
298+ ...( args . telemetry !== undefined ? { telemetry : args . telemetry } : { } ) ,
299+ } ) ,
300+ ) ;
301+ if ( sa . profiles !== undefined ) {
302+ orchestratorTools . push (
303+ createSearchAgentsTool ( ( ) => {
304+ const profiles = sa . profiles ;
305+ return typeof profiles === "function" ? profiles ( ) : ( profiles ?? [ ] ) ;
306+ } ) ,
307+ ) ;
308+ }
309+ // Tier 1: the primary session is always an orchestrator and may
310+ // target any worker (assertCanTargetAgent's rule), so no authority
311+ // context is passed here — omitting it is treated as unrestricted,
312+ // matching Tier 1's actual authority.
313+ orchestratorTools . push ( createReadAgentTraceTool ( sa . getWorkdirBase ) ) ;
314+
315+ // Mirror nested runSubAgent's orchestrator fleet mount (run.ts), but
316+ // reuse the existing TUI/exec session store — do not allocate a private
317+ // store only for these verbs. spawnAllowlist stays unwired on primary.
318+ if ( sa . sessions !== undefined ) {
319+ const fleetSessions = sa . sessions ;
320+ const fleetRecords = createFleetRecords ( ) ;
321+ const fleetDeps = {
322+ permissionGate,
323+ inheritMcpTools : ( ) => inheritedMcpTools ,
324+ ...( shellTimeout !== undefined ? { shellTimeout } : { } ) ,
325+ ...( shellEnv !== undefined ? { shellEnv } : { } ) ,
326+ ...( extraToolPlugins . length > 0 ? { extraToolPlugins } : { } ) ,
327+ cwd,
328+ getWorkdirBase : sa . getWorkdirBase ,
329+ provider : sa . provider ,
330+ ...( args . getBlobReader !== undefined ? { getBlobReader : args . getBlobReader } : { } ) ,
331+ run : runSubAgent ,
332+ sessions : fleetSessions ,
333+ fleetRecords,
334+ ...( sa . onEvent !== undefined ? { onEvent : sa . onEvent } : { } ) ,
335+ ...( sa . onProgress !== undefined ? { onProgress : sa . onProgress } : { } ) ,
336+ ...( sa . settings !== undefined ? { settings : sa . settings } : { } ) ,
337+ ...( sa . catalog !== undefined ? { catalog : sa . catalog } : { } ) ,
338+ ...( args . telemetry !== undefined ? { telemetry : args . telemetry } : { } ) ,
339+ } ;
340+ orchestratorTools . push (
341+ createSpawnAgentTool ( fleetDeps ) ,
342+ createWaitAgentsTool ( { sessions : fleetSessions , fleetRecords } ) ,
343+ createCloseAgentTool ( { sessions : fleetSessions } ) ,
344+ createResumeAgentTool ( { sessions : fleetSessions } ) ,
345+ createInterruptAgentTool ( { sessions : fleetSessions } ) ,
346+ createFollowupTaskTool ( { sessions : fleetSessions } ) ,
347+ ) ;
348+ }
349+ }
350+
266351 const baseTools : AgentTool [ ] = [
267352 ...fromToolRunner ( posixTools ) . map ( ( tool ) => ( {
268353 ...tool ,
@@ -276,47 +361,7 @@ export async function createAgentToolset(args: AgentToolsetArgs): Promise<AgentT
276361 createUseSkillTool ( cwd , skillDirs , args . telemetry ) ,
277362 createWebFetchTool ( ) ,
278363 createWebSearchTool ( ) ,
279- ...( subAgentsEnabled && args . subAgent !== undefined
280- ? [
281- createTaskTool ( {
282- cwd,
283- getWorkdirBase : args . subAgent . getWorkdirBase ,
284- provider : args . subAgent . provider ,
285- permissionGate,
286- inheritMcpTools : ( ) => inheritedMcpTools ,
287- run : runSubAgent ,
288- ...( shellTimeout !== undefined ? { shellTimeout } : { } ) ,
289- ...( shellEnv !== undefined ? { shellEnv } : { } ) ,
290- ...( extraToolPlugins . length > 0 ? { extraToolPlugins } : { } ) ,
291- ...( args . subAgent . onEvent !== undefined ? { onEvent : args . subAgent . onEvent } : { } ) ,
292- ...( args . subAgent . onProgress !== undefined
293- ? { onProgress : args . subAgent . onProgress }
294- : { } ) ,
295- ...( args . subAgent . sessions !== undefined ? { sessions : args . subAgent . sessions } : { } ) ,
296- ...( args . subAgent . settings !== undefined ? { settings : args . subAgent . settings } : { } ) ,
297- ...( args . subAgent . catalog !== undefined ? { catalog : args . subAgent . catalog } : { } ) ,
298- ...( args . subAgent . profiles !== undefined ? { profiles : args . subAgent . profiles } : { } ) ,
299- ...( args . getBlobReader !== undefined ? { getBlobReader : args . getBlobReader } : { } ) ,
300- ...( args . subAgent . useWorktree !== undefined
301- ? { useWorktree : args . subAgent . useWorktree }
302- : { } ) ,
303- ...( args . telemetry !== undefined ? { telemetry : args . telemetry } : { } ) ,
304- } ) ,
305- ...( args . subAgent . profiles !== undefined
306- ? [
307- createSearchAgentsTool ( ( ) => {
308- const profiles = args . subAgent ! . profiles ;
309- return typeof profiles === "function" ? profiles ( ) : ( profiles ?? [ ] ) ;
310- } ) ,
311- ]
312- : [ ] ) ,
313- // Tier 1: the primary session is always an orchestrator and may
314- // target any worker (assertCanTargetAgent's rule), so no authority
315- // context is passed here — omitting it is treated as unrestricted,
316- // matching Tier 1's actual authority.
317- createReadAgentTraceTool ( args . subAgent . getWorkdirBase ) ,
318- ]
319- : [ ] ) ,
364+ ...orchestratorTools ,
320365 stringTool ( {
321366 definition : manageTasksDefinition ,
322367 handler : async ( rawArgs : Record < string , unknown > ) : Promise < string > => {
0 commit comments