/ hooks / useSwarmInitialization.ts
useSwarmInitialization.ts
 1  /**
 2   * Swarm Initialization Hook
 3   *
 4   * Initializes swarm features: teammate hooks and context.
 5   * Handles both fresh spawns and resumed teammate sessions.
 6   *
 7   * This hook is conditionally loaded to allow dead code elimination when swarms are disabled.
 8   */
 9  
10  import { useEffect } from 'react'
11  import { getSessionId } from '../bootstrap/state.js'
12  import type { AppState } from '../state/AppState.js'
13  import type { Message } from '../types/message.js'
14  import { isAgentSwarmsEnabled } from '../utils/agentSwarmsEnabled.js'
15  import { initializeTeammateContextFromSession } from '../utils/swarm/reconnection.js'
16  import { readTeamFile } from '../utils/swarm/teamHelpers.js'
17  import { initializeTeammateHooks } from '../utils/swarm/teammateInit.js'
18  import { getDynamicTeamContext } from '../utils/teammate.js'
19  
20  type SetAppState = (f: (prevState: AppState) => AppState) => void
21  
22  /**
23   * Hook that initializes swarm features when ENABLE_AGENT_SWARMS is true.
24   *
25   * Handles both:
26   * - Resumed teammate sessions (from --resume or /resume) where teamName/agentName
27   *   are stored in transcript messages
28   * - Fresh spawns where context is read from environment variables
29   */
30  export function useSwarmInitialization(
31    setAppState: SetAppState,
32    initialMessages: Message[] | undefined,
33    { enabled = true }: { enabled?: boolean } = {},
34  ): void {
35    useEffect(() => {
36      if (!enabled) return
37      if (isAgentSwarmsEnabled()) {
38        // Check if this is a resumed agent session (from --resume or /resume)
39        // Resumed sessions have teamName/agentName stored in transcript messages
40        const firstMessage = initialMessages?.[0]
41        const teamName =
42          firstMessage && 'teamName' in firstMessage
43            ? (firstMessage.teamName as string | undefined)
44            : undefined
45        const agentName =
46          firstMessage && 'agentName' in firstMessage
47            ? (firstMessage.agentName as string | undefined)
48            : undefined
49  
50        if (teamName && agentName) {
51          // Resumed agent session - set up team context from stored info
52          initializeTeammateContextFromSession(setAppState, teamName, agentName)
53  
54          // Get agentId from team file for hook initialization
55          const teamFile = readTeamFile(teamName)
56          const member = teamFile?.members.find(
57            (m: { name: string }) => m.name === agentName,
58          )
59          if (member) {
60            initializeTeammateHooks(setAppState, getSessionId(), {
61              teamName,
62              agentId: member.agentId,
63              agentName,
64            })
65          }
66        } else {
67          // Fresh spawn or standalone session
68          // teamContext is already computed in main.tsx via computeInitialTeamContext()
69          // and included in initialState, so we only need to initialize hooks here
70          const context = getDynamicTeamContext?.()
71          if (context?.teamName && context?.agentId && context?.agentName) {
72            initializeTeammateHooks(setAppState, getSessionId(), {
73              teamName: context.teamName,
74              agentId: context.agentId,
75              agentName: context.agentName,
76            })
77          }
78        }
79      }
80    }, [setAppState, initialMessages, enabled])
81  }