@push.rocks/smartagent 1.6.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +3 -0
- package/dist_ts/index.js +6 -1
- package/dist_ts/smartagent.classes.dualagent.d.ts +17 -3
- package/dist_ts/smartagent.classes.dualagent.js +57 -26
- package/dist_ts/smartagent.classes.toolregistry.d.ts +75 -0
- package/dist_ts/smartagent.classes.toolregistry.js +161 -0
- package/dist_ts/smartagent.interfaces.d.ts +52 -0
- package/dist_ts/smartagent.interfaces.js +1 -1
- package/dist_ts/smartagent.tools.expert.d.ts +27 -0
- package/dist_ts/smartagent.tools.expert.js +126 -0
- package/dist_ts/smartagent.tools.search.d.ts +29 -0
- package/dist_ts/smartagent.tools.search.js +215 -0
- package/package.json +1 -1
- package/readme.hints.md +60 -3
- package/readme.md +205 -11
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +7 -0
- package/ts/smartagent.classes.dualagent.ts +63 -28
- package/ts/smartagent.classes.toolregistry.ts +188 -0
- package/ts/smartagent.interfaces.ts +60 -0
- package/ts/smartagent.tools.expert.ts +144 -0
- package/ts/smartagent.tools.search.ts +237 -0
package/readme.md
CHANGED
|
@@ -37,20 +37,19 @@ flowchart TB
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
subgraph Orchestrator["DualAgentOrchestrator"]
|
|
40
|
+
Registry["ToolRegistry<br/><i>Visibility & Lifecycle</i>"]
|
|
40
41
|
Driver["Driver Agent<br/><i>Reason + Plan</i>"]
|
|
41
42
|
Guardian["Guardian Agent<br/><i>Evaluate against policy</i>"]
|
|
42
43
|
|
|
43
44
|
Driver -->|"tool call proposal"| Guardian
|
|
44
45
|
Guardian -->|"approve / reject + feedback"| Driver
|
|
46
|
+
Registry -->|"visible tools"| Driver
|
|
45
47
|
end
|
|
46
48
|
|
|
47
|
-
subgraph Tools["
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Browser["Browser"]
|
|
52
|
-
Deno["Deno"]
|
|
53
|
-
JSON["JSON Validator"]
|
|
49
|
+
subgraph Tools["Tools"]
|
|
50
|
+
Initial["Initial Tools<br/><i>Always visible</i>"]
|
|
51
|
+
OnDemand["On-Demand Tools<br/><i>Discoverable via search</i>"]
|
|
52
|
+
Experts["Expert SubAgents<br/><i>Specialized agents as tools</i>"]
|
|
54
53
|
end
|
|
55
54
|
|
|
56
55
|
Task --> Orchestrator
|
|
@@ -100,7 +99,7 @@ await orchestrator.stop();
|
|
|
100
99
|
|
|
101
100
|
## Standard Tools
|
|
102
101
|
|
|
103
|
-
SmartAgent comes with
|
|
102
|
+
SmartAgent comes with five battle-tested tools out of the box via `registerStandardTools()`:
|
|
104
103
|
|
|
105
104
|
### 🗂️ FilesystemTool
|
|
106
105
|
|
|
@@ -231,12 +230,21 @@ By default, code runs **fully sandboxed with no permissions**. Permissions must
|
|
|
231
230
|
</tool_call>
|
|
232
231
|
```
|
|
233
232
|
|
|
233
|
+
## Additional Tools
|
|
234
|
+
|
|
234
235
|
### 📋 JsonValidatorTool
|
|
235
236
|
|
|
236
237
|
Validate and format JSON data. Perfect for agents to self-check their JSON output before completing tasks.
|
|
237
238
|
|
|
238
239
|
**Actions**: `validate`, `format`
|
|
239
240
|
|
|
241
|
+
```typescript
|
|
242
|
+
import { JsonValidatorTool } from '@push.rocks/smartagent';
|
|
243
|
+
|
|
244
|
+
// Register the JSON validator tool (not included in registerStandardTools)
|
|
245
|
+
orchestrator.registerTool(new JsonValidatorTool());
|
|
246
|
+
```
|
|
247
|
+
|
|
240
248
|
```typescript
|
|
241
249
|
// Validate JSON with required field checking
|
|
242
250
|
<tool_call>
|
|
@@ -258,6 +266,157 @@ Validate and format JSON data. Perfect for agents to self-check their JSON outpu
|
|
|
258
266
|
</tool_call>
|
|
259
267
|
```
|
|
260
268
|
|
|
269
|
+
### 🔍 ToolSearchTool
|
|
270
|
+
|
|
271
|
+
Enable the Driver to discover and activate on-demand tools at runtime.
|
|
272
|
+
|
|
273
|
+
**Actions**: `search`, `list`, `activate`, `details`
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// Enable tool search (adds the 'tools' tool)
|
|
277
|
+
orchestrator.enableToolSearch();
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
// Search for tools by capability
|
|
282
|
+
<tool_call>
|
|
283
|
+
<tool>tools</tool>
|
|
284
|
+
<action>search</action>
|
|
285
|
+
<params>{"query": "database"}</params>
|
|
286
|
+
</tool_call>
|
|
287
|
+
|
|
288
|
+
// List all available tools
|
|
289
|
+
<tool_call>
|
|
290
|
+
<tool>tools</tool>
|
|
291
|
+
<action>list</action>
|
|
292
|
+
<params>{}</params>
|
|
293
|
+
</tool_call>
|
|
294
|
+
|
|
295
|
+
// Activate an on-demand tool
|
|
296
|
+
<tool_call>
|
|
297
|
+
<tool>tools</tool>
|
|
298
|
+
<action>activate</action>
|
|
299
|
+
<params>{"name": "database_expert"}</params>
|
|
300
|
+
</tool_call>
|
|
301
|
+
|
|
302
|
+
// Get detailed information about a tool
|
|
303
|
+
<tool_call>
|
|
304
|
+
<tool>tools</tool>
|
|
305
|
+
<action>details</action>
|
|
306
|
+
<params>{"name": "filesystem"}</params>
|
|
307
|
+
</tool_call>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### 🧠 ExpertTool (SubAgents)
|
|
311
|
+
|
|
312
|
+
Create specialized sub-agents that can be invoked as tools. Experts are complete `DualAgentOrchestrator` instances wrapped as tools, enabling hierarchical agent architectures.
|
|
313
|
+
|
|
314
|
+
**Actions**: `consult`
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// Register an expert for code review
|
|
318
|
+
orchestrator.registerExpert({
|
|
319
|
+
name: 'code_reviewer',
|
|
320
|
+
description: 'Reviews code for quality, bugs, and best practices',
|
|
321
|
+
systemMessage: `You are an expert code reviewer. Analyze code for:
|
|
322
|
+
- Bugs and potential issues
|
|
323
|
+
- Code style and best practices
|
|
324
|
+
- Performance concerns
|
|
325
|
+
- Security vulnerabilities`,
|
|
326
|
+
guardianPolicy: 'Allow read-only file access within the workspace',
|
|
327
|
+
tools: [new FilesystemTool()],
|
|
328
|
+
visibility: 'on-demand', // Only available via tool search
|
|
329
|
+
tags: ['code', 'review', 'quality'],
|
|
330
|
+
category: 'expert',
|
|
331
|
+
});
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
// Consult an expert
|
|
336
|
+
<tool_call>
|
|
337
|
+
<tool>code_reviewer</tool>
|
|
338
|
+
<action>consult</action>
|
|
339
|
+
<params>{
|
|
340
|
+
"task": "Review this function for potential issues",
|
|
341
|
+
"context": "This is a user authentication handler"
|
|
342
|
+
}</params>
|
|
343
|
+
</tool_call>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## 🎯 Tool Visibility System
|
|
347
|
+
|
|
348
|
+
SmartAgent supports **tool visibility modes** for scalable agent architectures:
|
|
349
|
+
|
|
350
|
+
- **`initial`** (default): Tool is visible to the Driver from the start, included in the system prompt
|
|
351
|
+
- **`on-demand`**: Tool is hidden until explicitly activated via `tools.activate()`
|
|
352
|
+
|
|
353
|
+
This enables you to have many specialized tools/experts without overwhelming the Driver's context.
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
// Register a tool with on-demand visibility
|
|
357
|
+
orchestrator.registerTool(new MySpecializedTool(), {
|
|
358
|
+
visibility: 'on-demand',
|
|
359
|
+
tags: ['specialized', 'database'],
|
|
360
|
+
category: 'data',
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
// Enable tool search so Driver can discover and activate on-demand tools
|
|
364
|
+
orchestrator.enableToolSearch();
|
|
365
|
+
|
|
366
|
+
// The Driver can now:
|
|
367
|
+
// 1. tools.search({"query": "database"}) -> finds MySpecializedTool
|
|
368
|
+
// 2. tools.activate({"name": "myspecialized"}) -> enables it
|
|
369
|
+
// 3. myspecialized.action({...}) -> use the tool
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Expert SubAgent Example
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const orchestrator = new DualAgentOrchestrator({
|
|
376
|
+
openaiToken: 'sk-...',
|
|
377
|
+
defaultProvider: 'openai',
|
|
378
|
+
guardianPolicyPrompt: 'Allow safe operations...',
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
orchestrator.registerStandardTools();
|
|
382
|
+
orchestrator.enableToolSearch();
|
|
383
|
+
|
|
384
|
+
// Initial expert (always visible)
|
|
385
|
+
orchestrator.registerExpert({
|
|
386
|
+
name: 'code_assistant',
|
|
387
|
+
description: 'Helps with coding tasks and code generation',
|
|
388
|
+
systemMessage: 'You are a helpful coding assistant...',
|
|
389
|
+
guardianPolicy: 'Allow read-only file access',
|
|
390
|
+
tools: [new FilesystemTool()],
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// On-demand experts (discoverable via search)
|
|
394
|
+
orchestrator.registerExpert({
|
|
395
|
+
name: 'database_expert',
|
|
396
|
+
description: 'Database design, optimization, and query analysis',
|
|
397
|
+
systemMessage: 'You are a database expert...',
|
|
398
|
+
guardianPolicy: 'Allow read-only operations',
|
|
399
|
+
visibility: 'on-demand',
|
|
400
|
+
tags: ['database', 'sql', 'optimization'],
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
orchestrator.registerExpert({
|
|
404
|
+
name: 'security_auditor',
|
|
405
|
+
description: 'Security vulnerability assessment and best practices',
|
|
406
|
+
systemMessage: 'You are a security expert...',
|
|
407
|
+
guardianPolicy: 'Allow read-only file access',
|
|
408
|
+
visibility: 'on-demand',
|
|
409
|
+
tags: ['security', 'audit', 'vulnerabilities'],
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
await orchestrator.start();
|
|
413
|
+
|
|
414
|
+
// Now the Driver can:
|
|
415
|
+
// - Use code_assistant directly
|
|
416
|
+
// - Search for "database" and activate database_expert when needed
|
|
417
|
+
// - Search for "security" and activate security_auditor when needed
|
|
418
|
+
```
|
|
419
|
+
|
|
261
420
|
## 🎥 Streaming Support
|
|
262
421
|
|
|
263
422
|
SmartAgent supports token-by-token streaming for real-time output during LLM generation:
|
|
@@ -330,6 +489,29 @@ const orchestrator = new DualAgentOrchestrator({
|
|
|
330
489
|
|
|
331
490
|
**Event Types**: `task_started`, `iteration_started`, `tool_proposed`, `guardian_evaluating`, `tool_approved`, `tool_rejected`, `tool_executing`, `tool_completed`, `task_completed`, `clarification_needed`, `max_iterations`, `max_rejections`
|
|
332
491
|
|
|
492
|
+
## 🔧 Native Tool Calling
|
|
493
|
+
|
|
494
|
+
For providers that support native tool calling (like Ollama with certain models), SmartAgent can use the provider's built-in tool calling API instead of XML parsing:
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
const orchestrator = new DualAgentOrchestrator({
|
|
498
|
+
ollamaToken: 'http://localhost:11434', // Ollama endpoint
|
|
499
|
+
defaultProvider: 'ollama',
|
|
500
|
+
guardianPolicyPrompt: '...',
|
|
501
|
+
|
|
502
|
+
// Enable native tool calling
|
|
503
|
+
useNativeToolCalling: true,
|
|
504
|
+
});
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
When `useNativeToolCalling` is enabled:
|
|
508
|
+
- Tools are converted to JSON schema format automatically
|
|
509
|
+
- The provider handles tool call parsing natively
|
|
510
|
+
- Streaming still works with `[THINKING]` and `[OUTPUT]` markers for supported models
|
|
511
|
+
- Tool calls appear as `toolName_actionName` (e.g., `json_validate`)
|
|
512
|
+
|
|
513
|
+
This is more efficient for models that support it and avoids potential XML parsing issues.
|
|
514
|
+
|
|
333
515
|
## Guardian Policy Examples
|
|
334
516
|
|
|
335
517
|
The Guardian's power comes from your policy. Here are battle-tested examples:
|
|
@@ -401,6 +583,7 @@ interface IDualAgentOptions {
|
|
|
401
583
|
perplexityToken?: string;
|
|
402
584
|
groqToken?: string;
|
|
403
585
|
xaiToken?: string;
|
|
586
|
+
ollamaToken?: string; // URL for Ollama endpoint
|
|
404
587
|
|
|
405
588
|
// Use existing SmartAi instance (optional - avoids duplicate providers)
|
|
406
589
|
smartAiInstance?: SmartAi;
|
|
@@ -415,6 +598,9 @@ interface IDualAgentOptions {
|
|
|
415
598
|
name?: string; // Agent system name
|
|
416
599
|
verbose?: boolean; // Enable verbose logging
|
|
417
600
|
|
|
601
|
+
// Native tool calling
|
|
602
|
+
useNativeToolCalling?: boolean; // Use provider's native tool calling API (default: false)
|
|
603
|
+
|
|
418
604
|
// Limits
|
|
419
605
|
maxIterations?: number; // Max task iterations (default: 20)
|
|
420
606
|
maxConsecutiveRejections?: number; // Abort after N rejections (default: 3)
|
|
@@ -573,12 +759,15 @@ const orchestrator = new DualAgentOrchestrator({
|
|
|
573
759
|
| `stop()` | Cleanup all tools and resources |
|
|
574
760
|
| `run(task, options?)` | Execute a task with optional images for vision |
|
|
575
761
|
| `continueTask(input)` | Continue a task with user input |
|
|
576
|
-
| `registerTool(tool)` | Register a custom tool |
|
|
577
|
-
| `registerStandardTools()` | Register all built-in tools |
|
|
762
|
+
| `registerTool(tool, options?)` | Register a custom tool with optional visibility settings |
|
|
763
|
+
| `registerStandardTools()` | Register all built-in tools (Filesystem, HTTP, Shell, Browser, Deno) |
|
|
578
764
|
| `registerScopedFilesystemTool(basePath, excludePatterns?)` | Register filesystem tool with path restriction |
|
|
765
|
+
| `registerExpert(config)` | Register a specialized sub-agent as a tool |
|
|
766
|
+
| `enableToolSearch()` | Enable tool discovery and activation for the Driver |
|
|
579
767
|
| `setGuardianPolicy(policy)` | Update Guardian policy at runtime |
|
|
580
768
|
| `getHistory()` | Get conversation history |
|
|
581
769
|
| `getToolNames()` | Get list of registered tool names |
|
|
770
|
+
| `getRegistry()` | Get the ToolRegistry for advanced operations |
|
|
582
771
|
| `isActive()` | Check if orchestrator is running |
|
|
583
772
|
|
|
584
773
|
### Exports
|
|
@@ -589,6 +778,9 @@ export { DualAgentOrchestrator } from '@push.rocks/smartagent';
|
|
|
589
778
|
export { DriverAgent } from '@push.rocks/smartagent';
|
|
590
779
|
export { GuardianAgent } from '@push.rocks/smartagent';
|
|
591
780
|
|
|
781
|
+
// Tool Registry
|
|
782
|
+
export { ToolRegistry } from '@push.rocks/smartagent';
|
|
783
|
+
|
|
592
784
|
// Tools
|
|
593
785
|
export { BaseToolWrapper } from '@push.rocks/smartagent';
|
|
594
786
|
export { FilesystemTool, type IFilesystemToolOptions } from '@push.rocks/smartagent';
|
|
@@ -597,9 +789,11 @@ export { ShellTool } from '@push.rocks/smartagent';
|
|
|
597
789
|
export { BrowserTool } from '@push.rocks/smartagent';
|
|
598
790
|
export { DenoTool, type TDenoPermission } from '@push.rocks/smartagent';
|
|
599
791
|
export { JsonValidatorTool } from '@push.rocks/smartagent';
|
|
792
|
+
export { ToolSearchTool } from '@push.rocks/smartagent';
|
|
793
|
+
export { ExpertTool } from '@push.rocks/smartagent';
|
|
600
794
|
|
|
601
795
|
// Types and interfaces
|
|
602
|
-
export * from '@push.rocks/smartagent'; // All interfaces
|
|
796
|
+
export * from '@push.rocks/smartagent'; // All interfaces (IExpertConfig, IToolMetadata, etc.)
|
|
603
797
|
|
|
604
798
|
// Re-exported from @push.rocks/smartai
|
|
605
799
|
export { type ISmartAiOptions, type TProvider, type ChatMessage, type ChatOptions, type ChatResponse };
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/index.ts
CHANGED
|
@@ -7,6 +7,9 @@ export { DualAgentOrchestrator } from './smartagent.classes.dualagent.js';
|
|
|
7
7
|
export { DriverAgent } from './smartagent.classes.driveragent.js';
|
|
8
8
|
export { GuardianAgent } from './smartagent.classes.guardianagent.js';
|
|
9
9
|
|
|
10
|
+
// Export tool registry and related classes
|
|
11
|
+
export { ToolRegistry } from './smartagent.classes.toolregistry.js';
|
|
12
|
+
|
|
10
13
|
// Export base tool class for custom tool creation
|
|
11
14
|
export { BaseToolWrapper } from './smartagent.tools.base.js';
|
|
12
15
|
|
|
@@ -18,6 +21,10 @@ export { BrowserTool } from './smartagent.tools.browser.js';
|
|
|
18
21
|
export { DenoTool, type TDenoPermission } from './smartagent.tools.deno.js';
|
|
19
22
|
export { JsonValidatorTool } from './smartagent.tools.json.js';
|
|
20
23
|
|
|
24
|
+
// Export tool search and expert tools
|
|
25
|
+
export { ToolSearchTool } from './smartagent.tools.search.js';
|
|
26
|
+
export { ExpertTool } from './smartagent.tools.expert.js';
|
|
27
|
+
|
|
21
28
|
// Export all interfaces
|
|
22
29
|
export * from './smartagent.interfaces.js';
|
|
23
30
|
|
|
@@ -8,6 +8,9 @@ import { HttpTool } from './smartagent.tools.http.js';
|
|
|
8
8
|
import { ShellTool } from './smartagent.tools.shell.js';
|
|
9
9
|
import { BrowserTool } from './smartagent.tools.browser.js';
|
|
10
10
|
import { DenoTool } from './smartagent.tools.deno.js';
|
|
11
|
+
import { ToolRegistry } from './smartagent.classes.toolregistry.js';
|
|
12
|
+
import { ToolSearchTool } from './smartagent.tools.search.js';
|
|
13
|
+
import { ExpertTool } from './smartagent.tools.expert.js';
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
16
|
* DualAgentOrchestrator - Coordinates Driver and Guardian agents
|
|
@@ -20,7 +23,7 @@ export class DualAgentOrchestrator {
|
|
|
20
23
|
private guardianProvider: plugins.smartai.MultiModalModel;
|
|
21
24
|
private driver: DriverAgent;
|
|
22
25
|
private guardian: GuardianAgent;
|
|
23
|
-
private
|
|
26
|
+
private registry: ToolRegistry = new ToolRegistry();
|
|
24
27
|
private isRunning = false;
|
|
25
28
|
private conversationHistory: interfaces.IAgentMessage[] = [];
|
|
26
29
|
private ownsSmartAi = true; // true if we created the SmartAi instance, false if it was provided
|
|
@@ -125,19 +128,55 @@ export class DualAgentOrchestrator {
|
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
/**
|
|
128
|
-
* Register a custom tool
|
|
131
|
+
* Register a custom tool with optional visibility settings
|
|
129
132
|
*/
|
|
130
|
-
public registerTool(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
public registerTool(
|
|
134
|
+
tool: BaseToolWrapper,
|
|
135
|
+
options?: interfaces.IToolRegistrationOptions
|
|
136
|
+
): void {
|
|
137
|
+
this.registry.register(tool, options);
|
|
138
|
+
|
|
139
|
+
// If initial visibility and agents exist, register with them
|
|
140
|
+
const visibility = options?.visibility ?? 'initial';
|
|
141
|
+
if (visibility === 'initial') {
|
|
142
|
+
if (this.driver) {
|
|
143
|
+
this.driver.registerTool(tool);
|
|
144
|
+
}
|
|
145
|
+
if (this.guardian) {
|
|
146
|
+
this.guardian.registerTool(tool);
|
|
147
|
+
}
|
|
138
148
|
}
|
|
139
149
|
}
|
|
140
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Register an expert (subagent) as a tool
|
|
153
|
+
*/
|
|
154
|
+
public registerExpert(config: interfaces.IExpertConfig): void {
|
|
155
|
+
const expert = new ExpertTool(config, this.smartai);
|
|
156
|
+
this.registerTool(expert, {
|
|
157
|
+
visibility: config.visibility,
|
|
158
|
+
tags: config.tags,
|
|
159
|
+
category: config.category ?? 'expert',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Enable tool search functionality
|
|
165
|
+
* This adds a 'tools' tool that allows the Driver to discover and activate on-demand tools
|
|
166
|
+
*/
|
|
167
|
+
public enableToolSearch(): void {
|
|
168
|
+
const searchTool = new ToolSearchTool(this.registry, (tool) => {
|
|
169
|
+
// Callback when an on-demand tool is activated
|
|
170
|
+
if (this.driver) {
|
|
171
|
+
this.driver.registerTool(tool);
|
|
172
|
+
}
|
|
173
|
+
if (this.guardian) {
|
|
174
|
+
this.guardian.registerTool(tool);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
this.registerTool(searchTool); // Always initial visibility
|
|
178
|
+
}
|
|
179
|
+
|
|
141
180
|
/**
|
|
142
181
|
* Register all standard tools
|
|
143
182
|
*/
|
|
@@ -193,19 +232,14 @@ export class DualAgentOrchestrator {
|
|
|
193
232
|
});
|
|
194
233
|
this.guardian = new GuardianAgent(this.guardianProvider, this.options.guardianPolicyPrompt);
|
|
195
234
|
|
|
196
|
-
// Register
|
|
197
|
-
for (const tool of this.
|
|
235
|
+
// Register visible tools with agents
|
|
236
|
+
for (const tool of this.registry.getVisibleTools()) {
|
|
198
237
|
this.driver.registerTool(tool);
|
|
199
238
|
this.guardian.registerTool(tool);
|
|
200
239
|
}
|
|
201
240
|
|
|
202
|
-
// Initialize
|
|
203
|
-
|
|
204
|
-
for (const tool of this.tools.values()) {
|
|
205
|
-
initPromises.push(tool.initialize());
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
await Promise.all(initPromises);
|
|
241
|
+
// Initialize visible tools
|
|
242
|
+
await this.registry.initializeVisibleTools();
|
|
209
243
|
this.isRunning = true;
|
|
210
244
|
}
|
|
211
245
|
|
|
@@ -213,13 +247,7 @@ export class DualAgentOrchestrator {
|
|
|
213
247
|
* Cleanup all tools
|
|
214
248
|
*/
|
|
215
249
|
public async stop(): Promise<void> {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
for (const tool of this.tools.values()) {
|
|
219
|
-
cleanupPromises.push(tool.cleanup());
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
await Promise.all(cleanupPromises);
|
|
250
|
+
await this.registry.cleanup();
|
|
223
251
|
|
|
224
252
|
// Only stop smartai if we created it (don't stop external instances)
|
|
225
253
|
if (this.ownsSmartAi) {
|
|
@@ -432,7 +460,7 @@ Please output the exact XML format above.`
|
|
|
432
460
|
});
|
|
433
461
|
|
|
434
462
|
// Execute the tool
|
|
435
|
-
const tool = this.
|
|
463
|
+
const tool = this.registry.getTool(proposal.toolName);
|
|
436
464
|
if (!tool) {
|
|
437
465
|
const errorMessage = `Tool "${proposal.toolName}" not found.`;
|
|
438
466
|
driverResponse = await this.driver.continueWithMessage(
|
|
@@ -652,6 +680,13 @@ Please output the exact XML format above.`
|
|
|
652
680
|
* Get registered tool names
|
|
653
681
|
*/
|
|
654
682
|
public getToolNames(): string[] {
|
|
655
|
-
return
|
|
683
|
+
return this.registry.getAllMetadata().map((m) => m.name);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Get the tool registry for advanced operations
|
|
688
|
+
*/
|
|
689
|
+
public getRegistry(): ToolRegistry {
|
|
690
|
+
return this.registry;
|
|
656
691
|
}
|
|
657
692
|
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as interfaces from './smartagent.interfaces.js';
|
|
2
|
+
import { BaseToolWrapper } from './smartagent.tools.base.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ToolRegistry - Manages tool registration, visibility, and lifecycle
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Track all registered tools with their metadata
|
|
9
|
+
* - Manage visibility (initial vs on-demand)
|
|
10
|
+
* - Handle activation of on-demand tools
|
|
11
|
+
* - Provide search functionality
|
|
12
|
+
*/
|
|
13
|
+
export class ToolRegistry {
|
|
14
|
+
private tools: Map<string, BaseToolWrapper> = new Map();
|
|
15
|
+
private metadata: Map<string, interfaces.IToolMetadata> = new Map();
|
|
16
|
+
private activated: Set<string> = new Set();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Register a tool with optional visibility settings
|
|
20
|
+
*/
|
|
21
|
+
register(tool: BaseToolWrapper, options: interfaces.IToolRegistrationOptions = {}): void {
|
|
22
|
+
const visibility = options.visibility ?? 'initial';
|
|
23
|
+
|
|
24
|
+
this.tools.set(tool.name, tool);
|
|
25
|
+
this.metadata.set(tool.name, {
|
|
26
|
+
name: tool.name,
|
|
27
|
+
description: tool.description,
|
|
28
|
+
actions: tool.actions,
|
|
29
|
+
visibility,
|
|
30
|
+
isActivated: visibility === 'initial',
|
|
31
|
+
isInitialized: false,
|
|
32
|
+
tags: options.tags,
|
|
33
|
+
category: options.category,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (visibility === 'initial') {
|
|
37
|
+
this.activated.add(tool.name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get tools visible to the Driver (initial + activated on-demand)
|
|
43
|
+
*/
|
|
44
|
+
getVisibleTools(): BaseToolWrapper[] {
|
|
45
|
+
return Array.from(this.tools.entries())
|
|
46
|
+
.filter(([name]) => this.activated.has(name))
|
|
47
|
+
.map(([, tool]) => tool);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get all tools (for search results)
|
|
52
|
+
*/
|
|
53
|
+
getAllTools(): BaseToolWrapper[] {
|
|
54
|
+
return Array.from(this.tools.values());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get a specific tool by name
|
|
59
|
+
*/
|
|
60
|
+
getTool(name: string): BaseToolWrapper | undefined {
|
|
61
|
+
return this.tools.get(name);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get metadata for a tool
|
|
66
|
+
*/
|
|
67
|
+
getMetadata(name: string): interfaces.IToolMetadata | undefined {
|
|
68
|
+
return this.metadata.get(name);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get all metadata
|
|
73
|
+
*/
|
|
74
|
+
getAllMetadata(): interfaces.IToolMetadata[] {
|
|
75
|
+
return Array.from(this.metadata.values());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Search tools by query (matches name, description, tags, action names)
|
|
80
|
+
*/
|
|
81
|
+
search(query: string): interfaces.IToolMetadata[] {
|
|
82
|
+
const q = query.toLowerCase();
|
|
83
|
+
return this.getAllMetadata().filter((meta) => {
|
|
84
|
+
if (meta.name.toLowerCase().includes(q)) return true;
|
|
85
|
+
if (meta.description.toLowerCase().includes(q)) return true;
|
|
86
|
+
if (meta.tags?.some((t) => t.toLowerCase().includes(q))) return true;
|
|
87
|
+
if (meta.category?.toLowerCase().includes(q)) return true;
|
|
88
|
+
if (
|
|
89
|
+
meta.actions.some(
|
|
90
|
+
(a) => a.name.toLowerCase().includes(q) || a.description.toLowerCase().includes(q)
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
return true;
|
|
94
|
+
return false;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Activate an on-demand tool
|
|
100
|
+
*/
|
|
101
|
+
async activate(name: string): Promise<{ success: boolean; error?: string }> {
|
|
102
|
+
const tool = this.tools.get(name);
|
|
103
|
+
const meta = this.metadata.get(name);
|
|
104
|
+
|
|
105
|
+
if (!tool || !meta) {
|
|
106
|
+
return { success: false, error: `Tool "${name}" not found` };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this.activated.has(name)) {
|
|
110
|
+
return { success: true }; // Already activated
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Initialize if not already initialized
|
|
114
|
+
if (!meta.isInitialized) {
|
|
115
|
+
await tool.initialize();
|
|
116
|
+
meta.isInitialized = true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this.activated.add(name);
|
|
120
|
+
meta.isActivated = true;
|
|
121
|
+
|
|
122
|
+
return { success: true };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Check if a tool is activated
|
|
127
|
+
*/
|
|
128
|
+
isActivated(name: string): boolean {
|
|
129
|
+
return this.activated.has(name);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Initialize all initial (visible) tools
|
|
134
|
+
*/
|
|
135
|
+
async initializeVisibleTools(): Promise<void> {
|
|
136
|
+
const promises: Promise<void>[] = [];
|
|
137
|
+
|
|
138
|
+
for (const [name, tool] of this.tools) {
|
|
139
|
+
const meta = this.metadata.get(name);
|
|
140
|
+
if (meta && this.activated.has(name) && !meta.isInitialized) {
|
|
141
|
+
promises.push(
|
|
142
|
+
tool.initialize().then(() => {
|
|
143
|
+
meta.isInitialized = true;
|
|
144
|
+
})
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
await Promise.all(promises);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Cleanup all initialized tools
|
|
154
|
+
*/
|
|
155
|
+
async cleanup(): Promise<void> {
|
|
156
|
+
const promises: Promise<void>[] = [];
|
|
157
|
+
|
|
158
|
+
for (const [name, tool] of this.tools) {
|
|
159
|
+
const meta = this.metadata.get(name);
|
|
160
|
+
if (meta?.isInitialized) {
|
|
161
|
+
promises.push(tool.cleanup());
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
await Promise.all(promises);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Check if a tool exists in the registry
|
|
170
|
+
*/
|
|
171
|
+
has(name: string): boolean {
|
|
172
|
+
return this.tools.has(name);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get the number of registered tools
|
|
177
|
+
*/
|
|
178
|
+
get size(): number {
|
|
179
|
+
return this.tools.size;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get the number of activated tools
|
|
184
|
+
*/
|
|
185
|
+
get activatedCount(): number {
|
|
186
|
+
return this.activated.size;
|
|
187
|
+
}
|
|
188
|
+
}
|