/** * Task Agent Module * * Specialized agent for executing structured tasks with * planning, execution, and verification phases. */ import { BaseAgent, AgentConfig, AgentResponse, AgentTool } from './base-agent'; export interface TaskStep { id: string; description: string; status: 'pending' | 'running' | 'completed' | 'failed'; result?: unknown; error?: string; } export interface TaskPlan { steps: TaskStep[]; estimatedComplexity: 'low' | 'medium' | 'high'; dependencies: Map; } export interface TaskResult { success: boolean; steps: TaskStep[]; output: unknown; errors: string[]; } /** * TaskAgent - Agent specialized for structured task execution */ export class TaskAgent extends BaseAgent { private currentPlan: TaskPlan | null = null; private taskHistory: TaskResult[] = []; constructor(config: AgentConfig) { super(config); // Add default tools for task agents this.addTool({ name: 'plan', description: 'Create a plan for a complex task', execute: async (params) => { const task = params as { description: string }; return this.createPlan(task.description); } }); this.addTool({ name: 'execute_step', description: 'Execute a single step of the plan', execute: async (params) => { const step = params as { stepId: string }; return this.executeStep(step.stepId); } }); } /** * Execute a task with planning */ async act(input: string, context?: string): Promise { // First, create a plan this.currentPlan = await this.createPlan(input); // Execute the plan const result = await this.executePlan(); this.taskHistory.push(result); return { content: result.success ? `Task completed successfully.\n${JSON.stringify(result.output, null, 2)}` : `Task failed. Errors: ${result.errors.join(', ')}`, tokens: { prompt: 0, completion: 0, total: 0 }, metadata: { plan: this.currentPlan, result } }; } /** * Create a plan for a task */ private async createPlan(taskDescription: string): Promise { const planningPrompt = `Break down the following task into steps. For each step, provide a brief description. Task: ${taskDescription} Respond in JSON format: { "steps": [ { "id": "step1", "description": "First step description" }, { "id": "step2", "description": "Second step description" } ], "complexity": "low|medium|high", "dependencies": { "step2": ["step1"] } }`; const response = await this.process(planningPrompt); try { // Extract JSON from response const jsonMatch = response.content.match(/\{[\s\S]*\}/); if (jsonMatch) { const plan = JSON.parse(jsonMatch[0]); return { steps: plan.steps.map((s: TaskStep) => ({ ...s, status: 'pending' as const })), estimatedComplexity: plan.complexity || 'medium', dependencies: new Map(Object.entries(plan.dependencies || {})) }; } } catch { // Fall back to simple plan } // Default simple plan return { steps: [{ id: 'step1', description: taskDescription, status: 'pending' }], estimatedComplexity: 'low', dependencies: new Map() }; } /** * Execute the current plan */ private async executePlan(): Promise { if (!this.currentPlan) { return { success: false, steps: [], output: null, errors: ['No plan available'] }; } const errors: string[] = []; const completedSteps = new Set(); // Execute steps in order, respecting dependencies for (const step of this.currentPlan.steps) { // Check dependencies const deps = this.currentPlan.dependencies.get(step.id) || []; const depsMet = deps.every(depId => completedSteps.has(depId)); if (!depsMet) { step.status = 'failed'; step.error = 'Dependencies not met'; errors.push(`Step ${step.id}: Dependencies not met`); continue; } // Execute step step.status = 'running'; try { const result = await this.executeStep(step.id); step.status = 'completed'; step.result = result; completedSteps.add(step.id); } catch (error) { step.status = 'failed'; step.error = String(error); errors.push(`Step ${step.id}: ${error}`); } } const success = errors.length === 0; const finalStep = this.currentPlan.steps[this.currentPlan.steps.length - 1]; return { success, steps: this.currentPlan.steps, output: finalStep.result, errors }; } /** * Execute a single step */ private async executeStep(stepId: string): Promise { if (!this.currentPlan) throw new Error('No plan available'); const step = this.currentPlan.steps.find(s => s.id === stepId); if (!step) throw new Error(`Step ${stepId} not found`); const response = await this.process( `Execute the following step and provide the result:\n\n${step.description}` ); return response.content; } /** * Get task history */ getTaskHistory(): TaskResult[] { return [...this.taskHistory]; } /** * Get current plan */ getCurrentPlan(): TaskPlan | null { return this.currentPlan; } } /** * Create a task agent */ export function createTaskAgent( name: string, systemPrompt: string, options?: { description?: string; tools?: AgentTool[]; } ): TaskAgent { return new TaskAgent({ name, systemPrompt, description: options?.description || `Task Agent: ${name}`, tools: options?.tools }); }