musubi-sdd 3.10.0 → 5.1.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 +24 -19
- package/package.json +1 -1
- package/src/agents/agent-loop.js +532 -0
- package/src/agents/agentic/code-generator.js +767 -0
- package/src/agents/agentic/code-reviewer.js +698 -0
- package/src/agents/agentic/index.js +43 -0
- package/src/agents/function-tool.js +432 -0
- package/src/agents/index.js +45 -0
- package/src/agents/schema-generator.js +514 -0
- package/src/analyzers/ast-extractor.js +870 -0
- package/src/analyzers/context-optimizer.js +681 -0
- package/src/analyzers/repository-map.js +692 -0
- package/src/integrations/index.js +7 -1
- package/src/integrations/mcp/index.js +175 -0
- package/src/integrations/mcp/mcp-context-provider.js +472 -0
- package/src/integrations/mcp/mcp-discovery.js +436 -0
- package/src/integrations/mcp/mcp-tool-registry.js +467 -0
- package/src/integrations/mcp-connector.js +818 -0
- package/src/integrations/tool-discovery.js +589 -0
- package/src/managers/index.js +7 -0
- package/src/managers/skill-tools.js +565 -0
- package/src/monitoring/cost-tracker.js +7 -0
- package/src/monitoring/incident-manager.js +10 -0
- package/src/monitoring/observability.js +10 -0
- package/src/monitoring/quality-dashboard.js +491 -0
- package/src/monitoring/release-manager.js +10 -0
- package/src/orchestration/agent-skill-binding.js +655 -0
- package/src/orchestration/error-handler.js +827 -0
- package/src/orchestration/index.js +235 -1
- package/src/orchestration/mcp-tool-adapters.js +896 -0
- package/src/orchestration/reasoning/index.js +58 -0
- package/src/orchestration/reasoning/planning-engine.js +831 -0
- package/src/orchestration/reasoning/reasoning-engine.js +710 -0
- package/src/orchestration/reasoning/self-correction.js +751 -0
- package/src/orchestration/skill-executor.js +665 -0
- package/src/orchestration/skill-registry.js +650 -0
- package/src/orchestration/workflow-examples.js +1072 -0
- package/src/orchestration/workflow-executor.js +779 -0
- package/src/phase4-integration.js +248 -0
- package/src/phase5-integration.js +402 -0
- package/src/steering/steering-auto-update.js +572 -0
- package/src/steering/steering-validator.js +547 -0
- package/src/templates/template-constraints.js +646 -0
- package/src/validators/advanced-validation.js +580 -0
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool Discovery Service
|
|
3
|
+
* @description Dynamic MCP tool detection and management
|
|
4
|
+
* @version 3.11.0
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Automatic tool discovery from MCP servers
|
|
8
|
+
* - Tool categorization and tagging
|
|
9
|
+
* - Skill-to-tool mapping
|
|
10
|
+
* - Tool capability matching
|
|
11
|
+
* - Tool usage analytics
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const { EventEmitter } = require('events');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Tool Categories
|
|
20
|
+
*/
|
|
21
|
+
const ToolCategory = {
|
|
22
|
+
FILE_SYSTEM: 'file-system',
|
|
23
|
+
CODE_ANALYSIS: 'code-analysis',
|
|
24
|
+
SEARCH: 'search',
|
|
25
|
+
DOCUMENTATION: 'documentation',
|
|
26
|
+
TESTING: 'testing',
|
|
27
|
+
BUILD: 'build',
|
|
28
|
+
DEPLOYMENT: 'deployment',
|
|
29
|
+
MONITORING: 'monitoring',
|
|
30
|
+
DATABASE: 'database',
|
|
31
|
+
API: 'api',
|
|
32
|
+
AI: 'ai',
|
|
33
|
+
UTILITY: 'utility',
|
|
34
|
+
UNKNOWN: 'unknown'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Tool capability scores
|
|
39
|
+
*/
|
|
40
|
+
const CapabilityScore = {
|
|
41
|
+
EXACT_MATCH: 1.0,
|
|
42
|
+
HIGH_MATCH: 0.8,
|
|
43
|
+
MEDIUM_MATCH: 0.6,
|
|
44
|
+
LOW_MATCH: 0.4,
|
|
45
|
+
NO_MATCH: 0.0
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Category keywords for auto-detection
|
|
50
|
+
*/
|
|
51
|
+
const CATEGORY_KEYWORDS = {
|
|
52
|
+
[ToolCategory.FILE_SYSTEM]: ['file', 'read', 'write', 'directory', 'path', 'fs', 'folder'],
|
|
53
|
+
[ToolCategory.CODE_ANALYSIS]: ['code', 'analyze', 'parse', 'ast', 'syntax', 'lint', 'semantic'],
|
|
54
|
+
[ToolCategory.SEARCH]: ['search', 'find', 'grep', 'query', 'lookup', 'index'],
|
|
55
|
+
[ToolCategory.DOCUMENTATION]: ['doc', 'document', 'readme', 'markdown', 'comment', 'jsdoc'],
|
|
56
|
+
[ToolCategory.TESTING]: ['test', 'spec', 'assert', 'mock', 'coverage', 'jest', 'mocha'],
|
|
57
|
+
[ToolCategory.BUILD]: ['build', 'compile', 'bundle', 'webpack', 'transpile', 'package'],
|
|
58
|
+
[ToolCategory.DEPLOYMENT]: ['deploy', 'release', 'publish', 'ci', 'cd', 'docker', 'kubernetes'],
|
|
59
|
+
[ToolCategory.MONITORING]: ['monitor', 'log', 'metric', 'alert', 'trace', 'health'],
|
|
60
|
+
[ToolCategory.DATABASE]: ['database', 'db', 'sql', 'query', 'migrate', 'schema'],
|
|
61
|
+
[ToolCategory.API]: ['api', 'rest', 'http', 'request', 'endpoint', 'graphql'],
|
|
62
|
+
[ToolCategory.AI]: ['ai', 'ml', 'llm', 'generate', 'embed', 'inference', 'model'],
|
|
63
|
+
[ToolCategory.UTILITY]: ['util', 'helper', 'convert', 'format', 'validate', 'transform']
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Discovered Tool with metadata
|
|
68
|
+
*/
|
|
69
|
+
class DiscoveredTool {
|
|
70
|
+
constructor(tool, options = {}) {
|
|
71
|
+
this.name = tool.name;
|
|
72
|
+
this.description = tool.description || '';
|
|
73
|
+
this.inputSchema = tool.inputSchema || {};
|
|
74
|
+
this.server = tool.server || options.server || 'unknown';
|
|
75
|
+
this.category = options.category || ToolCategory.UNKNOWN;
|
|
76
|
+
this.tags = options.tags || [];
|
|
77
|
+
this.capabilities = options.capabilities || [];
|
|
78
|
+
this.usageCount = 0;
|
|
79
|
+
this.lastUsed = null;
|
|
80
|
+
this.averageLatency = 0;
|
|
81
|
+
this.errorRate = 0;
|
|
82
|
+
this.discoveredAt = new Date();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Record tool usage
|
|
87
|
+
* @param {number} latency - Execution latency in ms
|
|
88
|
+
* @param {boolean} success - Whether execution succeeded
|
|
89
|
+
*/
|
|
90
|
+
recordUsage(latency, success = true) {
|
|
91
|
+
this.usageCount++;
|
|
92
|
+
this.lastUsed = new Date();
|
|
93
|
+
|
|
94
|
+
// Update running average latency
|
|
95
|
+
this.averageLatency = (this.averageLatency * (this.usageCount - 1) + latency) / this.usageCount;
|
|
96
|
+
|
|
97
|
+
// Update error rate
|
|
98
|
+
if (!success) {
|
|
99
|
+
this.errorRate = ((this.errorRate * (this.usageCount - 1)) + 1) / this.usageCount;
|
|
100
|
+
} else {
|
|
101
|
+
this.errorRate = (this.errorRate * (this.usageCount - 1)) / this.usageCount;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get tool reliability score
|
|
107
|
+
* @returns {number} Score 0-1
|
|
108
|
+
*/
|
|
109
|
+
getReliabilityScore() {
|
|
110
|
+
if (this.usageCount === 0) return 0.5; // Neutral for unused tools
|
|
111
|
+
return 1 - this.errorRate;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
toJSON() {
|
|
115
|
+
return {
|
|
116
|
+
name: this.name,
|
|
117
|
+
description: this.description,
|
|
118
|
+
server: this.server,
|
|
119
|
+
category: this.category,
|
|
120
|
+
tags: this.tags,
|
|
121
|
+
capabilities: this.capabilities,
|
|
122
|
+
usageCount: this.usageCount,
|
|
123
|
+
lastUsed: this.lastUsed,
|
|
124
|
+
averageLatency: this.averageLatency,
|
|
125
|
+
reliability: this.getReliabilityScore(),
|
|
126
|
+
discoveredAt: this.discoveredAt
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Tool Discovery Service
|
|
133
|
+
*/
|
|
134
|
+
class ToolDiscovery extends EventEmitter {
|
|
135
|
+
constructor(options = {}) {
|
|
136
|
+
super();
|
|
137
|
+
this.options = {
|
|
138
|
+
autoDiscovery: true,
|
|
139
|
+
refreshInterval: 300000, // 5 minutes
|
|
140
|
+
enableAnalytics: true,
|
|
141
|
+
...options
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
this.tools = new Map();
|
|
145
|
+
this.toolsByCategory = new Map();
|
|
146
|
+
this.toolsByServer = new Map();
|
|
147
|
+
this.skillToolMappings = new Map();
|
|
148
|
+
this._refreshTimer = null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Discover tools from MCP connector
|
|
153
|
+
* @param {MCPConnector} connector - MCP connector instance
|
|
154
|
+
* @returns {Promise<Array<DiscoveredTool>>} Discovered tools
|
|
155
|
+
*/
|
|
156
|
+
async discoverFromConnector(connector) {
|
|
157
|
+
const discoveredTools = [];
|
|
158
|
+
const allTools = connector.getAllTools();
|
|
159
|
+
|
|
160
|
+
for (const tool of allTools) {
|
|
161
|
+
const discovered = this._processTool(tool);
|
|
162
|
+
discoveredTools.push(discovered);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
this.emit('discovered', discoveredTools);
|
|
166
|
+
return discoveredTools;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Process and categorize a tool
|
|
171
|
+
* @private
|
|
172
|
+
* @param {Object} tool - Raw tool definition
|
|
173
|
+
* @returns {DiscoveredTool} Processed tool
|
|
174
|
+
*/
|
|
175
|
+
_processTool(tool) {
|
|
176
|
+
const category = this._detectCategory(tool);
|
|
177
|
+
const tags = this._extractTags(tool);
|
|
178
|
+
const capabilities = this._analyzeCapabilities(tool);
|
|
179
|
+
|
|
180
|
+
const discovered = new DiscoveredTool(tool, {
|
|
181
|
+
category,
|
|
182
|
+
tags,
|
|
183
|
+
capabilities
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Index the tool
|
|
187
|
+
this.tools.set(tool.name, discovered);
|
|
188
|
+
|
|
189
|
+
// Index by category
|
|
190
|
+
if (!this.toolsByCategory.has(category)) {
|
|
191
|
+
this.toolsByCategory.set(category, new Set());
|
|
192
|
+
}
|
|
193
|
+
this.toolsByCategory.get(category).add(tool.name);
|
|
194
|
+
|
|
195
|
+
// Index by server
|
|
196
|
+
const server = tool.server || 'unknown';
|
|
197
|
+
if (!this.toolsByServer.has(server)) {
|
|
198
|
+
this.toolsByServer.set(server, new Set());
|
|
199
|
+
}
|
|
200
|
+
this.toolsByServer.get(server).add(tool.name);
|
|
201
|
+
|
|
202
|
+
return discovered;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Detect tool category based on name and description
|
|
207
|
+
* @private
|
|
208
|
+
*/
|
|
209
|
+
_detectCategory(tool) {
|
|
210
|
+
const text = `${tool.name} ${tool.description}`.toLowerCase();
|
|
211
|
+
|
|
212
|
+
let bestCategory = ToolCategory.UNKNOWN;
|
|
213
|
+
let bestScore = 0;
|
|
214
|
+
|
|
215
|
+
for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {
|
|
216
|
+
let score = 0;
|
|
217
|
+
for (const keyword of keywords) {
|
|
218
|
+
if (text.includes(keyword)) {
|
|
219
|
+
score++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (score > bestScore) {
|
|
223
|
+
bestScore = score;
|
|
224
|
+
bestCategory = category;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return bestCategory;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Extract tags from tool definition
|
|
233
|
+
* @private
|
|
234
|
+
*/
|
|
235
|
+
_extractTags(tool) {
|
|
236
|
+
const tags = new Set();
|
|
237
|
+
const text = `${tool.name} ${tool.description}`.toLowerCase();
|
|
238
|
+
|
|
239
|
+
// Extract from name (split by common separators)
|
|
240
|
+
const nameParts = tool.name.split(/[-_./]/);
|
|
241
|
+
for (const part of nameParts) {
|
|
242
|
+
if (part.length > 2) {
|
|
243
|
+
tags.add(part.toLowerCase());
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Extract common action verbs
|
|
248
|
+
const actionVerbs = ['read', 'write', 'create', 'update', 'delete', 'list', 'search', 'analyze', 'generate'];
|
|
249
|
+
for (const verb of actionVerbs) {
|
|
250
|
+
if (text.includes(verb)) {
|
|
251
|
+
tags.add(verb);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Add category as tag
|
|
256
|
+
const category = this._detectCategory(tool);
|
|
257
|
+
if (category !== ToolCategory.UNKNOWN) {
|
|
258
|
+
tags.add(category);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return Array.from(tags);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Analyze tool capabilities based on schema
|
|
266
|
+
* @private
|
|
267
|
+
*/
|
|
268
|
+
_analyzeCapabilities(tool) {
|
|
269
|
+
const capabilities = [];
|
|
270
|
+
const schema = tool.inputSchema || {};
|
|
271
|
+
|
|
272
|
+
// Analyze input parameters
|
|
273
|
+
if (schema.properties) {
|
|
274
|
+
const propNames = Object.keys(schema.properties);
|
|
275
|
+
|
|
276
|
+
if (propNames.some(p => p.includes('file') || p.includes('path'))) {
|
|
277
|
+
capabilities.push('file-operations');
|
|
278
|
+
}
|
|
279
|
+
if (propNames.some(p => p.includes('query') || p.includes('search'))) {
|
|
280
|
+
capabilities.push('search');
|
|
281
|
+
}
|
|
282
|
+
if (propNames.some(p => p.includes('code') || p.includes('source'))) {
|
|
283
|
+
capabilities.push('code-processing');
|
|
284
|
+
}
|
|
285
|
+
if (propNames.some(p => p.includes('url') || p.includes('endpoint'))) {
|
|
286
|
+
capabilities.push('network');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Analyze based on tool name patterns
|
|
291
|
+
const name = tool.name.toLowerCase();
|
|
292
|
+
if (name.includes('list') || name.includes('get')) {
|
|
293
|
+
capabilities.push('read');
|
|
294
|
+
}
|
|
295
|
+
if (name.includes('create') || name.includes('write') || name.includes('add')) {
|
|
296
|
+
capabilities.push('write');
|
|
297
|
+
}
|
|
298
|
+
if (name.includes('delete') || name.includes('remove')) {
|
|
299
|
+
capabilities.push('delete');
|
|
300
|
+
}
|
|
301
|
+
if (name.includes('update') || name.includes('modify') || name.includes('edit')) {
|
|
302
|
+
capabilities.push('update');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return [...new Set(capabilities)];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Find tools matching criteria
|
|
310
|
+
* @param {Object} criteria - Search criteria
|
|
311
|
+
* @returns {Array<DiscoveredTool>} Matching tools
|
|
312
|
+
*/
|
|
313
|
+
findTools(criteria = {}) {
|
|
314
|
+
let results = Array.from(this.tools.values());
|
|
315
|
+
|
|
316
|
+
// Filter by category
|
|
317
|
+
if (criteria.category) {
|
|
318
|
+
results = results.filter(t => t.category === criteria.category);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Filter by server
|
|
322
|
+
if (criteria.server) {
|
|
323
|
+
results = results.filter(t => t.server === criteria.server);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Filter by tags
|
|
327
|
+
if (criteria.tags && criteria.tags.length > 0) {
|
|
328
|
+
results = results.filter(t =>
|
|
329
|
+
criteria.tags.some(tag => t.tags.includes(tag))
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Filter by capabilities
|
|
334
|
+
if (criteria.capabilities && criteria.capabilities.length > 0) {
|
|
335
|
+
results = results.filter(t =>
|
|
336
|
+
criteria.capabilities.some(cap => t.capabilities.includes(cap))
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Filter by name pattern
|
|
341
|
+
if (criteria.namePattern) {
|
|
342
|
+
const pattern = new RegExp(criteria.namePattern, 'i');
|
|
343
|
+
results = results.filter(t => pattern.test(t.name));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Filter by minimum reliability
|
|
347
|
+
if (typeof criteria.minReliability === 'number') {
|
|
348
|
+
results = results.filter(t => t.getReliabilityScore() >= criteria.minReliability);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Sort by relevance or usage
|
|
352
|
+
if (criteria.sortBy === 'usage') {
|
|
353
|
+
results.sort((a, b) => b.usageCount - a.usageCount);
|
|
354
|
+
} else if (criteria.sortBy === 'reliability') {
|
|
355
|
+
results.sort((a, b) => b.getReliabilityScore() - a.getReliabilityScore());
|
|
356
|
+
} else if (criteria.sortBy === 'latency') {
|
|
357
|
+
results.sort((a, b) => a.averageLatency - b.averageLatency);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Limit results
|
|
361
|
+
if (criteria.limit) {
|
|
362
|
+
results = results.slice(0, criteria.limit);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return results;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Match tools to a task description
|
|
370
|
+
* @param {string} taskDescription - Task description
|
|
371
|
+
* @param {Object} options - Matching options
|
|
372
|
+
* @returns {Array<Object>} Matched tools with scores
|
|
373
|
+
*/
|
|
374
|
+
matchToolsToTask(taskDescription, options = {}) {
|
|
375
|
+
const { limit = 5, minScore = 0.3 } = options;
|
|
376
|
+
const matches = [];
|
|
377
|
+
const taskWords = taskDescription.toLowerCase().split(/\s+/);
|
|
378
|
+
|
|
379
|
+
for (const tool of this.tools.values()) {
|
|
380
|
+
let score = 0;
|
|
381
|
+
const toolText = `${tool.name} ${tool.description} ${tool.tags.join(' ')}`.toLowerCase();
|
|
382
|
+
|
|
383
|
+
// Calculate word overlap
|
|
384
|
+
for (const word of taskWords) {
|
|
385
|
+
if (word.length > 2 && toolText.includes(word)) {
|
|
386
|
+
score += 0.2;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Bonus for capability match
|
|
391
|
+
for (const capability of tool.capabilities) {
|
|
392
|
+
if (taskDescription.toLowerCase().includes(capability)) {
|
|
393
|
+
score += 0.3;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Bonus for category match
|
|
398
|
+
for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {
|
|
399
|
+
if (tool.category === category) {
|
|
400
|
+
for (const keyword of keywords) {
|
|
401
|
+
if (taskDescription.toLowerCase().includes(keyword)) {
|
|
402
|
+
score += 0.15;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Apply reliability factor
|
|
410
|
+
score *= (0.5 + 0.5 * tool.getReliabilityScore());
|
|
411
|
+
|
|
412
|
+
// Normalize score to 0-1
|
|
413
|
+
score = Math.min(1.0, score);
|
|
414
|
+
|
|
415
|
+
if (score >= minScore) {
|
|
416
|
+
matches.push({ tool, score });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Sort by score descending
|
|
421
|
+
matches.sort((a, b) => b.score - a.score);
|
|
422
|
+
|
|
423
|
+
return matches.slice(0, limit);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Map skills to available tools
|
|
428
|
+
* @param {Array<Object>} skills - Skill definitions
|
|
429
|
+
* @returns {Map<string, Array<string>>} Skill to tools mapping
|
|
430
|
+
*/
|
|
431
|
+
mapSkillsToTools(skills) {
|
|
432
|
+
const mappings = new Map();
|
|
433
|
+
|
|
434
|
+
for (const skill of skills) {
|
|
435
|
+
const skillName = skill.name || skill.id;
|
|
436
|
+
const matchedTools = [];
|
|
437
|
+
|
|
438
|
+
// Match by allowed-tools if defined
|
|
439
|
+
if (skill.allowedTools && Array.isArray(skill.allowedTools)) {
|
|
440
|
+
for (const toolName of skill.allowedTools) {
|
|
441
|
+
if (this.tools.has(toolName)) {
|
|
442
|
+
matchedTools.push(toolName);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Match by skill description/purpose
|
|
448
|
+
if (skill.description || skill.purpose) {
|
|
449
|
+
const taskMatch = this.matchToolsToTask(
|
|
450
|
+
skill.description || skill.purpose,
|
|
451
|
+
{ limit: 3, minScore: 0.4 }
|
|
452
|
+
);
|
|
453
|
+
for (const { tool } of taskMatch) {
|
|
454
|
+
if (!matchedTools.includes(tool.name)) {
|
|
455
|
+
matchedTools.push(tool.name);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
mappings.set(skillName, matchedTools);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
this.skillToolMappings = mappings;
|
|
464
|
+
return mappings;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Get tools for a specific skill
|
|
469
|
+
* @param {string} skillName - Skill name
|
|
470
|
+
* @returns {Array<DiscoveredTool>} Tools for the skill
|
|
471
|
+
*/
|
|
472
|
+
getToolsForSkill(skillName) {
|
|
473
|
+
const toolNames = this.skillToolMappings.get(skillName) || [];
|
|
474
|
+
return toolNames
|
|
475
|
+
.map(name => this.tools.get(name))
|
|
476
|
+
.filter(Boolean);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Record tool usage
|
|
481
|
+
* @param {string} toolName - Tool name
|
|
482
|
+
* @param {number} latency - Execution latency
|
|
483
|
+
* @param {boolean} success - Whether execution succeeded
|
|
484
|
+
*/
|
|
485
|
+
recordToolUsage(toolName, latency, success = true) {
|
|
486
|
+
const tool = this.tools.get(toolName);
|
|
487
|
+
if (tool) {
|
|
488
|
+
tool.recordUsage(latency, success);
|
|
489
|
+
this.emit('toolUsed', { toolName, latency, success });
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Get analytics summary
|
|
495
|
+
* @returns {Object} Analytics data
|
|
496
|
+
*/
|
|
497
|
+
getAnalytics() {
|
|
498
|
+
const tools = Array.from(this.tools.values());
|
|
499
|
+
|
|
500
|
+
const byCategory = {};
|
|
501
|
+
for (const [category, toolNames] of this.toolsByCategory) {
|
|
502
|
+
byCategory[category] = toolNames.size;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const byServer = {};
|
|
506
|
+
for (const [server, toolNames] of this.toolsByServer) {
|
|
507
|
+
byServer[server] = toolNames.size;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const topUsed = tools
|
|
511
|
+
.sort((a, b) => b.usageCount - a.usageCount)
|
|
512
|
+
.slice(0, 10)
|
|
513
|
+
.map(t => ({ name: t.name, usageCount: t.usageCount }));
|
|
514
|
+
|
|
515
|
+
const leastReliable = tools
|
|
516
|
+
.filter(t => t.usageCount > 0)
|
|
517
|
+
.sort((a, b) => a.getReliabilityScore() - b.getReliabilityScore())
|
|
518
|
+
.slice(0, 5)
|
|
519
|
+
.map(t => ({ name: t.name, reliability: t.getReliabilityScore() }));
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
totalTools: this.tools.size,
|
|
523
|
+
byCategory,
|
|
524
|
+
byServer,
|
|
525
|
+
topUsed,
|
|
526
|
+
leastReliable,
|
|
527
|
+
totalUsage: tools.reduce((sum, t) => sum + t.usageCount, 0)
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Start auto-refresh timer
|
|
533
|
+
*/
|
|
534
|
+
startAutoRefresh(connector) {
|
|
535
|
+
if (this._refreshTimer) {
|
|
536
|
+
clearInterval(this._refreshTimer);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
this._refreshTimer = setInterval(async () => {
|
|
540
|
+
try {
|
|
541
|
+
await this.discoverFromConnector(connector);
|
|
542
|
+
this.emit('refreshed');
|
|
543
|
+
} catch (error) {
|
|
544
|
+
this.emit('refreshError', error);
|
|
545
|
+
}
|
|
546
|
+
}, this.options.refreshInterval);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Stop auto-refresh timer
|
|
551
|
+
*/
|
|
552
|
+
stopAutoRefresh() {
|
|
553
|
+
if (this._refreshTimer) {
|
|
554
|
+
clearInterval(this._refreshTimer);
|
|
555
|
+
this._refreshTimer = null;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Clear all discovered tools
|
|
561
|
+
*/
|
|
562
|
+
clear() {
|
|
563
|
+
this.tools.clear();
|
|
564
|
+
this.toolsByCategory.clear();
|
|
565
|
+
this.toolsByServer.clear();
|
|
566
|
+
this.skillToolMappings.clear();
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Export tool catalog
|
|
571
|
+
* @returns {Object} Catalog data
|
|
572
|
+
*/
|
|
573
|
+
exportCatalog() {
|
|
574
|
+
return {
|
|
575
|
+
exportedAt: new Date().toISOString(),
|
|
576
|
+
tools: Array.from(this.tools.values()).map(t => t.toJSON()),
|
|
577
|
+
categories: Object.values(ToolCategory),
|
|
578
|
+
analytics: this.getAnalytics()
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
module.exports = {
|
|
584
|
+
ToolDiscovery,
|
|
585
|
+
DiscoveredTool,
|
|
586
|
+
ToolCategory,
|
|
587
|
+
CapabilityScore,
|
|
588
|
+
CATEGORY_KEYWORDS
|
|
589
|
+
};
|
package/src/managers/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const MemoryCondenser = require('./memory-condenser');
|
|
|
12
12
|
const RepoSkillManager = require('./repo-skill-manager');
|
|
13
13
|
const SkillLoader = require('./skill-loader');
|
|
14
14
|
const WorkflowManager = require('./workflow');
|
|
15
|
+
const { SkillToolsManager, SkillToolConfig, RestrictionLevel, DEFAULT_TOOL_SETS } = require('./skill-tools');
|
|
15
16
|
|
|
16
17
|
module.exports = {
|
|
17
18
|
// Checkpoint
|
|
@@ -19,6 +20,12 @@ module.exports = {
|
|
|
19
20
|
CheckpointState,
|
|
20
21
|
CheckpointConfig,
|
|
21
22
|
|
|
23
|
+
// Skill Tools (Sprint 3.4)
|
|
24
|
+
SkillToolsManager,
|
|
25
|
+
SkillToolConfig,
|
|
26
|
+
RestrictionLevel,
|
|
27
|
+
DEFAULT_TOOL_SETS,
|
|
28
|
+
|
|
22
29
|
// Other managers
|
|
23
30
|
AgentMemory,
|
|
24
31
|
ChangeManager,
|