claude-flow 3.7.0-alpha.51 → 3.7.0-alpha.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-flow",
3
- "version": "3.7.0-alpha.51",
3
+ "version": "3.7.0-alpha.52",
4
4
  "description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1280,6 +1280,149 @@ export const embeddingsTools = [
1280
1280
  },
1281
1281
  },
1282
1282
  // ============================================================
1283
+ // ADR-121 Phase 11 — RRF ensemble retrieval (alpha.52 CLI)
1284
+ // ============================================================
1285
+ //
1286
+ // Question-reformulation pipelines produce N parallel result lists.
1287
+ // Reciprocal Rank Fusion (Cormack-Clarke-Büttcher 2009) fuses them
1288
+ // into a single ranking without needing score comparability across
1289
+ // lists. Composes `embeddings_search_text_batch` (N parallel
1290
+ // searches) with `reciprocalRankFusion` (rank-level merge).
1291
+ //
1292
+ // Standard production ensemble-RAG pattern. Pairs naturally with
1293
+ // LLM query rewriting upstream (expand "how does auth work?" into
1294
+ // {"how does authentication work?", "what's the login flow?",
1295
+ // "describe the OAuth2 handshake"} → batch search each →
1296
+ // RRF-fuse) — recovers more relevant docs than a single search.
1297
+ {
1298
+ name: 'embeddings_search_text_ensemble',
1299
+ description: "Embed N text query variants, search a named AnnRouter handle for each in parallel, then RRF-fuse (Reciprocal Rank Fusion, Cormack-Clarke-Büttcher 2009) the N hit-lists into a single merged top-k ranking. Standard production shape for question-reformulation RAG: agents expand one user question into N variants, retrieve top-k for each, get a single fused list back — items appearing high in MORE variants outrank items appearing high in only one. Returns fused hits with per-list ranks for transparency + aggregate latency. λ-equivalent here is `kRrf` (default 60 per SIGIR 2009). Per-list `listWeights` available for biased ensemble (e.g. weight the original-query list 2× over reformulations). For non-fused multi-query results use embeddings_search_text_batch; for single-query diverse retrieval use embeddings_search_text_diverse.",
1300
+ category: 'embeddings',
1301
+ inputSchema: {
1302
+ type: 'object',
1303
+ properties: {
1304
+ texts: {
1305
+ type: 'array',
1306
+ items: { type: 'string' },
1307
+ description: 'Array of query text variants. Order preserved in per-list ranks.',
1308
+ },
1309
+ name: { type: 'string', description: 'AnnRouter handle name (set by embeddings_ann_router_build).' },
1310
+ k: { type: 'number', description: 'Number of fused results to return.' },
1311
+ perQueryK: {
1312
+ type: 'number',
1313
+ description: 'Top-k per query before fusion. Default 2*k. Larger = wider candidate pool, more compute.',
1314
+ },
1315
+ kRrf: {
1316
+ type: 'number',
1317
+ description: 'RRF smoothing constant. Default 60 (SIGIR 2009). Smaller = top-rank dominance.',
1318
+ },
1319
+ listWeights: {
1320
+ type: 'array',
1321
+ items: { type: 'number' },
1322
+ description: 'Per-query weights. Length must equal texts.length. Default = 1 each.',
1323
+ },
1324
+ },
1325
+ required: ['texts', 'name', 'k'],
1326
+ },
1327
+ handler: async (input) => {
1328
+ const config = loadConfig();
1329
+ if (!config) {
1330
+ return { success: false, error: 'Embeddings not initialized. Run embeddings_init first.' };
1331
+ }
1332
+ const texts = input.texts;
1333
+ const name = input.name;
1334
+ const k = input.k;
1335
+ const perQueryK = typeof input.perQueryK === 'number' && input.perQueryK >= 1
1336
+ ? input.perQueryK
1337
+ : Math.max(k * 2, k);
1338
+ const kRrf = typeof input.kRrf === 'number' && input.kRrf > 0 ? input.kRrf : 60;
1339
+ const listWeights = Array.isArray(input.listWeights) ? input.listWeights : undefined;
1340
+ if (!Array.isArray(texts) || texts.length === 0) {
1341
+ return { success: false, error: 'texts must be a non-empty array' };
1342
+ }
1343
+ if (!Number.isInteger(k) || k < 1) {
1344
+ return { success: false, error: 'k must be a positive integer' };
1345
+ }
1346
+ for (let i = 0; i < texts.length; i++) {
1347
+ if (typeof texts[i] !== 'string') {
1348
+ return { success: false, error: `texts[${i}] is not a string` };
1349
+ }
1350
+ }
1351
+ if (listWeights && listWeights.length !== texts.length) {
1352
+ return {
1353
+ success: false,
1354
+ error: `listWeights.length (${listWeights.length}) must match texts.length (${texts.length})`,
1355
+ };
1356
+ }
1357
+ const { getAnnRouterRegistry } = await import('../memory/ann-router-registry.js');
1358
+ const registry = getAnnRouterRegistry();
1359
+ // Stage 1 — embed all queries in parallel.
1360
+ const embedT0 = Date.now();
1361
+ let embeddings;
1362
+ try {
1363
+ embeddings = await Promise.all(texts.map(t => generateRealEmbedding(t, config.dimension)));
1364
+ }
1365
+ catch (err) {
1366
+ return { success: false, name, error: `batch embed failed: ${err instanceof Error ? err.message : String(err)}` };
1367
+ }
1368
+ const embeddingMs = Date.now() - embedT0;
1369
+ // Stage 2 — search each variant in parallel. Per-query errors
1370
+ // become empty result lists (the variant just doesn't contribute
1371
+ // to the fusion) rather than aborting the ensemble.
1372
+ const searchT0 = Date.now();
1373
+ const perQueryResults = await Promise.all(embeddings.map(async (emb, i) => {
1374
+ try {
1375
+ const hits = await registry.search(name, new Float32Array(emb), perQueryK);
1376
+ return { index: i, text: texts[i], hits, success: true };
1377
+ }
1378
+ catch (err) {
1379
+ return {
1380
+ index: i,
1381
+ text: texts[i],
1382
+ hits: [],
1383
+ success: false,
1384
+ error: err instanceof Error ? err.message : String(err),
1385
+ };
1386
+ }
1387
+ }));
1388
+ const searchMs = Date.now() - searchT0;
1389
+ // Stage 3 — RRF fusion across the per-query lists.
1390
+ const { reciprocalRankFusion } = await import('@claude-flow/embeddings/rrf');
1391
+ const fuseT0 = Date.now();
1392
+ const lists = perQueryResults.map(r => r.hits.map(h => ({ id: h.id, payload: { score: h.score } })));
1393
+ const fused = reciprocalRankFusion(lists, { k, kRrf, listWeights });
1394
+ const fuseMs = Date.now() - fuseT0;
1395
+ const successCount = perQueryResults.filter(r => r.success).length;
1396
+ return {
1397
+ success: successCount === perQueryResults.length,
1398
+ name,
1399
+ k,
1400
+ queryCount: texts.length,
1401
+ perQueryK,
1402
+ kRrf,
1403
+ listWeights: listWeights ?? null,
1404
+ successCount,
1405
+ failureCount: perQueryResults.length - successCount,
1406
+ hits: fused,
1407
+ perQuery: perQueryResults.map(r => ({
1408
+ index: r.index,
1409
+ text: r.text,
1410
+ success: r.success,
1411
+ hitCount: r.hits.length,
1412
+ error: r.success ? undefined : r.error,
1413
+ })),
1414
+ latency: {
1415
+ embeddingMs,
1416
+ searchMs,
1417
+ fuseMs,
1418
+ totalMs: embeddingMs + searchMs + fuseMs,
1419
+ avgPerQueryMs: Math.round(((embeddingMs + searchMs) / texts.length) * 100) / 100,
1420
+ },
1421
+ embeddingDimension: embeddings[0]?.length,
1422
+ };
1423
+ },
1424
+ },
1425
+ // ============================================================
1283
1426
  // ADR-121 Phase 10 — MMR diversity rerank (alpha.51 CLI)
1284
1427
  // ============================================================
1285
1428
  //
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.7.0-alpha.51",
3
+ "version": "3.7.0-alpha.52",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",
@@ -104,14 +104,14 @@
104
104
  "semver": "^7.6.0",
105
105
  "yaml": "^2.8.0",
106
106
  "@claude-flow/memory": "^3.0.0-alpha.17",
107
- "@claude-flow/embeddings": "^3.0.0-alpha.31",
107
+ "@claude-flow/embeddings": "^3.0.0-alpha.32",
108
108
  "@claude-flow/security": "^3.0.0-alpha.8",
109
109
  "@claude-flow/swarm": "^3.0.0-alpha.8"
110
110
  },
111
111
  "optionalDependencies": {
112
112
  "@claude-flow/aidefence": "^3.0.2",
113
113
  "@claude-flow/codex": "^3.0.0-alpha.8",
114
- "@claude-flow/embeddings": "^3.0.0-alpha.31",
114
+ "@claude-flow/embeddings": "^3.0.0-alpha.32",
115
115
  "@claude-flow/guidance": "^3.0.0-alpha.1",
116
116
  "@claude-flow/memory": "^3.0.0-alpha.17",
117
117
  "@claude-flow/plugin-gastown-bridge": "^0.1.3",