Files
smartagent/ts/smartagent.tools.search.ts

238 lines
6.3 KiB
TypeScript
Raw Permalink Normal View History

import * as interfaces from './smartagent.interfaces.js';
import { BaseToolWrapper } from './smartagent.tools.base.js';
import { ToolRegistry } from './smartagent.classes.toolregistry.js';
/**
* ToolSearchTool - AI-facing interface for discovering and activating tools
*
* This tool enables the Driver to:
* - Search for tools by capability
* - List all available tools
* - Activate on-demand tools
* - Get detailed information about specific tools
*/
export class ToolSearchTool extends BaseToolWrapper {
public name = 'tools';
public description =
'Search for and activate available tools and experts. Use this to discover specialized capabilities.';
public actions: interfaces.IToolAction[] = [
{
name: 'search',
description: 'Search for tools by name, description, tags, or capabilities',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
},
{
name: 'list',
description: 'List all available tools grouped by visibility',
parameters: { type: 'object', properties: {} },
},
{
name: 'activate',
description: 'Activate an on-demand tool to make it available for use',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name of the tool to activate' },
},
required: ['name'],
},
},
{
name: 'details',
description: 'Get detailed information about a specific tool',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name of the tool' },
},
required: ['name'],
},
},
];
private registry: ToolRegistry;
private onToolActivated?: (tool: BaseToolWrapper) => void;
constructor(registry: ToolRegistry, onToolActivated?: (tool: BaseToolWrapper) => void) {
super();
this.registry = registry;
this.onToolActivated = onToolActivated;
}
async initialize(): Promise<void> {
this.isInitialized = true;
}
async cleanup(): Promise<void> {
this.isInitialized = false;
}
async execute(
action: string,
params: Record<string, unknown>
): Promise<interfaces.IToolExecutionResult> {
this.validateAction(action);
switch (action) {
case 'search':
return this.handleSearch(params.query as string);
case 'list':
return this.handleList();
case 'activate':
return this.handleActivate(params.name as string);
case 'details':
return this.handleDetails(params.name as string);
default:
return { success: false, error: `Unknown action: ${action}` };
}
}
private handleSearch(query: string): interfaces.IToolExecutionResult {
const results = this.registry.search(query);
return {
success: true,
result: results.map((m) => ({
name: m.name,
description: m.description,
visibility: m.visibility,
isActivated: m.isActivated,
category: m.category,
tags: m.tags,
actionCount: m.actions.length,
})),
summary: `Found ${results.length} tools matching "${query}"`,
};
}
private handleList(): interfaces.IToolExecutionResult {
const all = this.registry.getAllMetadata();
const initial = all.filter((m) => m.visibility === 'initial');
const onDemand = all.filter((m) => m.visibility === 'on-demand');
return {
success: true,
result: {
initial: initial.map((m) => ({
name: m.name,
description: m.description,
category: m.category,
})),
onDemand: onDemand.map((m) => ({
name: m.name,
description: m.description,
category: m.category,
isActivated: m.isActivated,
})),
summary: `${initial.length} initial, ${onDemand.length} on-demand`,
},
};
}
private async handleActivate(name: string): Promise<interfaces.IToolExecutionResult> {
const result = await this.registry.activate(name);
if (result.success && this.onToolActivated) {
const tool = this.registry.getTool(name);
if (tool) {
this.onToolActivated(tool);
}
}
return {
success: result.success,
result: result.success ? { name, message: `Tool "${name}" is now available` } : undefined,
error: result.error,
summary: result.success ? `Activated: ${name}` : result.error,
};
}
private handleDetails(name: string): interfaces.IToolExecutionResult {
const tool = this.registry.getTool(name);
const meta = this.registry.getMetadata(name);
if (!tool || !meta) {
return { success: false, error: `Tool "${name}" not found` };
}
return {
success: true,
result: {
name: meta.name,
description: meta.description,
visibility: meta.visibility,
isActivated: meta.isActivated,
category: meta.category,
tags: meta.tags,
actions: meta.actions,
fullExplanation: tool.getToolExplanation(),
},
};
}
getCallSummary(action: string, params: Record<string, unknown>): string {
switch (action) {
case 'search':
return `Search tools: "${params.query}"`;
case 'list':
return 'List all tools';
case 'activate':
return `Activate tool: ${params.name}`;
case 'details':
return `Get details: ${params.name}`;
default:
return `tools.${action}`;
}
}
getToolExplanation(): string {
return `## Tool: tools
Search for and manage available tools and experts.
### Actions:
**search** - Find tools by capability
\`\`\`
<tool_call>
<tool>tools</tool>
<action>search</action>
<params>{"query": "database"}</params>
</tool_call>
\`\`\`
**list** - List all tools grouped by visibility
\`\`\`
<tool_call>
<tool>tools</tool>
<action>list</action>
<params>{}</params>
</tool_call>
\`\`\`
**activate** - Activate an on-demand tool
\`\`\`
<tool_call>
<tool>tools</tool>
<action>activate</action>
<params>{"name": "database_expert"}</params>
</tool_call>
\`\`\`
**details** - Get full information about a tool
\`\`\`
<tool_call>
<tool>tools</tool>
<action>details</action>
<params>{"name": "filesystem"}</params>
</tool_call>
\`\`\`
`;
}
}