File size: 4,221 Bytes
064bfd6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | import { z } from 'zod/v4'
import { logEvent } from '../../services/analytics/index.js'
import type { AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS } from '../../services/analytics/metadata.js'
import type { Tool } from '../../Tool.js'
import { buildTool, type ToolDef } from '../../Tool.js'
import { isAgentSwarmsEnabled } from '../../utils/agentSwarmsEnabled.js'
import { lazySchema } from '../../utils/lazySchema.js'
import { jsonStringify } from '../../utils/slowOperations.js'
import { TEAM_LEAD_NAME } from '../../utils/swarm/constants.js'
import {
cleanupTeamDirectories,
readTeamFile,
unregisterTeamForSessionCleanup,
} from '../../utils/swarm/teamHelpers.js'
import { clearTeammateColors } from '../../utils/swarm/teammateLayoutManager.js'
import { clearLeaderTeamName } from '../../utils/tasks.js'
import { TEAM_DELETE_TOOL_NAME } from './constants.js'
import { getPrompt } from './prompt.js'
import { renderToolResultMessage, renderToolUseMessage } from './UI.js'
const inputSchema = lazySchema(() => z.strictObject({}))
type InputSchema = ReturnType<typeof inputSchema>
export type Output = {
success: boolean
message: string
team_name?: string
}
export type Input = z.infer<InputSchema>
export const TeamDeleteTool: Tool<InputSchema, Output> = buildTool({
name: TEAM_DELETE_TOOL_NAME,
searchHint: 'disband a swarm team and clean up',
maxResultSizeChars: 100_000,
shouldDefer: true,
userFacingName() {
return ''
},
get inputSchema(): InputSchema {
return inputSchema()
},
isEnabled() {
return isAgentSwarmsEnabled()
},
async description() {
return 'Clean up team and task directories when the swarm is complete'
},
async prompt() {
return getPrompt()
},
mapToolResultToToolResultBlockParam(data, toolUseID) {
return {
tool_use_id: toolUseID,
type: 'tool_result' as const,
content: [
{
type: 'text' as const,
text: jsonStringify(data),
},
],
}
},
async call(_input, context) {
const { setAppState, getAppState } = context
const appState = getAppState()
const teamName = appState.teamContext?.teamName
if (teamName) {
// Read team config to check for active members
const teamFile = readTeamFile(teamName)
if (teamFile) {
// Filter out the team lead - only count non-lead members
const nonLeadMembers = teamFile.members.filter(
m => m.name !== TEAM_LEAD_NAME,
)
// Separate truly active members from idle/dead ones
// Members with isActive === false are idle (finished their turn or crashed)
const activeMembers = nonLeadMembers.filter(m => m.isActive !== false)
if (activeMembers.length > 0) {
const memberNames = activeMembers.map(m => m.name).join(', ')
return {
data: {
success: false,
message: `Cannot cleanup team with ${activeMembers.length} active member(s): ${memberNames}. Use requestShutdown to gracefully terminate teammates first.`,
team_name: teamName,
},
}
}
}
await cleanupTeamDirectories(teamName)
// Already cleaned — don't try again on gracefulShutdown.
unregisterTeamForSessionCleanup(teamName)
// Clear color assignments so new teams start fresh
clearTeammateColors()
// Clear leader team name so getTaskListId() falls back to session ID
clearLeaderTeamName()
logEvent('tengu_team_deleted', {
team_name:
teamName as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
}
// Clear team context and inbox from app state
setAppState(prev => ({
...prev,
teamContext: undefined,
inbox: {
messages: [], // Clear any queued messages
},
}))
return {
data: {
success: true,
message: teamName
? `Cleaned up directories and worktrees for team "${teamName}"`
: 'No team name found, nothing to clean up',
team_name: teamName,
},
}
},
renderToolUseMessage,
renderToolResultMessage,
} satisfies ToolDef<InputSchema, Output>)
|