@push.rocks/smartagent 1.7.0 → 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/readme.md CHANGED
@@ -37,19 +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["Standard Tools"]
48
- FS["Filesystem"]
49
- HTTP["HTTP"]
50
- Shell["Shell"]
51
- Browser["Browser"]
52
- Deno["Deno"]
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>"]
53
53
  end
54
54
 
55
55
  Task --> Orchestrator
@@ -266,6 +266,157 @@ orchestrator.registerTool(new JsonValidatorTool());
266
266
  </tool_call>
267
267
  ```
268
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
+
269
420
  ## 🎥 Streaming Support
270
421
 
271
422
  SmartAgent supports token-by-token streaming for real-time output during LLM generation:
@@ -608,12 +759,15 @@ const orchestrator = new DualAgentOrchestrator({
608
759
  | `stop()` | Cleanup all tools and resources |
609
760
  | `run(task, options?)` | Execute a task with optional images for vision |
610
761
  | `continueTask(input)` | Continue a task with user input |
611
- | `registerTool(tool)` | Register a custom tool |
762
+ | `registerTool(tool, options?)` | Register a custom tool with optional visibility settings |
612
763
  | `registerStandardTools()` | Register all built-in tools (Filesystem, HTTP, Shell, Browser, Deno) |
613
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 |
614
767
  | `setGuardianPolicy(policy)` | Update Guardian policy at runtime |
615
768
  | `getHistory()` | Get conversation history |
616
769
  | `getToolNames()` | Get list of registered tool names |
770
+ | `getRegistry()` | Get the ToolRegistry for advanced operations |
617
771
  | `isActive()` | Check if orchestrator is running |
618
772
 
619
773
  ### Exports
@@ -624,6 +778,9 @@ export { DualAgentOrchestrator } from '@push.rocks/smartagent';
624
778
  export { DriverAgent } from '@push.rocks/smartagent';
625
779
  export { GuardianAgent } from '@push.rocks/smartagent';
626
780
 
781
+ // Tool Registry
782
+ export { ToolRegistry } from '@push.rocks/smartagent';
783
+
627
784
  // Tools
628
785
  export { BaseToolWrapper } from '@push.rocks/smartagent';
629
786
  export { FilesystemTool, type IFilesystemToolOptions } from '@push.rocks/smartagent';
@@ -632,9 +789,11 @@ export { ShellTool } from '@push.rocks/smartagent';
632
789
  export { BrowserTool } from '@push.rocks/smartagent';
633
790
  export { DenoTool, type TDenoPermission } from '@push.rocks/smartagent';
634
791
  export { JsonValidatorTool } from '@push.rocks/smartagent';
792
+ export { ToolSearchTool } from '@push.rocks/smartagent';
793
+ export { ExpertTool } from '@push.rocks/smartagent';
635
794
 
636
795
  // Types and interfaces
637
- export * from '@push.rocks/smartagent'; // All interfaces
796
+ export * from '@push.rocks/smartagent'; // All interfaces (IExpertConfig, IToolMetadata, etc.)
638
797
 
639
798
  // Re-exported from @push.rocks/smartai
640
799
  export { type ISmartAiOptions, type TProvider, type ChatMessage, type ChatOptions, type ChatResponse };
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartagent',
6
- version: '1.7.0',
6
+ version: '1.8.0',
7
7
  description: 'an agentic framework built on top of @push.rocks/smartai'
8
8
  }
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 tools: Map<string, BaseToolWrapper> = new Map();
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(tool: BaseToolWrapper): void {
131
- this.tools.set(tool.name, tool);
132
- // Register with agents if they exist (they're created in start())
133
- if (this.driver) {
134
- this.driver.registerTool(tool);
135
- }
136
- if (this.guardian) {
137
- this.guardian.registerTool(tool);
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 any tools that were added before start() with the agents
197
- for (const tool of this.tools.values()) {
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 all tools
203
- const initPromises: Promise<void>[] = [];
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
- const cleanupPromises: Promise<void>[] = [];
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.tools.get(proposal.toolName);
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 Array.from(this.tools.keys());
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
+ }
@@ -1,5 +1,65 @@
1
1
  import * as plugins from './plugins.js';
2
2
 
3
+ // ================================
4
+ // Tool Visibility & Registry Types
5
+ // ================================
6
+
7
+ /**
8
+ * Tool visibility mode
9
+ * - 'initial': Conveyed to model in system prompt AND discoverable via search
10
+ * - 'on-demand': Only discoverable via search, must be activated before use
11
+ */
12
+ export type TToolVisibility = 'initial' | 'on-demand';
13
+
14
+ /**
15
+ * Tool metadata for discovery and management
16
+ */
17
+ export interface IToolMetadata {
18
+ name: string;
19
+ description: string;
20
+ actions: IToolAction[];
21
+ visibility: TToolVisibility;
22
+ isActivated: boolean;
23
+ isInitialized: boolean;
24
+ tags?: string[];
25
+ category?: string;
26
+ }
27
+
28
+ /**
29
+ * Options when registering a tool
30
+ */
31
+ export interface IToolRegistrationOptions {
32
+ visibility?: TToolVisibility;
33
+ tags?: string[];
34
+ category?: string;
35
+ }
36
+
37
+ /**
38
+ * Configuration for creating an Expert (SubAgent)
39
+ */
40
+ export interface IExpertConfig {
41
+ /** Unique name for the expert */
42
+ name: string;
43
+ /** Description of the expert's capabilities */
44
+ description: string;
45
+ /** System message defining expert behavior */
46
+ systemMessage: string;
47
+ /** Guardian policy for the expert's inner agent */
48
+ guardianPolicy: string;
49
+ /** AI provider (defaults to parent's provider) */
50
+ provider?: plugins.smartai.TProvider;
51
+ /** Tools available to this expert */
52
+ tools?: IAgentToolWrapper[];
53
+ /** Max iterations for expert tasks (default: 10) */
54
+ maxIterations?: number;
55
+ /** Visibility mode (default: 'initial') */
56
+ visibility?: TToolVisibility;
57
+ /** Searchable tags */
58
+ tags?: string[];
59
+ /** Category for grouping */
60
+ category?: string;
61
+ }
62
+
3
63
  // ================================
4
64
  // Task Run Options
5
65
  // ================================