import * as plugins from './plugins.js'; import * as interfaces from './smartagent.interfaces.js'; import { BaseToolWrapper } from './smartagent.tools.base.js'; // Forward declaration to avoid circular import at module load time // The actual import happens lazily in initialize() let DualAgentOrchestrator: typeof import('./smartagent.classes.dualagent.js').DualAgentOrchestrator; /** * ExpertTool - A specialized agent wrapped as a tool * * Enables hierarchical agent architectures where the Driver can delegate * complex tasks to specialized experts with their own tools and policies. */ export class ExpertTool extends BaseToolWrapper { public name: string; public description: string; public actions: interfaces.IToolAction[] = [ { name: 'consult', description: 'Delegate a task or question to this expert', parameters: { type: 'object', properties: { task: { type: 'string', description: 'The task or question for the expert' }, context: { type: 'string', description: 'Additional context to help the expert' }, }, required: ['task'], }, }, ]; private config: interfaces.IExpertConfig; private smartAi: plugins.smartai.SmartAi; private inner?: InstanceType; constructor(config: interfaces.IExpertConfig, smartAi: plugins.smartai.SmartAi) { super(); this.config = config; this.smartAi = smartAi; this.name = config.name; this.description = config.description; } async initialize(): Promise { // Lazy import to avoid circular dependency if (!DualAgentOrchestrator) { const module = await import('./smartagent.classes.dualagent.js'); DualAgentOrchestrator = module.DualAgentOrchestrator; } this.inner = new DualAgentOrchestrator({ smartAiInstance: this.smartAi, // Share SmartAi instance defaultProvider: this.config.provider, driverSystemMessage: this.config.systemMessage, guardianPolicyPrompt: this.config.guardianPolicy, maxIterations: this.config.maxIterations ?? 10, }); // Register expert's tools if (this.config.tools) { for (const tool of this.config.tools) { // Tools in the config are IAgentToolWrapper, but we need BaseToolWrapper // Since all our tools extend BaseToolWrapper, this cast is safe this.inner.registerTool(tool as BaseToolWrapper); } } await this.inner.start(); this.isInitialized = true; } async cleanup(): Promise { if (this.inner) { await this.inner.stop(); this.inner = undefined; } this.isInitialized = false; } async execute( action: string, params: Record ): Promise { this.validateAction(action); this.ensureInitialized(); const task = params.task as string; const context = params.context as string | undefined; const fullTask = context ? `Context: ${context}\n\nTask: ${task}` : task; try { const result = await this.inner!.run(fullTask); return { success: result.success, result: { response: result.result, iterations: result.iterations, status: result.status, }, summary: result.success ? `Expert "${this.name}" completed (${result.iterations} iterations)` : `Expert "${this.name}" failed: ${result.status}`, }; } catch (error) { return { success: false, error: `Expert error: ${error instanceof Error ? error.message : String(error)}`, }; } } getCallSummary(action: string, params: Record): string { const task = params.task as string; const preview = task.length > 60 ? task.substring(0, 60) + '...' : task; return `Consult ${this.name}: "${preview}"`; } getToolExplanation(): string { return `## Expert: ${this.name} ${this.description} ### Usage: Delegate tasks to this expert when you need specialized help. \`\`\` ${this.name} consult {"task": "Your question or task", "context": "Optional background"} \`\`\` `; } /** * Get the expert's configuration */ getConfig(): interfaces.IExpertConfig { return this.config; } }