feat(tools): add ToolRegistry, ToolSearchTool and ExpertTool to support on-demand tool visibility, discovery, activation, and expert/subagent tooling; extend DualAgentOrchestrator API and interfaces to manage tool lifecycle
This commit is contained in:
@@ -8,6 +8,9 @@ import { HttpTool } from './smartagent.tools.http.js';
|
||||
import { ShellTool } from './smartagent.tools.shell.js';
|
||||
import { BrowserTool } from './smartagent.tools.browser.js';
|
||||
import { DenoTool } from './smartagent.tools.deno.js';
|
||||
import { ToolRegistry } from './smartagent.classes.toolregistry.js';
|
||||
import { ToolSearchTool } from './smartagent.tools.search.js';
|
||||
import { ExpertTool } from './smartagent.tools.expert.js';
|
||||
|
||||
/**
|
||||
* DualAgentOrchestrator - Coordinates Driver and Guardian agents
|
||||
@@ -20,7 +23,7 @@ export class DualAgentOrchestrator {
|
||||
private guardianProvider: plugins.smartai.MultiModalModel;
|
||||
private driver: DriverAgent;
|
||||
private guardian: GuardianAgent;
|
||||
private tools: Map<string, BaseToolWrapper> = new Map();
|
||||
private registry: ToolRegistry = new ToolRegistry();
|
||||
private isRunning = false;
|
||||
private conversationHistory: interfaces.IAgentMessage[] = [];
|
||||
private ownsSmartAi = true; // true if we created the SmartAi instance, false if it was provided
|
||||
@@ -125,19 +128,55 @@ export class DualAgentOrchestrator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom tool
|
||||
* Register a custom tool with optional visibility settings
|
||||
*/
|
||||
public registerTool(tool: BaseToolWrapper): void {
|
||||
this.tools.set(tool.name, tool);
|
||||
// Register with agents if they exist (they're created in start())
|
||||
if (this.driver) {
|
||||
this.driver.registerTool(tool);
|
||||
}
|
||||
if (this.guardian) {
|
||||
this.guardian.registerTool(tool);
|
||||
public registerTool(
|
||||
tool: BaseToolWrapper,
|
||||
options?: interfaces.IToolRegistrationOptions
|
||||
): void {
|
||||
this.registry.register(tool, options);
|
||||
|
||||
// If initial visibility and agents exist, register with them
|
||||
const visibility = options?.visibility ?? 'initial';
|
||||
if (visibility === 'initial') {
|
||||
if (this.driver) {
|
||||
this.driver.registerTool(tool);
|
||||
}
|
||||
if (this.guardian) {
|
||||
this.guardian.registerTool(tool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an expert (subagent) as a tool
|
||||
*/
|
||||
public registerExpert(config: interfaces.IExpertConfig): void {
|
||||
const expert = new ExpertTool(config, this.smartai);
|
||||
this.registerTool(expert, {
|
||||
visibility: config.visibility,
|
||||
tags: config.tags,
|
||||
category: config.category ?? 'expert',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable tool search functionality
|
||||
* This adds a 'tools' tool that allows the Driver to discover and activate on-demand tools
|
||||
*/
|
||||
public enableToolSearch(): void {
|
||||
const searchTool = new ToolSearchTool(this.registry, (tool) => {
|
||||
// Callback when an on-demand tool is activated
|
||||
if (this.driver) {
|
||||
this.driver.registerTool(tool);
|
||||
}
|
||||
if (this.guardian) {
|
||||
this.guardian.registerTool(tool);
|
||||
}
|
||||
});
|
||||
this.registerTool(searchTool); // Always initial visibility
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all standard tools
|
||||
*/
|
||||
@@ -193,19 +232,14 @@ export class DualAgentOrchestrator {
|
||||
});
|
||||
this.guardian = new GuardianAgent(this.guardianProvider, this.options.guardianPolicyPrompt);
|
||||
|
||||
// Register any tools that were added before start() with the agents
|
||||
for (const tool of this.tools.values()) {
|
||||
// Register visible tools with agents
|
||||
for (const tool of this.registry.getVisibleTools()) {
|
||||
this.driver.registerTool(tool);
|
||||
this.guardian.registerTool(tool);
|
||||
}
|
||||
|
||||
// Initialize all tools
|
||||
const initPromises: Promise<void>[] = [];
|
||||
for (const tool of this.tools.values()) {
|
||||
initPromises.push(tool.initialize());
|
||||
}
|
||||
|
||||
await Promise.all(initPromises);
|
||||
// Initialize visible tools
|
||||
await this.registry.initializeVisibleTools();
|
||||
this.isRunning = true;
|
||||
}
|
||||
|
||||
@@ -213,13 +247,7 @@ export class DualAgentOrchestrator {
|
||||
* Cleanup all tools
|
||||
*/
|
||||
public async stop(): Promise<void> {
|
||||
const cleanupPromises: Promise<void>[] = [];
|
||||
|
||||
for (const tool of this.tools.values()) {
|
||||
cleanupPromises.push(tool.cleanup());
|
||||
}
|
||||
|
||||
await Promise.all(cleanupPromises);
|
||||
await this.registry.cleanup();
|
||||
|
||||
// Only stop smartai if we created it (don't stop external instances)
|
||||
if (this.ownsSmartAi) {
|
||||
@@ -432,7 +460,7 @@ Please output the exact XML format above.`
|
||||
});
|
||||
|
||||
// Execute the tool
|
||||
const tool = this.tools.get(proposal.toolName);
|
||||
const tool = this.registry.getTool(proposal.toolName);
|
||||
if (!tool) {
|
||||
const errorMessage = `Tool "${proposal.toolName}" not found.`;
|
||||
driverResponse = await this.driver.continueWithMessage(
|
||||
@@ -652,6 +680,13 @@ Please output the exact XML format above.`
|
||||
* Get registered tool names
|
||||
*/
|
||||
public getToolNames(): string[] {
|
||||
return Array.from(this.tools.keys());
|
||||
return this.registry.getAllMetadata().map((m) => m.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tool registry for advanced operations
|
||||
*/
|
||||
public getRegistry(): ToolRegistry {
|
||||
return this.registry;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user