BREAKING CHANGE(api): Migrate public API to ai-sdk v6 and refactor core agent architecture: replace class-based DualAgent/Driver/Guardian with a single runAgent function; introduce ts_tools factories for tools, a compactMessages compaction subpath, and truncateOutput utility; simplify ToolRegistry to return ToolSet and remove legacy BaseToolWrapper/tool classes; update package exports and dependencies and bump major version.
This commit is contained in:
@@ -1,188 +1,20 @@
|
||||
import * as interfaces from './smartagent.interfaces.js';
|
||||
import { BaseToolWrapper } from './smartagent.tools.base.js';
|
||||
import type { ToolSet } from './plugins.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();
|
||||
private tools: ToolSet = {};
|
||||
|
||||
/**
|
||||
* Register a tool with optional visibility settings
|
||||
* Register a tool.
|
||||
* @param name Tool name (must be unique, snake_case recommended)
|
||||
* @param def Tool definition created with ai-sdk's tool() helper
|
||||
*/
|
||||
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);
|
||||
}
|
||||
public register(name: string, def: ToolSet[string]): this {
|
||||
this.tools[name] = def;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/** Get the full ToolSet for passing to runAgent */
|
||||
public getTools(): ToolSet {
|
||||
return { ...this.tools };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user