elsabro 2.3.0 → 3.7.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 +668 -20
- package/bin/install.js +0 -0
- package/flows/development-flow.json +452 -0
- package/flows/quick-flow.json +118 -0
- package/package.json +3 -2
- package/references/SYSTEM_INDEX.md +379 -5
- package/references/agent-marketplace.md +2274 -0
- package/references/agent-protocol.md +1126 -0
- package/references/ai-code-suggestions.md +2413 -0
- package/references/checkpointing.md +595 -0
- package/references/collaboration-patterns.md +851 -0
- package/references/collaborative-sessions.md +1081 -0
- package/references/configuration-management.md +1810 -0
- package/references/cost-tracking.md +1095 -0
- package/references/enterprise-sso.md +2001 -0
- package/references/error-contracts-v2.md +968 -0
- package/references/event-driven.md +1031 -0
- package/references/flow-orchestration.md +940 -0
- package/references/flow-visualization.md +1557 -0
- package/references/ide-integrations.md +3513 -0
- package/references/interrupt-system.md +681 -0
- package/references/kubernetes-deployment.md +3099 -0
- package/references/memory-system.md +683 -0
- package/references/mobile-companion.md +3236 -0
- package/references/multi-llm-providers.md +2494 -0
- package/references/multi-project-memory.md +1182 -0
- package/references/observability.md +793 -0
- package/references/output-schemas.md +858 -0
- package/references/performance-profiler.md +955 -0
- package/references/plugin-system.md +1526 -0
- package/references/prompt-management.md +292 -0
- package/references/sandbox-execution.md +303 -0
- package/references/security-system.md +1253 -0
- package/references/streaming.md +696 -0
- package/references/testing-framework.md +1151 -0
- package/references/time-travel.md +802 -0
- package/references/tool-registry.md +886 -0
- package/references/voice-commands.md +3296 -0
- package/templates/agent-marketplace-config.json +220 -0
- package/templates/agent-protocol-config.json +136 -0
- package/templates/ai-suggestions-config.json +100 -0
- package/templates/checkpoint-state.json +61 -0
- package/templates/collaboration-config.json +157 -0
- package/templates/collaborative-sessions-config.json +153 -0
- package/templates/configuration-config.json +245 -0
- package/templates/cost-tracking-config.json +148 -0
- package/templates/enterprise-sso-config.json +438 -0
- package/templates/events-config.json +148 -0
- package/templates/flow-visualization-config.json +196 -0
- package/templates/ide-integrations-config.json +442 -0
- package/templates/kubernetes-config.json +764 -0
- package/templates/memory-state.json +84 -0
- package/templates/mobile-companion-config.json +600 -0
- package/templates/multi-llm-config.json +544 -0
- package/templates/multi-project-memory-config.json +145 -0
- package/templates/observability-config.json +109 -0
- package/templates/performance-profiler-config.json +125 -0
- package/templates/plugin-config.json +170 -0
- package/templates/prompt-management-config.json +86 -0
- package/templates/sandbox-config.json +185 -0
- package/templates/schemas-config.json +65 -0
- package/templates/security-config.json +120 -0
- package/templates/streaming-config.json +72 -0
- package/templates/testing-config.json +81 -0
- package/templates/timetravel-config.json +62 -0
- package/templates/tool-registry-config.json +109 -0
- package/templates/voice-commands-config.json +658 -0
|
@@ -0,0 +1,886 @@
|
|
|
1
|
+
# Tool Registry System (v3.3)
|
|
2
|
+
|
|
3
|
+
Sistema de registro dinámico de herramientas con discovery, versionado, y capability matching.
|
|
4
|
+
|
|
5
|
+
## Arquitectura
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────────────────────────────────┐
|
|
9
|
+
│ TOOL REGISTRY SYSTEM │
|
|
10
|
+
├─────────────────────────────────────────────────────────────────────────┤
|
|
11
|
+
│ │
|
|
12
|
+
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
13
|
+
│ │ TOOL REGISTRY │ │
|
|
14
|
+
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
|
|
15
|
+
│ │ │ Registered Tools │ │ │
|
|
16
|
+
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │
|
|
17
|
+
│ │ │ │ Bash │ │ Read │ │ Write │ │ MCP │ │ │ │
|
|
18
|
+
│ │ │ │ v1.2.0 │ │ v1.0.0 │ │ v1.0.0 │ │ v2.0.0 │ │ │ │
|
|
19
|
+
│ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │
|
|
20
|
+
│ │ └─────────────────────────────────────────────────────────┘ │ │
|
|
21
|
+
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
22
|
+
│ │ │
|
|
23
|
+
│ ▼ │
|
|
24
|
+
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
25
|
+
│ │ TOOL DISCOVERY │ │
|
|
26
|
+
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
27
|
+
│ │ │ By Name │ │ By Category │ │By Capability│ │ │
|
|
28
|
+
│ │ │ "Bash" │ │ "file-ops" │ │ "can:write" │ │ │
|
|
29
|
+
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
30
|
+
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
31
|
+
│ │ │
|
|
32
|
+
│ ▼ │
|
|
33
|
+
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
34
|
+
│ │ CAPABILITY MATCHER │ │
|
|
35
|
+
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
|
|
36
|
+
│ │ │ Agent Request → Matching Tools │ │ │
|
|
37
|
+
│ │ │ "Need to read files" → [Read, Glob, Grep, WebFetch] │ │ │
|
|
38
|
+
│ │ └───────────────────────────────────────────────────────────┘ │ │
|
|
39
|
+
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
40
|
+
│ │ │
|
|
41
|
+
│ ▼ │
|
|
42
|
+
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
43
|
+
│ │ VERSION MANAGER │ │
|
|
44
|
+
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
45
|
+
│ │ │ Versioning │ │ Deprecation │ │ Migration │ │ │
|
|
46
|
+
│ │ │ semver │ │ warnings │ │ paths │ │ │
|
|
47
|
+
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
48
|
+
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
49
|
+
│ │
|
|
50
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## ToolRegistry
|
|
56
|
+
|
|
57
|
+
### API Principal
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
interface ToolDefinition {
|
|
61
|
+
name: string;
|
|
62
|
+
version: string;
|
|
63
|
+
description: string;
|
|
64
|
+
category: string;
|
|
65
|
+
capabilities: string[];
|
|
66
|
+
parameters: ToolParameter[];
|
|
67
|
+
returns: ToolReturn;
|
|
68
|
+
examples?: ToolExample[];
|
|
69
|
+
metadata?: Record<string, unknown>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface ToolParameter {
|
|
73
|
+
name: string;
|
|
74
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
75
|
+
description: string;
|
|
76
|
+
required: boolean;
|
|
77
|
+
default?: unknown;
|
|
78
|
+
enum?: unknown[];
|
|
79
|
+
schema?: JSONSchema;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface ToolReturn {
|
|
83
|
+
type: string;
|
|
84
|
+
description: string;
|
|
85
|
+
schema?: JSONSchema;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface ToolExample {
|
|
89
|
+
description: string;
|
|
90
|
+
input: Record<string, unknown>;
|
|
91
|
+
output: unknown;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface RegisteredTool extends ToolDefinition {
|
|
95
|
+
id: string;
|
|
96
|
+
registered_at: string;
|
|
97
|
+
updated_at: string;
|
|
98
|
+
status: 'active' | 'deprecated' | 'disabled';
|
|
99
|
+
deprecation?: {
|
|
100
|
+
message: string;
|
|
101
|
+
replacement?: string;
|
|
102
|
+
remove_at?: string;
|
|
103
|
+
};
|
|
104
|
+
usage: {
|
|
105
|
+
total_calls: number;
|
|
106
|
+
success_rate: number;
|
|
107
|
+
avg_duration_ms: number;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
class ToolRegistry {
|
|
112
|
+
private tools: Map<string, RegisteredTool>;
|
|
113
|
+
private categories: Map<string, Set<string>>;
|
|
114
|
+
private capabilities: Map<string, Set<string>>;
|
|
115
|
+
private config: ToolRegistryConfig;
|
|
116
|
+
|
|
117
|
+
constructor(config: ToolRegistryConfig) {
|
|
118
|
+
this.config = config;
|
|
119
|
+
this.tools = new Map();
|
|
120
|
+
this.categories = new Map();
|
|
121
|
+
this.capabilities = new Map();
|
|
122
|
+
this.loadBuiltinTools();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Register new tool
|
|
126
|
+
register(definition: ToolDefinition): RegisteredTool {
|
|
127
|
+
const existing = this.tools.get(definition.name);
|
|
128
|
+
|
|
129
|
+
// Version conflict check
|
|
130
|
+
if (existing && !this.isNewerVersion(definition.version, existing.version)) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Tool ${definition.name} v${existing.version} already registered. ` +
|
|
133
|
+
`Provided v${definition.version} is not newer.`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const tool: RegisteredTool = {
|
|
138
|
+
...definition,
|
|
139
|
+
id: this.generateId(),
|
|
140
|
+
registered_at: new Date().toISOString(),
|
|
141
|
+
updated_at: new Date().toISOString(),
|
|
142
|
+
status: 'active',
|
|
143
|
+
usage: {
|
|
144
|
+
total_calls: existing?.usage.total_calls || 0,
|
|
145
|
+
success_rate: existing?.usage.success_rate || 100,
|
|
146
|
+
avg_duration_ms: existing?.usage.avg_duration_ms || 0
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Register tool
|
|
151
|
+
this.tools.set(definition.name, tool);
|
|
152
|
+
|
|
153
|
+
// Index by category
|
|
154
|
+
if (!this.categories.has(definition.category)) {
|
|
155
|
+
this.categories.set(definition.category, new Set());
|
|
156
|
+
}
|
|
157
|
+
this.categories.get(definition.category)!.add(definition.name);
|
|
158
|
+
|
|
159
|
+
// Index by capabilities
|
|
160
|
+
for (const capability of definition.capabilities) {
|
|
161
|
+
if (!this.capabilities.has(capability)) {
|
|
162
|
+
this.capabilities.set(capability, new Set());
|
|
163
|
+
}
|
|
164
|
+
this.capabilities.get(capability)!.add(definition.name);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Emit event
|
|
168
|
+
EventBus.publish('tool.registered', {
|
|
169
|
+
name: definition.name,
|
|
170
|
+
version: definition.version,
|
|
171
|
+
category: definition.category
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return tool;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Get tool by name
|
|
178
|
+
get(name: string): RegisteredTool | undefined {
|
|
179
|
+
return this.tools.get(name);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Get tool with version check
|
|
183
|
+
getVersion(name: string, version?: string): RegisteredTool | undefined {
|
|
184
|
+
const tool = this.tools.get(name);
|
|
185
|
+
if (!tool) return undefined;
|
|
186
|
+
|
|
187
|
+
if (version && !this.satisfiesVersion(tool.version, version)) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return tool;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// List all tools
|
|
195
|
+
list(options?: ListOptions): RegisteredTool[] {
|
|
196
|
+
let tools = Array.from(this.tools.values());
|
|
197
|
+
|
|
198
|
+
if (options?.category) {
|
|
199
|
+
tools = tools.filter(t => t.category === options.category);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (options?.status) {
|
|
203
|
+
tools = tools.filter(t => t.status === options.status);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (options?.capability) {
|
|
207
|
+
const toolNames = this.capabilities.get(options.capability);
|
|
208
|
+
if (toolNames) {
|
|
209
|
+
tools = tools.filter(t => toolNames.has(t.name));
|
|
210
|
+
} else {
|
|
211
|
+
tools = [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return tools;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Search tools
|
|
219
|
+
search(query: string): RegisteredTool[] {
|
|
220
|
+
const lowerQuery = query.toLowerCase();
|
|
221
|
+
|
|
222
|
+
return Array.from(this.tools.values()).filter(tool =>
|
|
223
|
+
tool.name.toLowerCase().includes(lowerQuery) ||
|
|
224
|
+
tool.description.toLowerCase().includes(lowerQuery) ||
|
|
225
|
+
tool.capabilities.some(c => c.toLowerCase().includes(lowerQuery))
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Deprecate tool
|
|
230
|
+
deprecate(name: string, message: string, replacement?: string): void {
|
|
231
|
+
const tool = this.tools.get(name);
|
|
232
|
+
if (!tool) throw new Error(`Tool not found: ${name}`);
|
|
233
|
+
|
|
234
|
+
tool.status = 'deprecated';
|
|
235
|
+
tool.deprecation = {
|
|
236
|
+
message,
|
|
237
|
+
replacement,
|
|
238
|
+
remove_at: this.calculateRemovalDate()
|
|
239
|
+
};
|
|
240
|
+
tool.updated_at = new Date().toISOString();
|
|
241
|
+
|
|
242
|
+
EventBus.publish('tool.deprecated', {
|
|
243
|
+
name,
|
|
244
|
+
message,
|
|
245
|
+
replacement
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Disable tool
|
|
250
|
+
disable(name: string): void {
|
|
251
|
+
const tool = this.tools.get(name);
|
|
252
|
+
if (!tool) throw new Error(`Tool not found: ${name}`);
|
|
253
|
+
|
|
254
|
+
tool.status = 'disabled';
|
|
255
|
+
tool.updated_at = new Date().toISOString();
|
|
256
|
+
|
|
257
|
+
EventBus.publish('tool.disabled', { name });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Enable tool
|
|
261
|
+
enable(name: string): void {
|
|
262
|
+
const tool = this.tools.get(name);
|
|
263
|
+
if (!tool) throw new Error(`Tool not found: ${name}`);
|
|
264
|
+
|
|
265
|
+
tool.status = 'active';
|
|
266
|
+
tool.deprecation = undefined;
|
|
267
|
+
tool.updated_at = new Date().toISOString();
|
|
268
|
+
|
|
269
|
+
EventBus.publish('tool.enabled', { name });
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Unregister tool
|
|
273
|
+
unregister(name: string): boolean {
|
|
274
|
+
const tool = this.tools.get(name);
|
|
275
|
+
if (!tool) return false;
|
|
276
|
+
|
|
277
|
+
// Remove from indices
|
|
278
|
+
this.categories.get(tool.category)?.delete(name);
|
|
279
|
+
for (const capability of tool.capabilities) {
|
|
280
|
+
this.capabilities.get(capability)?.delete(name);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
this.tools.delete(name);
|
|
284
|
+
|
|
285
|
+
EventBus.publish('tool.unregistered', { name });
|
|
286
|
+
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Record tool usage
|
|
291
|
+
recordUsage(name: string, success: boolean, duration_ms: number): void {
|
|
292
|
+
const tool = this.tools.get(name);
|
|
293
|
+
if (!tool) return;
|
|
294
|
+
|
|
295
|
+
tool.usage.total_calls++;
|
|
296
|
+
|
|
297
|
+
// Update success rate (rolling average)
|
|
298
|
+
const successValue = success ? 100 : 0;
|
|
299
|
+
tool.usage.success_rate =
|
|
300
|
+
(tool.usage.success_rate * (tool.usage.total_calls - 1) + successValue) /
|
|
301
|
+
tool.usage.total_calls;
|
|
302
|
+
|
|
303
|
+
// Update average duration (rolling average)
|
|
304
|
+
tool.usage.avg_duration_ms =
|
|
305
|
+
(tool.usage.avg_duration_ms * (tool.usage.total_calls - 1) + duration_ms) /
|
|
306
|
+
tool.usage.total_calls;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Get categories
|
|
310
|
+
getCategories(): string[] {
|
|
311
|
+
return Array.from(this.categories.keys());
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Get capabilities
|
|
315
|
+
getCapabilities(): string[] {
|
|
316
|
+
return Array.from(this.capabilities.keys());
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Export registry
|
|
320
|
+
export(): ToolRegistryExport {
|
|
321
|
+
return {
|
|
322
|
+
version: '1.0.0',
|
|
323
|
+
exported_at: new Date().toISOString(),
|
|
324
|
+
tools: Array.from(this.tools.values())
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Import registry
|
|
329
|
+
import(data: ToolRegistryExport): number {
|
|
330
|
+
let imported = 0;
|
|
331
|
+
for (const tool of data.tools) {
|
|
332
|
+
try {
|
|
333
|
+
this.register(tool);
|
|
334
|
+
imported++;
|
|
335
|
+
} catch {
|
|
336
|
+
// Skip conflicts
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return imported;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private loadBuiltinTools(): void {
|
|
343
|
+
// Register Claude Code built-in tools
|
|
344
|
+
const builtins: ToolDefinition[] = [
|
|
345
|
+
{
|
|
346
|
+
name: 'Bash',
|
|
347
|
+
version: '1.0.0',
|
|
348
|
+
description: 'Execute bash commands',
|
|
349
|
+
category: 'system',
|
|
350
|
+
capabilities: ['execute', 'shell', 'git', 'npm'],
|
|
351
|
+
parameters: [
|
|
352
|
+
{ name: 'command', type: 'string', description: 'Command to execute', required: true },
|
|
353
|
+
{ name: 'timeout', type: 'number', description: 'Timeout in ms', required: false }
|
|
354
|
+
],
|
|
355
|
+
returns: { type: 'string', description: 'Command output' }
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: 'Read',
|
|
359
|
+
version: '1.0.0',
|
|
360
|
+
description: 'Read file contents',
|
|
361
|
+
category: 'file-ops',
|
|
362
|
+
capabilities: ['read', 'file', 'content'],
|
|
363
|
+
parameters: [
|
|
364
|
+
{ name: 'file_path', type: 'string', description: 'Path to file', required: true },
|
|
365
|
+
{ name: 'offset', type: 'number', description: 'Start line', required: false },
|
|
366
|
+
{ name: 'limit', type: 'number', description: 'Max lines', required: false }
|
|
367
|
+
],
|
|
368
|
+
returns: { type: 'string', description: 'File content' }
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: 'Write',
|
|
372
|
+
version: '1.0.0',
|
|
373
|
+
description: 'Write file contents',
|
|
374
|
+
category: 'file-ops',
|
|
375
|
+
capabilities: ['write', 'file', 'create'],
|
|
376
|
+
parameters: [
|
|
377
|
+
{ name: 'file_path', type: 'string', description: 'Path to file', required: true },
|
|
378
|
+
{ name: 'content', type: 'string', description: 'Content to write', required: true }
|
|
379
|
+
],
|
|
380
|
+
returns: { type: 'boolean', description: 'Success status' }
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
name: 'Edit',
|
|
384
|
+
version: '1.0.0',
|
|
385
|
+
description: 'Edit file with replacements',
|
|
386
|
+
category: 'file-ops',
|
|
387
|
+
capabilities: ['edit', 'file', 'modify'],
|
|
388
|
+
parameters: [
|
|
389
|
+
{ name: 'file_path', type: 'string', description: 'Path to file', required: true },
|
|
390
|
+
{ name: 'old_string', type: 'string', description: 'Text to replace', required: true },
|
|
391
|
+
{ name: 'new_string', type: 'string', description: 'Replacement text', required: true }
|
|
392
|
+
],
|
|
393
|
+
returns: { type: 'boolean', description: 'Success status' }
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: 'Glob',
|
|
397
|
+
version: '1.0.0',
|
|
398
|
+
description: 'Find files by pattern',
|
|
399
|
+
category: 'search',
|
|
400
|
+
capabilities: ['search', 'find', 'pattern'],
|
|
401
|
+
parameters: [
|
|
402
|
+
{ name: 'pattern', type: 'string', description: 'Glob pattern', required: true },
|
|
403
|
+
{ name: 'path', type: 'string', description: 'Base path', required: false }
|
|
404
|
+
],
|
|
405
|
+
returns: { type: 'array', description: 'Matching file paths' }
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
name: 'Grep',
|
|
409
|
+
version: '1.0.0',
|
|
410
|
+
description: 'Search file contents',
|
|
411
|
+
category: 'search',
|
|
412
|
+
capabilities: ['search', 'content', 'regex'],
|
|
413
|
+
parameters: [
|
|
414
|
+
{ name: 'pattern', type: 'string', description: 'Search pattern', required: true },
|
|
415
|
+
{ name: 'path', type: 'string', description: 'Search path', required: false }
|
|
416
|
+
],
|
|
417
|
+
returns: { type: 'array', description: 'Matching lines' }
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: 'Task',
|
|
421
|
+
version: '1.0.0',
|
|
422
|
+
description: 'Launch subagent for complex tasks',
|
|
423
|
+
category: 'agent',
|
|
424
|
+
capabilities: ['delegate', 'parallel', 'subagent'],
|
|
425
|
+
parameters: [
|
|
426
|
+
{ name: 'prompt', type: 'string', description: 'Task description', required: true },
|
|
427
|
+
{ name: 'subagent_type', type: 'string', description: 'Agent type', required: true }
|
|
428
|
+
],
|
|
429
|
+
returns: { type: 'object', description: 'Agent result' }
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
name: 'WebFetch',
|
|
433
|
+
version: '1.0.0',
|
|
434
|
+
description: 'Fetch and process web content',
|
|
435
|
+
category: 'web',
|
|
436
|
+
capabilities: ['fetch', 'http', 'web'],
|
|
437
|
+
parameters: [
|
|
438
|
+
{ name: 'url', type: 'string', description: 'URL to fetch', required: true },
|
|
439
|
+
{ name: 'prompt', type: 'string', description: 'Processing prompt', required: true }
|
|
440
|
+
],
|
|
441
|
+
returns: { type: 'string', description: 'Processed content' }
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: 'WebSearch',
|
|
445
|
+
version: '1.0.0',
|
|
446
|
+
description: 'Search the web',
|
|
447
|
+
category: 'web',
|
|
448
|
+
capabilities: ['search', 'web', 'query'],
|
|
449
|
+
parameters: [
|
|
450
|
+
{ name: 'query', type: 'string', description: 'Search query', required: true }
|
|
451
|
+
],
|
|
452
|
+
returns: { type: 'array', description: 'Search results' }
|
|
453
|
+
}
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
for (const tool of builtins) {
|
|
457
|
+
this.register(tool);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private isNewerVersion(newVersion: string, oldVersion: string): boolean {
|
|
462
|
+
const parse = (v: string) => v.split('.').map(Number);
|
|
463
|
+
const [newMajor, newMinor, newPatch] = parse(newVersion);
|
|
464
|
+
const [oldMajor, oldMinor, oldPatch] = parse(oldVersion);
|
|
465
|
+
|
|
466
|
+
if (newMajor > oldMajor) return true;
|
|
467
|
+
if (newMajor < oldMajor) return false;
|
|
468
|
+
if (newMinor > oldMinor) return true;
|
|
469
|
+
if (newMinor < oldMinor) return false;
|
|
470
|
+
return newPatch > oldPatch;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
private satisfiesVersion(actual: string, required: string): boolean {
|
|
474
|
+
// Simple semver satisfaction check
|
|
475
|
+
if (required.startsWith('^')) {
|
|
476
|
+
const base = required.slice(1);
|
|
477
|
+
const [reqMajor] = base.split('.').map(Number);
|
|
478
|
+
const [actMajor] = actual.split('.').map(Number);
|
|
479
|
+
return actMajor === reqMajor && this.isNewerVersion(actual, base);
|
|
480
|
+
}
|
|
481
|
+
if (required.startsWith('~')) {
|
|
482
|
+
const base = required.slice(1);
|
|
483
|
+
const [reqMajor, reqMinor] = base.split('.').map(Number);
|
|
484
|
+
const [actMajor, actMinor] = actual.split('.').map(Number);
|
|
485
|
+
return actMajor === reqMajor && actMinor === reqMinor;
|
|
486
|
+
}
|
|
487
|
+
return actual === required;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private calculateRemovalDate(): string {
|
|
491
|
+
const date = new Date();
|
|
492
|
+
date.setMonth(date.getMonth() + 3);
|
|
493
|
+
return date.toISOString();
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
private generateId(): string {
|
|
497
|
+
return `tool_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## ToolDiscovery
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
interface DiscoveryQuery {
|
|
508
|
+
text?: string;
|
|
509
|
+
capabilities?: string[];
|
|
510
|
+
category?: string;
|
|
511
|
+
minVersion?: string;
|
|
512
|
+
includeDeprecated?: boolean;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
interface DiscoveryResult {
|
|
516
|
+
tool: RegisteredTool;
|
|
517
|
+
score: number;
|
|
518
|
+
matchedCapabilities: string[];
|
|
519
|
+
matchReason: string;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
class ToolDiscovery {
|
|
523
|
+
private registry: ToolRegistry;
|
|
524
|
+
private cache: Map<string, DiscoveryResult[]>;
|
|
525
|
+
|
|
526
|
+
constructor(registry: ToolRegistry) {
|
|
527
|
+
this.registry = registry;
|
|
528
|
+
this.cache = new Map();
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Discover tools matching query
|
|
532
|
+
discover(query: DiscoveryQuery): DiscoveryResult[] {
|
|
533
|
+
const cacheKey = JSON.stringify(query);
|
|
534
|
+
if (this.cache.has(cacheKey)) {
|
|
535
|
+
return this.cache.get(cacheKey)!;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
let candidates = this.registry.list({
|
|
539
|
+
status: query.includeDeprecated ? undefined : 'active'
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
const results: DiscoveryResult[] = [];
|
|
543
|
+
|
|
544
|
+
for (const tool of candidates) {
|
|
545
|
+
const score = this.calculateScore(tool, query);
|
|
546
|
+
if (score > 0) {
|
|
547
|
+
results.push({
|
|
548
|
+
tool,
|
|
549
|
+
score,
|
|
550
|
+
matchedCapabilities: this.getMatchedCapabilities(tool, query),
|
|
551
|
+
matchReason: this.getMatchReason(tool, query, score)
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Sort by score descending
|
|
557
|
+
results.sort((a, b) => b.score - a.score);
|
|
558
|
+
|
|
559
|
+
// Cache results
|
|
560
|
+
this.cache.set(cacheKey, results);
|
|
561
|
+
|
|
562
|
+
return results;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Find best tool for capability
|
|
566
|
+
findBest(capability: string): RegisteredTool | undefined {
|
|
567
|
+
const results = this.discover({ capabilities: [capability] });
|
|
568
|
+
return results[0]?.tool;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Find all tools for category
|
|
572
|
+
findByCategory(category: string): RegisteredTool[] {
|
|
573
|
+
return this.registry.list({ category });
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Suggest tools for task description
|
|
577
|
+
suggest(taskDescription: string): DiscoveryResult[] {
|
|
578
|
+
// Extract likely capabilities from description
|
|
579
|
+
const capabilities = this.extractCapabilities(taskDescription);
|
|
580
|
+
|
|
581
|
+
return this.discover({
|
|
582
|
+
text: taskDescription,
|
|
583
|
+
capabilities
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Clear discovery cache
|
|
588
|
+
clearCache(): void {
|
|
589
|
+
this.cache.clear();
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
private calculateScore(tool: RegisteredTool, query: DiscoveryQuery): number {
|
|
593
|
+
let score = 0;
|
|
594
|
+
|
|
595
|
+
// Text match
|
|
596
|
+
if (query.text) {
|
|
597
|
+
const text = query.text.toLowerCase();
|
|
598
|
+
if (tool.name.toLowerCase().includes(text)) score += 50;
|
|
599
|
+
if (tool.description.toLowerCase().includes(text)) score += 30;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Capability match
|
|
603
|
+
if (query.capabilities) {
|
|
604
|
+
for (const cap of query.capabilities) {
|
|
605
|
+
if (tool.capabilities.includes(cap)) score += 25;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Category match
|
|
610
|
+
if (query.category && tool.category === query.category) {
|
|
611
|
+
score += 20;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Version match
|
|
615
|
+
if (query.minVersion) {
|
|
616
|
+
if (this.satisfiesMinVersion(tool.version, query.minVersion)) {
|
|
617
|
+
score += 10;
|
|
618
|
+
} else {
|
|
619
|
+
score = 0; // Exclude if version doesn't satisfy
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Usage bonus (more used = more trusted)
|
|
624
|
+
if (tool.usage.total_calls > 100) score += 5;
|
|
625
|
+
if (tool.usage.success_rate > 95) score += 5;
|
|
626
|
+
|
|
627
|
+
// Penalty for deprecated
|
|
628
|
+
if (tool.status === 'deprecated') score -= 20;
|
|
629
|
+
|
|
630
|
+
return Math.max(0, score);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private getMatchedCapabilities(tool: RegisteredTool, query: DiscoveryQuery): string[] {
|
|
634
|
+
if (!query.capabilities) return [];
|
|
635
|
+
return query.capabilities.filter(c => tool.capabilities.includes(c));
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
private getMatchReason(tool: RegisteredTool, query: DiscoveryQuery, score: number): string {
|
|
639
|
+
const reasons: string[] = [];
|
|
640
|
+
|
|
641
|
+
if (query.text && tool.name.toLowerCase().includes(query.text.toLowerCase())) {
|
|
642
|
+
reasons.push('name match');
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (query.capabilities) {
|
|
646
|
+
const matched = this.getMatchedCapabilities(tool, query);
|
|
647
|
+
if (matched.length > 0) {
|
|
648
|
+
reasons.push(`capabilities: ${matched.join(', ')}`);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
if (query.category && tool.category === query.category) {
|
|
653
|
+
reasons.push('category match');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return reasons.join('; ') || 'general match';
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
private extractCapabilities(description: string): string[] {
|
|
660
|
+
const keywords: Record<string, string[]> = {
|
|
661
|
+
'read': ['read', 'file', 'content'],
|
|
662
|
+
'write': ['write', 'create', 'save'],
|
|
663
|
+
'edit': ['edit', 'modify', 'change', 'update'],
|
|
664
|
+
'search': ['search', 'find', 'look', 'grep'],
|
|
665
|
+
'execute': ['run', 'execute', 'command', 'bash', 'shell'],
|
|
666
|
+
'fetch': ['fetch', 'download', 'http', 'api', 'web'],
|
|
667
|
+
'delegate': ['agent', 'task', 'parallel', 'complex']
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
const lower = description.toLowerCase();
|
|
671
|
+
const capabilities: string[] = [];
|
|
672
|
+
|
|
673
|
+
for (const [capability, triggers] of Object.entries(keywords)) {
|
|
674
|
+
if (triggers.some(t => lower.includes(t))) {
|
|
675
|
+
capabilities.push(capability);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return capabilities;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
private satisfiesMinVersion(actual: string, min: string): boolean {
|
|
683
|
+
const parse = (v: string) => v.split('.').map(Number);
|
|
684
|
+
const [actMajor, actMinor, actPatch] = parse(actual);
|
|
685
|
+
const [minMajor, minMinor, minPatch] = parse(min);
|
|
686
|
+
|
|
687
|
+
if (actMajor > minMajor) return true;
|
|
688
|
+
if (actMajor < minMajor) return false;
|
|
689
|
+
if (actMinor > minMinor) return true;
|
|
690
|
+
if (actMinor < minMinor) return false;
|
|
691
|
+
return actPatch >= minPatch;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
## CapabilityMatcher
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
interface CapabilityRequirement {
|
|
702
|
+
capability: string;
|
|
703
|
+
required: boolean;
|
|
704
|
+
priority: number;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
interface MatchResult {
|
|
708
|
+
tool: RegisteredTool;
|
|
709
|
+
matchedCapabilities: string[];
|
|
710
|
+
missingCapabilities: string[];
|
|
711
|
+
matchPercentage: number;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
class CapabilityMatcher {
|
|
715
|
+
private registry: ToolRegistry;
|
|
716
|
+
|
|
717
|
+
constructor(registry: ToolRegistry) {
|
|
718
|
+
this.registry = registry;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Match tools to required capabilities
|
|
722
|
+
match(requirements: CapabilityRequirement[]): MatchResult[] {
|
|
723
|
+
const tools = this.registry.list({ status: 'active' });
|
|
724
|
+
const results: MatchResult[] = [];
|
|
725
|
+
|
|
726
|
+
for (const tool of tools) {
|
|
727
|
+
const matched: string[] = [];
|
|
728
|
+
const missing: string[] = [];
|
|
729
|
+
|
|
730
|
+
for (const req of requirements) {
|
|
731
|
+
if (tool.capabilities.includes(req.capability)) {
|
|
732
|
+
matched.push(req.capability);
|
|
733
|
+
} else if (req.required) {
|
|
734
|
+
missing.push(req.capability);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// Skip if missing required capabilities
|
|
739
|
+
if (missing.length > 0 && requirements.some(r => r.required && missing.includes(r.capability))) {
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const matchPercentage = (matched.length / requirements.length) * 100;
|
|
744
|
+
|
|
745
|
+
results.push({
|
|
746
|
+
tool,
|
|
747
|
+
matchedCapabilities: matched,
|
|
748
|
+
missingCapabilities: missing,
|
|
749
|
+
matchPercentage
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Sort by match percentage
|
|
754
|
+
return results.sort((a, b) => b.matchPercentage - a.matchPercentage);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// Find minimum set of tools covering all capabilities
|
|
758
|
+
findMinimalSet(capabilities: string[]): RegisteredTool[] {
|
|
759
|
+
const uncovered = new Set(capabilities);
|
|
760
|
+
const selected: RegisteredTool[] = [];
|
|
761
|
+
|
|
762
|
+
while (uncovered.size > 0) {
|
|
763
|
+
// Find tool that covers most uncovered capabilities
|
|
764
|
+
let best: RegisteredTool | undefined;
|
|
765
|
+
let bestCoverage = 0;
|
|
766
|
+
|
|
767
|
+
for (const tool of this.registry.list({ status: 'active' })) {
|
|
768
|
+
const coverage = tool.capabilities.filter(c => uncovered.has(c)).length;
|
|
769
|
+
if (coverage > bestCoverage) {
|
|
770
|
+
best = tool;
|
|
771
|
+
bestCoverage = coverage;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (!best || bestCoverage === 0) break;
|
|
776
|
+
|
|
777
|
+
selected.push(best);
|
|
778
|
+
for (const cap of best.capabilities) {
|
|
779
|
+
uncovered.delete(cap);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
return selected;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Check if capabilities are satisfiable
|
|
787
|
+
canSatisfy(capabilities: string[]): boolean {
|
|
788
|
+
const available = new Set(this.registry.getCapabilities());
|
|
789
|
+
return capabilities.every(c => available.has(c));
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Get missing capabilities
|
|
793
|
+
getMissing(capabilities: string[]): string[] {
|
|
794
|
+
const available = new Set(this.registry.getCapabilities());
|
|
795
|
+
return capabilities.filter(c => !available.has(c));
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
## Integración con Agentes
|
|
803
|
+
|
|
804
|
+
```typescript
|
|
805
|
+
// Uso en agentes
|
|
806
|
+
class SmartAgent {
|
|
807
|
+
private discovery: ToolDiscovery;
|
|
808
|
+
|
|
809
|
+
async selectTools(taskDescription: string): Promise<RegisteredTool[]> {
|
|
810
|
+
// Discover relevant tools
|
|
811
|
+
const results = this.discovery.suggest(taskDescription);
|
|
812
|
+
|
|
813
|
+
// Filter to top matches
|
|
814
|
+
const topTools = results
|
|
815
|
+
.filter(r => r.score > 30)
|
|
816
|
+
.slice(0, 5)
|
|
817
|
+
.map(r => r.tool);
|
|
818
|
+
|
|
819
|
+
return topTools;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
async execute(task: Task): Promise<Result> {
|
|
823
|
+
// Get available tools for this task
|
|
824
|
+
const tools = await this.selectTools(task.description);
|
|
825
|
+
|
|
826
|
+
// Build tool context for prompt
|
|
827
|
+
const toolContext = tools.map(t => ({
|
|
828
|
+
name: t.name,
|
|
829
|
+
description: t.description,
|
|
830
|
+
parameters: t.parameters
|
|
831
|
+
}));
|
|
832
|
+
|
|
833
|
+
// Execute with selected tools
|
|
834
|
+
return this.runWithTools(task, toolContext);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## Comandos
|
|
842
|
+
|
|
843
|
+
```bash
|
|
844
|
+
/elsabro:tools # Listar todas las herramientas
|
|
845
|
+
/elsabro:tools search "file" # Buscar herramientas
|
|
846
|
+
/elsabro:tools info Bash # Ver detalles de herramienta
|
|
847
|
+
/elsabro:tools stats # Ver estadísticas de uso
|
|
848
|
+
/elsabro:tools register ./tool.json # Registrar nueva herramienta
|
|
849
|
+
/elsabro:tools deprecate OldTool # Marcar como deprecated
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
---
|
|
853
|
+
|
|
854
|
+
## Configuración
|
|
855
|
+
|
|
856
|
+
```json
|
|
857
|
+
{
|
|
858
|
+
"toolRegistry": {
|
|
859
|
+
"enabled": true,
|
|
860
|
+
"autoLoadBuiltins": true,
|
|
861
|
+
"customToolsPath": ".elsabro/tools",
|
|
862
|
+
"caching": {
|
|
863
|
+
"enabled": true,
|
|
864
|
+
"ttl": 300000
|
|
865
|
+
},
|
|
866
|
+
"validation": {
|
|
867
|
+
"strictSchema": true,
|
|
868
|
+
"requireExamples": false
|
|
869
|
+
},
|
|
870
|
+
"deprecation": {
|
|
871
|
+
"warningPeriod": "30d",
|
|
872
|
+
"removalPeriod": "90d"
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
---
|
|
879
|
+
|
|
880
|
+
## Changelog
|
|
881
|
+
|
|
882
|
+
- **v3.3.0**: Initial Tool Registry System
|
|
883
|
+
- ToolRegistry with registration/versioning
|
|
884
|
+
- ToolDiscovery for smart tool finding
|
|
885
|
+
- CapabilityMatcher for requirements matching
|
|
886
|
+
- Built-in tool definitions
|