@claude-flow/cli 3.0.0-alpha.177 → 3.0.0-alpha.179
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 +1 -0
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/hooks.js +22 -0
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/hooks-tools.js +262 -13
- package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
- package/dist/src/ruvector/index.d.ts +1 -0
- package/dist/src/ruvector/index.d.ts.map +1 -1
- package/dist/src/ruvector/index.js +1 -0
- package/dist/src/ruvector/index.js.map +1 -1
- package/dist/src/ruvector/semantic-router.d.ts +77 -0
- package/dist/src/ruvector/semantic-router.d.ts.map +1 -0
- package/dist/src/ruvector/semantic-router.js +178 -0
- package/dist/src/ruvector/semantic-router.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp-tools/hooks-tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp-tools/hooks-tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA6jB1C,eAAO,MAAM,YAAY,EAAE,OAsC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,OAwB3B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,OAkC7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,OAuB9B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,OAiIxB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,OAyC1B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,OA8CvB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,OAoF1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,OA+B3B,CAAC;AAGF,eAAO,MAAM,YAAY,EAAE,OAsD1B,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,OAsC3B,CAAC;AAGF,eAAO,MAAM,gBAAgB,EAAE,OAoE9B,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,OAyE3B,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,OAsD/B,CAAC;AAGF,eAAO,MAAM,eAAe,EAAE,OAgD7B,CAAC;AAGF,eAAO,MAAM,mBAAmB,EAAE,OAuCjC,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,OA4BzB,CAAC;AAGF,eAAO,MAAM,SAAS,EAAE,OAsCvB,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,OAsG/B,CAAC;AAGF,eAAO,MAAM,sBAAsB,EAAE,OAkBpC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,OAsClC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,OA4CjC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,OA4IhC,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,OA0D/B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,OA8EhC,CAAC;AAGF,eAAO,MAAM,sBAAsB,EAAE,OA8KpC,CAAC;AAGF,eAAO,MAAM,sBAAsB,EAAE,OAwEpC,CAAC;AAGF,eAAO,MAAM,0BAA0B,EAAE,OAsHxC,CAAC;AA8PF,eAAO,MAAM,eAAe,EAAE,OA8C7B,CAAC;AAGF,eAAO,MAAM,mBAAmB,EAAE,OAiGjC,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,OAqD/B,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,OAgE/B,CAAC;AAiBF,eAAO,MAAM,eAAe,EAAE,OAyC7B,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,OA8B/B,CAAC;AAGF,eAAO,MAAM,eAAe,EAAE,OAuB7B,CAAC;AAqBF,eAAO,MAAM,iBAAiB,EAAE,OAuC/B,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,OAAO,EAwC/B,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -77,6 +77,178 @@ async function getMoERouter() {
|
|
|
77
77
|
}
|
|
78
78
|
return moeRouter;
|
|
79
79
|
}
|
|
80
|
+
// Semantic Router - lazy loaded
|
|
81
|
+
// Tries native VectorDb first (16k+ routes/s HNSW), falls back to pure JS (47k routes/s cosine)
|
|
82
|
+
let semanticRouter = null;
|
|
83
|
+
let nativeVectorDb = null;
|
|
84
|
+
let semanticRouterInitialized = false;
|
|
85
|
+
let routerBackend = 'none';
|
|
86
|
+
// Pre-computed embeddings for common task patterns (cached)
|
|
87
|
+
const TASK_PATTERN_EMBEDDINGS = new Map();
|
|
88
|
+
function generateSimpleEmbedding(text, dimension = 384) {
|
|
89
|
+
// Simple deterministic embedding based on character codes
|
|
90
|
+
// This is for routing purposes where we need consistent, fast embeddings
|
|
91
|
+
const embedding = new Float32Array(dimension);
|
|
92
|
+
const normalized = text.toLowerCase().replace(/[^a-z0-9\s]/g, '');
|
|
93
|
+
const words = normalized.split(/\s+/).filter(w => w.length > 0);
|
|
94
|
+
// Combine word-level and character-level features
|
|
95
|
+
for (let i = 0; i < dimension; i++) {
|
|
96
|
+
let value = 0;
|
|
97
|
+
// Word-level features
|
|
98
|
+
for (let w = 0; w < words.length; w++) {
|
|
99
|
+
const word = words[w];
|
|
100
|
+
for (let c = 0; c < word.length; c++) {
|
|
101
|
+
const charCode = word.charCodeAt(c);
|
|
102
|
+
value += Math.sin((charCode * (i + 1) + w * 17 + c * 23) * 0.0137);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Character-level features
|
|
106
|
+
for (let c = 0; c < text.length; c++) {
|
|
107
|
+
value += Math.cos((text.charCodeAt(c) * (i + 1) + c * 7) * 0.0073);
|
|
108
|
+
}
|
|
109
|
+
embedding[i] = value / Math.max(1, text.length);
|
|
110
|
+
}
|
|
111
|
+
// Normalize
|
|
112
|
+
let norm = 0;
|
|
113
|
+
for (let i = 0; i < dimension; i++) {
|
|
114
|
+
norm += embedding[i] * embedding[i];
|
|
115
|
+
}
|
|
116
|
+
norm = Math.sqrt(norm);
|
|
117
|
+
if (norm > 0) {
|
|
118
|
+
for (let i = 0; i < dimension; i++) {
|
|
119
|
+
embedding[i] /= norm;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return embedding;
|
|
123
|
+
}
|
|
124
|
+
// Task patterns used by both native and pure-JS routers
|
|
125
|
+
const TASK_PATTERNS = {
|
|
126
|
+
'security-task': {
|
|
127
|
+
keywords: ['authentication', 'security', 'auth', 'password', 'encryption', 'vulnerability', 'cve', 'audit'],
|
|
128
|
+
agents: ['security-architect', 'security-auditor', 'reviewer'],
|
|
129
|
+
},
|
|
130
|
+
'testing-task': {
|
|
131
|
+
keywords: ['test', 'testing', 'spec', 'coverage', 'unit test', 'integration test', 'e2e'],
|
|
132
|
+
agents: ['tester', 'reviewer'],
|
|
133
|
+
},
|
|
134
|
+
'api-task': {
|
|
135
|
+
keywords: ['api', 'endpoint', 'rest', 'graphql', 'route', 'handler', 'controller'],
|
|
136
|
+
agents: ['architect', 'coder', 'tester'],
|
|
137
|
+
},
|
|
138
|
+
'performance-task': {
|
|
139
|
+
keywords: ['performance', 'optimize', 'speed', 'memory', 'benchmark', 'profiling', 'bottleneck'],
|
|
140
|
+
agents: ['performance-engineer', 'coder', 'tester'],
|
|
141
|
+
},
|
|
142
|
+
'refactor-task': {
|
|
143
|
+
keywords: ['refactor', 'restructure', 'clean', 'organize', 'modular', 'decouple'],
|
|
144
|
+
agents: ['architect', 'coder', 'reviewer'],
|
|
145
|
+
},
|
|
146
|
+
'bugfix-task': {
|
|
147
|
+
keywords: ['bug', 'fix', 'error', 'issue', 'broken', 'crash', 'debug'],
|
|
148
|
+
agents: ['coder', 'tester', 'reviewer'],
|
|
149
|
+
},
|
|
150
|
+
'feature-task': {
|
|
151
|
+
keywords: ['feature', 'implement', 'add', 'new', 'create', 'build'],
|
|
152
|
+
agents: ['architect', 'coder', 'tester'],
|
|
153
|
+
},
|
|
154
|
+
'database-task': {
|
|
155
|
+
keywords: ['database', 'sql', 'query', 'schema', 'migration', 'orm'],
|
|
156
|
+
agents: ['architect', 'coder', 'tester'],
|
|
157
|
+
},
|
|
158
|
+
'frontend-task': {
|
|
159
|
+
keywords: ['frontend', 'ui', 'component', 'react', 'css', 'style', 'layout'],
|
|
160
|
+
agents: ['coder', 'reviewer', 'tester'],
|
|
161
|
+
},
|
|
162
|
+
'devops-task': {
|
|
163
|
+
keywords: ['deploy', 'ci', 'cd', 'pipeline', 'docker', 'kubernetes', 'infrastructure'],
|
|
164
|
+
agents: ['devops', 'coder', 'tester'],
|
|
165
|
+
},
|
|
166
|
+
'swarm-task': {
|
|
167
|
+
keywords: ['swarm', 'agent', 'coordinator', 'hive', 'mesh', 'topology'],
|
|
168
|
+
agents: ['swarm-specialist', 'coordinator', 'architect'],
|
|
169
|
+
},
|
|
170
|
+
'memory-task': {
|
|
171
|
+
keywords: ['memory', 'cache', 'store', 'vector', 'embedding', 'persistence'],
|
|
172
|
+
agents: ['memory-specialist', 'architect', 'coder'],
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Get the semantic router with environment detection.
|
|
177
|
+
* Tries native VectorDb first (HNSW, 16k routes/s), falls back to pure JS (47k routes/s cosine).
|
|
178
|
+
*/
|
|
179
|
+
async function getSemanticRouter() {
|
|
180
|
+
if (semanticRouterInitialized) {
|
|
181
|
+
return { router: semanticRouter, backend: routerBackend, native: nativeVectorDb };
|
|
182
|
+
}
|
|
183
|
+
semanticRouterInitialized = true;
|
|
184
|
+
// STEP 1: Try native VectorDb from @ruvector/router (HNSW-backed)
|
|
185
|
+
// Note: Native VectorDb uses a persistent database file which can have lock issues
|
|
186
|
+
// in concurrent environments. We try it first but fall back gracefully to pure JS.
|
|
187
|
+
try {
|
|
188
|
+
// Use createRequire for ESM compatibility with native modules
|
|
189
|
+
const { createRequire } = await import('module');
|
|
190
|
+
const require = createRequire(import.meta.url);
|
|
191
|
+
const router = require('@ruvector/router');
|
|
192
|
+
if (router.VectorDb && router.DistanceMetric) {
|
|
193
|
+
// Try to create VectorDb - may fail with lock error in concurrent envs
|
|
194
|
+
const db = new router.VectorDb({
|
|
195
|
+
dimensions: 384,
|
|
196
|
+
distanceMetric: router.DistanceMetric.Cosine,
|
|
197
|
+
hnswM: 16,
|
|
198
|
+
hnswEfConstruction: 200,
|
|
199
|
+
hnswEfSearch: 100,
|
|
200
|
+
});
|
|
201
|
+
// Initialize with task patterns
|
|
202
|
+
for (const [patternName, { keywords }] of Object.entries(TASK_PATTERNS)) {
|
|
203
|
+
for (const keyword of keywords) {
|
|
204
|
+
const embedding = generateSimpleEmbedding(keyword);
|
|
205
|
+
db.insert(`${patternName}:${keyword}`, embedding);
|
|
206
|
+
TASK_PATTERN_EMBEDDINGS.set(`${patternName}:${keyword}`, embedding);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
nativeVectorDb = db;
|
|
210
|
+
routerBackend = 'native';
|
|
211
|
+
return { router: null, backend: routerBackend, native: nativeVectorDb };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
// Native not available or database locked - fall back to pure JS
|
|
216
|
+
// Common errors: "Database already open. Cannot acquire lock." or "MODULE_NOT_FOUND"
|
|
217
|
+
// This is expected in concurrent environments or when binary isn't installed
|
|
218
|
+
}
|
|
219
|
+
// STEP 2: Fall back to pure JS SemanticRouter
|
|
220
|
+
try {
|
|
221
|
+
const { SemanticRouter } = await import('../ruvector/semantic-router.js');
|
|
222
|
+
semanticRouter = new SemanticRouter({ dimension: 384 });
|
|
223
|
+
for (const [patternName, { keywords, agents }] of Object.entries(TASK_PATTERNS)) {
|
|
224
|
+
const embeddings = keywords.map(kw => generateSimpleEmbedding(kw));
|
|
225
|
+
semanticRouter.addIntentWithEmbeddings(patternName, embeddings, { agents, keywords });
|
|
226
|
+
// Cache embeddings for keywords
|
|
227
|
+
keywords.forEach((kw, i) => {
|
|
228
|
+
TASK_PATTERN_EMBEDDINGS.set(kw, embeddings[i]);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
routerBackend = 'pure-js';
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
semanticRouter = null;
|
|
235
|
+
routerBackend = 'none';
|
|
236
|
+
}
|
|
237
|
+
return { router: semanticRouter, backend: routerBackend, native: nativeVectorDb };
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get router backend info for status display.
|
|
241
|
+
*/
|
|
242
|
+
function getRouterBackendInfo() {
|
|
243
|
+
switch (routerBackend) {
|
|
244
|
+
case 'native':
|
|
245
|
+
return { backend: 'native VectorDb (HNSW)', speed: '16k+ routes/s' };
|
|
246
|
+
case 'pure-js':
|
|
247
|
+
return { backend: 'pure JS (cosine)', speed: '47k routes/s' };
|
|
248
|
+
default:
|
|
249
|
+
return { backend: 'none', speed: 'N/A' };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
80
252
|
// Flash Attention - lazy loaded
|
|
81
253
|
let flashAttention = null;
|
|
82
254
|
async function getFlashAttention() {
|
|
@@ -208,7 +380,8 @@ const AGENT_PATTERNS = {
|
|
|
208
380
|
'.css': ['coder', 'designer'],
|
|
209
381
|
'.scss': ['coder', 'designer'],
|
|
210
382
|
};
|
|
211
|
-
|
|
383
|
+
// Keyword patterns for fallback routing (when semantic routing doesn't match)
|
|
384
|
+
const KEYWORD_PATTERNS = {
|
|
212
385
|
'authentication': { agents: ['security-architect', 'coder', 'tester'], confidence: 0.9 },
|
|
213
386
|
'auth': { agents: ['security-architect', 'coder', 'tester'], confidence: 0.85 },
|
|
214
387
|
'api': { agents: ['architect', 'coder', 'tester'], confidence: 0.85 },
|
|
@@ -241,7 +414,7 @@ function suggestAgentsForFile(filePath) {
|
|
|
241
414
|
}
|
|
242
415
|
function suggestAgentsForTask(task) {
|
|
243
416
|
const taskLower = task.toLowerCase();
|
|
244
|
-
for (const [pattern, result] of Object.entries(
|
|
417
|
+
for (const [pattern, result] of Object.entries(KEYWORD_PATTERNS)) {
|
|
245
418
|
if (taskLower.includes(pattern)) {
|
|
246
419
|
return result;
|
|
247
420
|
}
|
|
@@ -406,19 +579,82 @@ export const hooksPostCommand = {
|
|
|
406
579
|
};
|
|
407
580
|
export const hooksRoute = {
|
|
408
581
|
name: 'hooks_route',
|
|
409
|
-
description: 'Route task to optimal agent using
|
|
582
|
+
description: 'Route task to optimal agent using semantic similarity (native HNSW or pure JS)',
|
|
410
583
|
inputSchema: {
|
|
411
584
|
type: 'object',
|
|
412
585
|
properties: {
|
|
413
586
|
task: { type: 'string', description: 'Task description' },
|
|
414
587
|
context: { type: 'string', description: 'Additional context' },
|
|
588
|
+
useSemanticRouter: { type: 'boolean', description: 'Use semantic similarity routing (default: true)' },
|
|
415
589
|
},
|
|
416
590
|
required: ['task'],
|
|
417
591
|
},
|
|
418
592
|
handler: async (params) => {
|
|
419
593
|
const task = params.task;
|
|
420
|
-
const
|
|
421
|
-
|
|
594
|
+
const context = params.context;
|
|
595
|
+
const useSemanticRouter = params.useSemanticRouter !== false;
|
|
596
|
+
// Get router (tries native VectorDb first, falls back to pure JS)
|
|
597
|
+
const { router, backend, native } = useSemanticRouter
|
|
598
|
+
? await getSemanticRouter()
|
|
599
|
+
: { router: null, backend: 'none', native: null };
|
|
600
|
+
let semanticResult = [];
|
|
601
|
+
let routingMethod = 'keyword';
|
|
602
|
+
let routingLatencyMs = 0;
|
|
603
|
+
let backendInfo = '';
|
|
604
|
+
const queryText = context ? `${task} ${context}` : task;
|
|
605
|
+
const queryEmbedding = generateSimpleEmbedding(queryText);
|
|
606
|
+
// Try native VectorDb (HNSW-backed)
|
|
607
|
+
if (native && backend === 'native') {
|
|
608
|
+
const routeStart = performance.now();
|
|
609
|
+
try {
|
|
610
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
611
|
+
const results = native.search(queryEmbedding, 5);
|
|
612
|
+
routingLatencyMs = performance.now() - routeStart;
|
|
613
|
+
routingMethod = 'semantic-native';
|
|
614
|
+
backendInfo = 'native VectorDb (HNSW)';
|
|
615
|
+
// Convert results to semantic format
|
|
616
|
+
semanticResult = results.map((r) => {
|
|
617
|
+
const [patternName] = r.id.split(':');
|
|
618
|
+
const pattern = TASK_PATTERNS[patternName];
|
|
619
|
+
return {
|
|
620
|
+
intent: patternName,
|
|
621
|
+
score: 1 - r.score, // Native uses distance (lower is better), convert to similarity
|
|
622
|
+
metadata: { agents: pattern?.agents || ['coder'] },
|
|
623
|
+
};
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
// Native failed, try pure JS fallback
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
// Try pure JS SemanticRouter fallback
|
|
631
|
+
if (router && backend === 'pure-js' && semanticResult.length === 0) {
|
|
632
|
+
const routeStart = performance.now();
|
|
633
|
+
semanticResult = router.routeWithEmbedding(queryEmbedding, 3);
|
|
634
|
+
routingLatencyMs = performance.now() - routeStart;
|
|
635
|
+
routingMethod = 'semantic-pure-js';
|
|
636
|
+
backendInfo = 'pure JS (cosine similarity)';
|
|
637
|
+
}
|
|
638
|
+
// Get agents from semantic routing or fall back to keyword
|
|
639
|
+
let agents;
|
|
640
|
+
let confidence;
|
|
641
|
+
let matchedPattern = '';
|
|
642
|
+
if (semanticResult.length > 0 && semanticResult[0].score > 0.4) {
|
|
643
|
+
const topMatch = semanticResult[0];
|
|
644
|
+
agents = topMatch.metadata.agents || ['coder', 'researcher'];
|
|
645
|
+
confidence = topMatch.score;
|
|
646
|
+
matchedPattern = topMatch.intent;
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
// Fall back to keyword matching
|
|
650
|
+
const suggestion = suggestAgentsForTask(task);
|
|
651
|
+
agents = suggestion.agents;
|
|
652
|
+
confidence = suggestion.confidence;
|
|
653
|
+
matchedPattern = 'keyword-fallback';
|
|
654
|
+
routingMethod = 'keyword';
|
|
655
|
+
backendInfo = 'keyword matching';
|
|
656
|
+
}
|
|
657
|
+
// Determine complexity
|
|
422
658
|
const taskLower = task.toLowerCase();
|
|
423
659
|
const complexity = taskLower.includes('complex') || taskLower.includes('architecture') || task.length > 200
|
|
424
660
|
? 'high'
|
|
@@ -427,24 +663,37 @@ export const hooksRoute = {
|
|
|
427
663
|
: 'medium';
|
|
428
664
|
return {
|
|
429
665
|
task,
|
|
666
|
+
routing: {
|
|
667
|
+
method: routingMethod,
|
|
668
|
+
backend: backendInfo,
|
|
669
|
+
latencyMs: routingLatencyMs,
|
|
670
|
+
throughput: routingLatencyMs > 0 ? `${Math.round(1000 / routingLatencyMs)} routes/s` : 'N/A',
|
|
671
|
+
},
|
|
672
|
+
matchedPattern,
|
|
673
|
+
semanticMatches: semanticResult.slice(0, 3).map(r => ({
|
|
674
|
+
pattern: r.intent,
|
|
675
|
+
score: Math.round(r.score * 100) / 100,
|
|
676
|
+
})),
|
|
430
677
|
primaryAgent: {
|
|
431
|
-
type:
|
|
432
|
-
confidence:
|
|
433
|
-
reason:
|
|
678
|
+
type: agents[0],
|
|
679
|
+
confidence: Math.round(confidence * 100) / 100,
|
|
680
|
+
reason: routingMethod.startsWith('semantic')
|
|
681
|
+
? `Semantic similarity to "${matchedPattern}" pattern (${Math.round(confidence * 100)}%)`
|
|
682
|
+
: `Task contains keywords matching ${agents[0]} specialization`,
|
|
434
683
|
},
|
|
435
|
-
alternativeAgents:
|
|
684
|
+
alternativeAgents: agents.slice(1).map((agent, i) => ({
|
|
436
685
|
type: agent,
|
|
437
|
-
confidence:
|
|
686
|
+
confidence: Math.round((confidence - (0.1 * (i + 1))) * 100) / 100,
|
|
438
687
|
reason: `Alternative agent for ${agent} capabilities`,
|
|
439
688
|
})),
|
|
440
689
|
estimatedMetrics: {
|
|
441
|
-
successProbability:
|
|
690
|
+
successProbability: Math.round(confidence * 100) / 100,
|
|
442
691
|
estimatedDuration: complexity === 'high' ? '2-4 hours' : complexity === 'medium' ? '30-60 min' : '10-30 min',
|
|
443
692
|
complexity,
|
|
444
693
|
},
|
|
445
|
-
swarmRecommendation:
|
|
694
|
+
swarmRecommendation: agents.length > 2 ? {
|
|
446
695
|
topology: 'hierarchical',
|
|
447
|
-
agents
|
|
696
|
+
agents,
|
|
448
697
|
coordination: 'queen-led',
|
|
449
698
|
} : null,
|
|
450
699
|
};
|