gadget/docs/archive/tools/chat/subagent.ts

156 lines
4.5 KiB
TypeScript

// 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<string> {
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();