Files
letta-code/src/tools/impl/Task.ts

89 lines
2.6 KiB
TypeScript

/**
* Task tool implementation
*
* Spawns specialized subagents to handle complex, multi-step tasks autonomously.
* Supports both built-in subagent types and custom subagents defined in .letta/agents/.
*/
import { getAllSubagentConfigs } from "../../agent/subagents";
import { spawnSubagent } from "../../agent/subagents/manager";
import {
completeSubagent,
generateSubagentId,
registerSubagent,
} from "../../cli/helpers/subagentState.js";
import { validateRequiredParams } from "./validation";
interface TaskArgs {
subagent_type: string;
prompt: string;
description: string;
model?: string;
toolCallId?: string; // Injected by executeTool for linking subagent to parent tool call
signal?: AbortSignal; // Injected by executeTool for interruption handling
}
/**
* Task tool - Launch a specialized subagent to handle complex tasks
*/
export async function task(args: TaskArgs): Promise<string> {
// Validate required parameters
validateRequiredParams(
args,
["subagent_type", "prompt", "description"],
"Task",
);
const { subagent_type, prompt, description, model, toolCallId, signal } =
args;
// Get all available subagent configs (built-in + custom)
const allConfigs = await getAllSubagentConfigs();
// Validate subagent type
if (!(subagent_type in allConfigs)) {
const available = Object.keys(allConfigs).join(", ");
return `Error: Invalid subagent type "${subagent_type}". Available types: ${available}`;
}
// Register subagent with state store for UI display
const subagentId = generateSubagentId();
registerSubagent(subagentId, subagent_type, description, toolCallId);
try {
const result = await spawnSubagent(
subagent_type,
prompt,
model,
subagentId,
signal,
);
// Mark subagent as completed in state store
completeSubagent(subagentId, {
success: result.success,
error: result.error,
totalTokens: result.totalTokens,
});
if (!result.success) {
return `Error: ${result.error || "Subagent execution failed"}`;
}
// Include stable subagent metadata so orchestrators can attribute results.
// Keep the tool return type as a string for compatibility.
const header = [
`subagent_type=${subagent_type}`,
result.agentId ? `agent_id=${result.agentId}` : undefined,
]
.filter(Boolean)
.join(" ");
return `${header}\n\n${result.report}`;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
completeSubagent(subagentId, { success: false, error: errorMessage });
return `Error: ${errorMessage}`;
}
}