// src/tools/chat/subagent.ts // Copyright (C) 2025 DTP Technologies, LLC // All Rights Reserved import type { ToolDefinition } from "../../lib/ai-client.js"; import { DtpTool, type ToolArguments, type ToolContext, } from "../../lib/tool.js"; import AgentService from "../../services/agent.js"; import { ChatSessionMode } from "@/models/chat-session.js"; import HostMonitorService from "../../services/host-monitor.js"; const VALID_AGENT_TYPES = ["explore", "general"] as const; type AgentType = (typeof VALID_AGENT_TYPES)[number]; export class SubagentTool extends DtpTool { get name(): string { return "SubagentTool"; } get slug(): string { return "subagent"; } get metadata() { return { name: this.definition.function.name || "subagent", category: "chat", tags: ["subagent", "spawn", "delegate", "explore", "general"], modes: [ ChatSessionMode.Plan, ChatSessionMode.Build, ChatSessionMode.Test, ChatSessionMode.Ship, ChatSessionMode.Develop, ], }; } public definition: ToolDefinition = { type: "function", function: { name: "subagent", description: "Spawn a subagent to perform a specific task. The subagent will execute the task and return its result. Use 'explore' agent type for research and information gathering tasks. Use 'general' agent type for general-purpose task execution.", parameters: { type: "object", properties: { agent_type: { type: "string", enum: VALID_AGENT_TYPES, description: "The type of subagent to spawn. Use 'explore' for research and information gathering. Use 'general' for general-purpose task execution.", }, prompt: { type: "string", description: "The task description and instructions for the subagent. Be specific about what information to find or what task to perform.", }, }, required: ["agent_type", "prompt"], }, }, }; public async execute( context: ToolContext, args: ToolArguments, ): Promise { const { agent_type, prompt } = args; if (!agent_type) { return JSON.stringify({ success: false, error: "MISSING_AGENT_TYPE", message: "The 'agent_type' parameter is required.", hint: "Specify either 'explore' or 'general' for the agent_type parameter.", }); } if (!VALID_AGENT_TYPES.includes(agent_type as AgentType)) { return JSON.stringify({ success: false, error: "INVALID_AGENT_TYPE", message: `Invalid agent_type: '${agent_type}'. Must be one of: ${VALID_AGENT_TYPES.join(", ")}`, hint: "Use 'explore' for research tasks or 'general' for general tasks.", }); } if (!prompt) { return JSON.stringify({ success: false, error: "MISSING_PROMPT", message: "The 'prompt' parameter is required.", hint: "Provide specific instructions for the subagent to execute.", }); } if (typeof prompt !== "string") { return JSON.stringify({ success: false, error: "INVALID_PROMPT_TYPE", message: `The 'prompt' parameter must be a string, but received ${typeof prompt}.`, hint: "Ensure you pass a string value for the prompt parameter.", }); } this.log.debug("Spawning subagent", { agentType: agent_type, promptLength: prompt.length, }); try { const result = await AgentService.spawnSubagent( context.session, agent_type as AgentType, prompt, ); const resultJson = JSON.stringify({ success: true, data: { agentType: agent_type, result: result.response, historyCount: result.history.length, historyIds: result.historyIds, subagentType: agent_type, subagentPrompt: String(prompt), subagentStats: result.stats, }, }); const byteCount = Buffer.byteLength(resultJson, "utf-8"); HostMonitorService.subagent(byteCount); HostMonitorService.toolCall(byteCount); return resultJson; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.log.error("Subagent execution failed", { agentType: agent_type, error: errorMessage, }); return JSON.stringify({ success: false, error: "SUBAGENT_FAILED", message: errorMessage, }); } } } export default new SubagentTool();