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:
2026-03-06 11:39:01 +00:00
parent 903de44644
commit f9a9c9fb48
36 changed files with 3928 additions and 6586 deletions

View File

@@ -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 };
}
}