Files
smartagent/ts/smartagent.classes.toolregistry.ts

189 lines
4.6 KiB
TypeScript
Raw Permalink Normal View History

import * as interfaces from './smartagent.interfaces.js';
import { BaseToolWrapper } from './smartagent.tools.base.js';
/**
* ToolRegistry - Manages tool registration, visibility, and lifecycle
*
* Responsibilities:
* - Track all registered tools with their metadata
* - Manage visibility (initial vs on-demand)
* - Handle activation of on-demand tools
* - Provide search functionality
*/
export class ToolRegistry {
private tools: Map<string, BaseToolWrapper> = new Map();
private metadata: Map<string, interfaces.IToolMetadata> = new Map();
private activated: Set<string> = new Set();
/**
* Register a tool with optional visibility settings
*/
register(tool: BaseToolWrapper, options: interfaces.IToolRegistrationOptions = {}): void {
const visibility = options.visibility ?? 'initial';
this.tools.set(tool.name, tool);
this.metadata.set(tool.name, {
name: tool.name,
description: tool.description,
actions: tool.actions,
visibility,
isActivated: visibility === 'initial',
isInitialized: false,
tags: options.tags,
category: options.category,
});
if (visibility === 'initial') {
this.activated.add(tool.name);
}
}
/**
* Get tools visible to the Driver (initial + activated on-demand)
*/
getVisibleTools(): BaseToolWrapper[] {
return Array.from(this.tools.entries())
.filter(([name]) => this.activated.has(name))
.map(([, tool]) => tool);
}
/**
* Get all tools (for search results)
*/
getAllTools(): BaseToolWrapper[] {
return Array.from(this.tools.values());
}
/**
* Get a specific tool by name
*/
getTool(name: string): BaseToolWrapper | undefined {
return this.tools.get(name);
}
/**
* Get metadata for a tool
*/
getMetadata(name: string): interfaces.IToolMetadata | undefined {
return this.metadata.get(name);
}
/**
* Get all metadata
*/
getAllMetadata(): interfaces.IToolMetadata[] {
return Array.from(this.metadata.values());
}
/**
* Search tools by query (matches name, description, tags, action names)
*/
search(query: string): interfaces.IToolMetadata[] {
const q = query.toLowerCase();
return this.getAllMetadata().filter((meta) => {
if (meta.name.toLowerCase().includes(q)) return true;
if (meta.description.toLowerCase().includes(q)) return true;
if (meta.tags?.some((t) => t.toLowerCase().includes(q))) return true;
if (meta.category?.toLowerCase().includes(q)) return true;
if (
meta.actions.some(
(a) => a.name.toLowerCase().includes(q) || a.description.toLowerCase().includes(q)
)
)
return true;
return false;
});
}
/**
* Activate an on-demand tool
*/
async activate(name: string): Promise<{ success: boolean; error?: string }> {
const tool = this.tools.get(name);
const meta = this.metadata.get(name);
if (!tool || !meta) {
return { success: false, error: `Tool "${name}" not found` };
}
if (this.activated.has(name)) {
return { success: true }; // Already activated
}
// Initialize if not already initialized
if (!meta.isInitialized) {
await tool.initialize();
meta.isInitialized = true;
}
this.activated.add(name);
meta.isActivated = true;
return { success: true };
}
/**
* Check if a tool is activated
*/
isActivated(name: string): boolean {
return this.activated.has(name);
}
/**
* Initialize all initial (visible) tools
*/
async initializeVisibleTools(): Promise<void> {
const promises: Promise<void>[] = [];
for (const [name, tool] of this.tools) {
const meta = this.metadata.get(name);
if (meta && this.activated.has(name) && !meta.isInitialized) {
promises.push(
tool.initialize().then(() => {
meta.isInitialized = true;
})
);
}
}
await Promise.all(promises);
}
/**
* Cleanup all initialized tools
*/
async cleanup(): Promise<void> {
const promises: Promise<void>[] = [];
for (const [name, tool] of this.tools) {
const meta = this.metadata.get(name);
if (meta?.isInitialized) {
promises.push(tool.cleanup());
}
}
await Promise.all(promises);
}
/**
* Check if a tool exists in the registry
*/
has(name: string): boolean {
return this.tools.has(name);
}
/**
* Get the number of registered tools
*/
get size(): number {
return this.tools.size;
}
/**
* Get the number of activated tools
*/
get activatedCount(): number {
return this.activated.size;
}
}