claude-flow 3.5.72 → 3.5.74

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.5.72",
3
+ "version": "3.5.74",
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",
@@ -260,6 +260,17 @@ const trainCommand = {
260
260
  // Flush patterns to disk
261
261
  flushPatterns();
262
262
  const persistence = getPersistenceStatus();
263
+ // Save LoRA checkpoint via ruvllm TrainingPipeline if available
264
+ try {
265
+ const { LoRAAdapter } = await import('../ruvector/lora-adapter.js');
266
+ const path = await import('path');
267
+ const cpDir = path.join(process.cwd(), '.claude-flow', 'neural');
268
+ const cpPath = path.join(cpDir, `lora-checkpoint-${Date.now()}.json`);
269
+ const adapter = new LoRAAdapter({ inputDim: dim, outputDim: dim, rank: 4 });
270
+ await adapter.initBackend();
271
+ await adapter.saveCheckpoint(cpPath);
272
+ }
273
+ catch { /* checkpoint save is best-effort */ }
263
274
  output.writeln();
264
275
  // Display results
265
276
  const tableData = [
@@ -421,6 +432,43 @@ const statusCommand = {
421
432
  status: output.success('Available'),
422
433
  details: '~4x memory reduction',
423
434
  },
435
+ {
436
+ component: 'ruvllm Coordinator',
437
+ status: stats._ruvllmBackend === 'active' ? output.success('Active') : output.dim('Unavailable'),
438
+ details: stats._ruvllmBackend === 'active'
439
+ ? `SonaCoordinator | ${stats._ruvllmTrajectories} trajectories`
440
+ : 'Install @ruvector/ruvllm',
441
+ },
442
+ {
443
+ component: 'Contrastive Trainer',
444
+ status: stats._contrastiveTrainer && stats._contrastiveTrainer !== 'unavailable' ? output.success('Active') : output.dim('Unavailable'),
445
+ details: stats._contrastiveTrainer && stats._contrastiveTrainer !== 'unavailable'
446
+ ? `${stats._contrastiveTrainer.triplets ?? 0} triplets, ${stats._contrastiveTrainer.agents ?? 0} agents`
447
+ : 'Install @ruvector/ruvllm',
448
+ },
449
+ {
450
+ component: 'Training Pipeline',
451
+ status: stats._trainingBackend === 'ruvllm' ? output.success('Active') : output.dim(stats._trainingBackend || 'Unavailable'),
452
+ details: stats._trainingBackend === 'ruvllm'
453
+ ? 'ruvllm checkpoints enabled'
454
+ : 'JS fallback (no checkpoints)',
455
+ },
456
+ await (async () => {
457
+ try {
458
+ const { getGraphStats } = await import('../ruvector/graph-backend.js');
459
+ const gs = await getGraphStats();
460
+ return {
461
+ component: 'Graph Database',
462
+ status: gs.backend === 'graph-node' ? output.success('Active') : output.dim('Unavailable'),
463
+ details: gs.backend === 'graph-node'
464
+ ? `${gs.totalNodes} nodes, ${gs.totalEdges} edges`
465
+ : 'Install @ruvector/graph-node',
466
+ };
467
+ }
468
+ catch {
469
+ return { component: 'Graph Database', status: output.dim('Unavailable'), details: 'Not loaded' };
470
+ }
471
+ })(),
424
472
  ],
425
473
  });
426
474
  if (verbose) {
@@ -678,6 +726,12 @@ const optimizeCommand = {
678
726
  await initializeIntelligence();
679
727
  const patterns = await getAllPatterns();
680
728
  const stats = getIntelligenceStats();
729
+ // Trigger ruvllm background learning if available
730
+ try {
731
+ const { runBackgroundLearning } = await import('../memory/intelligence.js');
732
+ await runBackgroundLearning();
733
+ }
734
+ catch { /* background learning is best-effort */ }
681
735
  // Get actual pattern storage size
682
736
  const patternDir = path.join(process.cwd(), '.claude-flow', 'neural');
683
737
  let beforeSize = 0;
@@ -52,9 +52,8 @@ function concurrencyRules() {
52
52
  return `## Concurrency: 1 MESSAGE = ALL RELATED OPERATIONS
53
53
 
54
54
  - All operations MUST be concurrent/parallel in a single message
55
- - Use Claude Code's Task tool for spawning agents, not just MCP
56
- - ALWAYS batch ALL todos in ONE TodoWrite call (5-10+ minimum)
57
- - ALWAYS spawn ALL agents in ONE message with full instructions via Task tool
55
+ - Use Claude Code's Agent tool for spawning agents, not just MCP
56
+ - ALWAYS spawn ALL agents in ONE message with full instructions via Agent tool
58
57
  - ALWAYS batch ALL file reads/writes/edits in ONE message
59
58
  - ALWAYS batch ALL Bash commands in ONE message`;
60
59
  }
@@ -62,9 +61,9 @@ function swarmOrchestration() {
62
61
  return `## Swarm Orchestration
63
62
 
64
63
  - MUST initialize the swarm using CLI tools when starting complex tasks
65
- - MUST spawn concurrent agents using Claude Code's Task tool
66
- - Never use CLI tools alone for execution — Task tool agents do the actual work
67
- - MUST call CLI tools AND Task tool in ONE message for complex work
64
+ - MUST spawn concurrent agents using Claude Code's Agent tool
65
+ - Never use CLI tools alone for execution — Agent tool agents do the actual work
66
+ - MUST call CLI tools AND Agent tool in ONE message for complex work
68
67
 
69
68
  ### 3-Tier Model Routing (ADR-026)
70
69
 
@@ -74,8 +73,7 @@ function swarmOrchestration() {
74
73
  | **2** | Haiku | ~500ms | $0.0002 | Simple tasks, low complexity (<30%) |
75
74
  | **3** | Sonnet/Opus | 2-5s | $0.003-0.015 | Complex reasoning, architecture, security (>30%) |
76
75
 
77
- - Always check for \`[AGENT_BOOSTER_AVAILABLE]\` or \`[TASK_MODEL_RECOMMENDATION]\` before spawning agents
78
- - Use Edit tool directly when \`[AGENT_BOOSTER_AVAILABLE]\``;
76
+ - For Tier 1 simple transforms, use Edit tool directly — no LLM agent needed`;
79
77
  }
80
78
  function antiDriftConfig() {
81
79
  return `## Swarm Configuration & Anti-Drift
@@ -103,11 +101,11 @@ When the user requests a complex task, spawn agents in background and WAIT:
103
101
  Bash("npx @claude-flow/cli@latest swarm init --topology hierarchical --max-agents 8 --strategy specialized")
104
102
 
105
103
  // STEP 2: Spawn ALL agents IN BACKGROUND in a SINGLE message
106
- Task({prompt: "Research requirements...", subagent_type: "researcher", run_in_background: true})
107
- Task({prompt: "Design architecture...", subagent_type: "system-architect", run_in_background: true})
108
- Task({prompt: "Implement solution...", subagent_type: "coder", run_in_background: true})
109
- Task({prompt: "Write tests...", subagent_type: "tester", run_in_background: true})
110
- Task({prompt: "Review code quality...", subagent_type: "reviewer", run_in_background: true})
104
+ Agent("Research requirements", "Analyze codebase patterns and store findings in memory", {subagent_type: "researcher", run_in_background: true})
105
+ Agent("Design architecture", "Design architecture based on research", {subagent_type: "system-architect", run_in_background: true})
106
+ Agent("Implement solution", "Implement the solution following the design", {subagent_type: "coder", run_in_background: true})
107
+ Agent("Write tests", "Write comprehensive tests for the implementation", {subagent_type: "tester", run_in_background: true})
108
+ Agent("Review code quality", "Review code quality, security, and best practices", {subagent_type: "reviewer", run_in_background: true})
111
109
  \`\`\`
112
110
 
113
111
  ### Agent Routing
@@ -128,10 +126,10 @@ Task({prompt: "Review code quality...", subagent_type: "reviewer", run_in_backgr
128
126
  function executionRules() {
129
127
  return `## Swarm Execution Rules
130
128
 
131
- - ALWAYS use \`run_in_background: true\` for all agent Task calls
132
- - ALWAYS put ALL agent Task calls in ONE message for parallel execution
129
+ - ALWAYS use \`run_in_background: true\` for all Agent tool calls
130
+ - ALWAYS put ALL Agent calls in ONE message for parallel execution
133
131
  - After spawning, STOP — do NOT add more tool calls or check status
134
- - Never poll TaskOutput or check swarm status — trust agents to return
132
+ - Never poll agent status repeatedly — trust agents to return
135
133
  - When agent results arrive, review ALL results before proceeding`;
136
134
  }
137
135
  function cliCommandsTable() {
@@ -407,7 +405,7 @@ npx @claude-flow/cli@latest doctor --fix
407
405
 
408
406
  ## Claude Code vs MCP Tools
409
407
 
410
- - **Claude Code Task tool** handles execution: agents, file ops, code generation, git
408
+ - **Claude Code Agent tool** handles execution: agents, file ops, code generation, git
411
409
  - **MCP tools** (via ToolSearch) handle coordination: swarm, memory, hooks, routing, hive-mind
412
410
  - **CLI commands** (via Bash) are the same tools with terminal output
413
411
  - Use \`ToolSearch("keyword")\` to discover available MCP tools
@@ -184,6 +184,12 @@ export const agentTools = [
184
184
  };
185
185
  store.agents[agentId] = agent;
186
186
  saveAgentStore(store);
187
+ // Record agent in graph database (ADR-087, best-effort)
188
+ try {
189
+ const { addNode } = await import('../ruvector/graph-backend.js');
190
+ await addNode({ id: agentId, type: 'agent', name: agentType });
191
+ }
192
+ catch { /* graph-node not available */ }
187
193
  // Include Agent Booster routing info if applicable
188
194
  const response = {
189
195
  success: true,
@@ -243,6 +243,20 @@ export const agentdbCausalEdge = {
243
243
  return { success: false, error: 'targetId is required (non-empty string)' };
244
244
  if (!relation)
245
245
  return { success: false, error: 'relation is required (non-empty string)' };
246
+ // Try native graph-node backend first (ADR-087)
247
+ try {
248
+ const graphBackend = await import('../ruvector/graph-backend.js');
249
+ if (await graphBackend.isGraphBackendAvailable()) {
250
+ const graphResult = await graphBackend.recordCausalEdge(sourceId, targetId, relation, typeof params.weight === 'number' ? validateScore(params.weight, 0.5) : undefined);
251
+ if (graphResult.success) {
252
+ // Also record in AgentDB bridge for compatibility
253
+ const bridge = await getBridge();
254
+ await bridge.bridgeRecordCausalEdge({ sourceId, targetId, relation, weight: typeof params.weight === 'number' ? validateScore(params.weight, 0.5) : undefined }).catch(() => { });
255
+ return { ...graphResult, _graphNodeBackend: true };
256
+ }
257
+ }
258
+ }
259
+ catch { /* graph-node not available, fall through */ }
246
260
  const bridge = await getBridge();
247
261
  const result = await bridge.bridgeRecordCausalEdge({
248
262
  sourceId,
@@ -291,6 +291,7 @@ async function getSemanticRouter() {
291
291
  }
292
292
  nativeVectorDb = db;
293
293
  routerBackend = 'native';
294
+ console.log('[hooks] Semantic router initialized: native VectorDb (HNSW, 16k+ routes/s)');
294
295
  return { router: null, backend: routerBackend, native: nativeVectorDb };
295
296
  }
296
297
  }
@@ -312,10 +313,12 @@ async function getSemanticRouter() {
312
313
  });
313
314
  }
314
315
  routerBackend = 'pure-js';
316
+ console.log('[hooks] Semantic router initialized: pure JS (cosine, 47k routes/s)');
315
317
  }
316
318
  catch {
317
319
  semanticRouter = null;
318
320
  routerBackend = 'none';
321
+ console.log('[hooks] Semantic router initialized: none (no backend available)');
319
322
  }
320
323
  return { router: semanticRouter, backend: routerBackend, native: nativeVectorDb };
321
324
  }
@@ -2030,6 +2033,46 @@ export const hooksIntelligence = {
2030
2033
  implemented: true,
2031
2034
  note: 'Real ONNX embeddings via Xenova/all-MiniLM-L6-v2',
2032
2035
  },
2036
+ ruvllmCoordinator: await (async () => {
2037
+ try {
2038
+ const { getIntelligenceStats } = await import('../memory/intelligence.js');
2039
+ const s = getIntelligenceStats();
2040
+ return { status: s._ruvllmBackend || 'unavailable', trajectories: s._ruvllmTrajectories || 0, note: s._ruvllmBackend === 'active' ? 'SonaCoordinator forwarding trajectories' : '@ruvector/ruvllm not loaded' };
2041
+ }
2042
+ catch {
2043
+ return { status: 'unavailable', trajectories: 0, note: 'Not initialized' };
2044
+ }
2045
+ })(),
2046
+ contrastiveTrainer: await (async () => {
2047
+ try {
2048
+ const { getSONAStats } = await import('../memory/sona-optimizer.js');
2049
+ const s = await getSONAStats();
2050
+ return { status: s._contrastiveTrainer !== 'unavailable' ? 'active' : 'unavailable', details: s._contrastiveTrainer, note: s._contrastiveTrainer !== 'unavailable' ? 'Agent embedding learning active' : '@ruvector/ruvllm not loaded' };
2051
+ }
2052
+ catch {
2053
+ return { status: 'unavailable', details: null, note: 'Not initialized' };
2054
+ }
2055
+ })(),
2056
+ trainingPipeline: await (async () => {
2057
+ try {
2058
+ const loraInst = await getLoRAAdapter();
2059
+ const s = loraInst?.getStats();
2060
+ return { status: s?._trainingBackend || 'unavailable', note: s?._trainingBackend === 'ruvllm' ? 'Checkpoint save/load via ruvllm' : 'JS fallback' };
2061
+ }
2062
+ catch {
2063
+ return { status: 'unavailable', note: 'Not initialized' };
2064
+ }
2065
+ })(),
2066
+ graphDatabase: await (async () => {
2067
+ try {
2068
+ const { getGraphStats } = await import('../ruvector/graph-backend.js');
2069
+ const gs = await getGraphStats();
2070
+ return { status: gs.backend, totalNodes: gs.totalNodes, totalEdges: gs.totalEdges, avgDegree: gs.avgDegree, note: gs.backend === 'graph-node' ? 'Native Rust graph with hyperedges and k-hop queries' : '@ruvector/graph-node not loaded' };
2071
+ }
2072
+ catch {
2073
+ return { status: 'unavailable', totalNodes: 0, totalEdges: 0, avgDegree: 0, note: 'Not initialized' };
2074
+ }
2075
+ })(),
2033
2076
  },
2034
2077
  realMetrics: {
2035
2078
  trajectories: realStats.trajectories,
@@ -2041,7 +2084,7 @@ export const hooksIntelligence = {
2041
2084
  working: [
2042
2085
  'memory-store', 'embeddings', 'trajectory-recording', 'claims', 'swarm-coordination',
2043
2086
  'hnsw-index', 'pattern-storage', 'sona-optimizer', 'ewc-consolidation', 'moe-routing',
2044
- 'flash-attention', 'lora-adapter'
2087
+ 'flash-attention', 'lora-adapter', 'ruvllm-coordinator', 'contrastive-trainer', 'training-pipeline', 'graph-database'
2045
2088
  ],
2046
2089
  partial: [],
2047
2090
  notImplemented: [],
@@ -2304,6 +2347,12 @@ export const hooksTrajectoryEnd = {
2304
2347
  // SONA learning failed, continue without it
2305
2348
  }
2306
2349
  }
2350
+ // Trigger ruvllm background learning after trajectory end
2351
+ try {
2352
+ const { runBackgroundLearning } = await import('../memory/intelligence.js');
2353
+ await runBackgroundLearning();
2354
+ }
2355
+ catch { /* best-effort */ }
2307
2356
  // Try EWC++ consolidation on successful trajectories
2308
2357
  if (success) {
2309
2358
  const ewc = await getEWCConsolidator();
@@ -2668,12 +2717,38 @@ export const hooksIntelligenceStats = {
2668
2717
  implementation: 'real-lora',
2669
2718
  };
2670
2719
  }
2720
+ // ruvllm native backend stats
2721
+ let ruvllmStats = { coordinator: 'unavailable', trajectories: 0, contrastiveTrainer: 'unavailable', trainingBackend: 'unavailable', graphDatabase: { backend: 'unavailable', totalNodes: 0, totalEdges: 0 } };
2722
+ try {
2723
+ const { getIntelligenceStats } = await import('../memory/intelligence.js');
2724
+ const iStats = getIntelligenceStats();
2725
+ ruvllmStats.coordinator = iStats._ruvllmBackend || 'unavailable';
2726
+ ruvllmStats.trajectories = iStats._ruvllmTrajectories || 0;
2727
+ }
2728
+ catch { /* not initialized */ }
2729
+ try {
2730
+ const { getSONAStats: getSONA } = await import('../memory/sona-optimizer.js');
2731
+ const sStats = await getSONA();
2732
+ ruvllmStats.contrastiveTrainer = sStats._contrastiveTrainer || 'unavailable';
2733
+ }
2734
+ catch { /* not initialized */ }
2735
+ if (lora) {
2736
+ const ls = lora.getStats();
2737
+ ruvllmStats.trainingBackend = ls._trainingBackend || 'unavailable';
2738
+ }
2739
+ try {
2740
+ const { getGraphStats } = await import('../ruvector/graph-backend.js');
2741
+ const gs = await getGraphStats();
2742
+ ruvllmStats.graphDatabase = { backend: gs.backend, totalNodes: gs.totalNodes, totalEdges: gs.totalEdges, avgDegree: gs.avgDegree };
2743
+ }
2744
+ catch { /* not available */ }
2671
2745
  const stats = {
2672
2746
  sona: sonaStats,
2673
2747
  moe: moeStats,
2674
2748
  ewc: ewcStats,
2675
2749
  flash: flashStats,
2676
2750
  lora: loraStats,
2751
+ ruvllm: ruvllmStats,
2677
2752
  hnsw: {
2678
2753
  indexSize: memoryStats.memory.indexSize,
2679
2754
  avgSearchTimeMs: 0.12,
@@ -131,7 +131,11 @@ async function generateEmbedding(text, dims = 384) {
131
131
  }
132
132
  }
133
133
  // Hash-based deterministic embedding (better than pure random for consistency)
134
+ // NOTE: No semantic meaning — only useful for consistent deduplication, not similarity search
134
135
  if (text) {
136
+ if (embeddingServiceName === 'none') {
137
+ embeddingServiceName = 'hash-fallback';
138
+ }
135
139
  const hash = text.split('').reduce((acc, char, i) => {
136
140
  return acc + char.charCodeAt(0) * (i + 1);
137
141
  }, 0);
@@ -238,6 +242,7 @@ export const neuralTools = [
238
242
  return {
239
243
  success: true,
240
244
  _realEmbedding: !!realEmbeddings,
245
+ _embeddingSource: embeddingServiceName,
241
246
  embeddingProvider: embeddingServiceName,
242
247
  modelId,
243
248
  type: modelType,
@@ -307,6 +312,7 @@ export const neuralTools = [
307
312
  return {
308
313
  success: true,
309
314
  _realEmbedding: !!realEmbeddings,
315
+ _embeddingSource: embeddingServiceName,
310
316
  embeddingProvider: embeddingServiceName,
311
317
  _hasStoredPatterns: storedPatterns.length > 0,
312
318
  modelId: model?.id || 'default',
@@ -397,6 +403,7 @@ export const neuralTools = [
397
403
  return {
398
404
  success: true,
399
405
  _realEmbedding: !!realEmbeddings,
406
+ _embeddingSource: embeddingServiceName,
400
407
  embeddingProvider: embeddingServiceName,
401
408
  patternId,
402
409
  name: pattern.name,
@@ -420,6 +427,7 @@ export const neuralTools = [
420
427
  return {
421
428
  _realSimilarity: true,
422
429
  _realEmbedding: !!realEmbeddings,
430
+ _embeddingSource: embeddingServiceName,
423
431
  embeddingProvider: embeddingServiceName,
424
432
  query,
425
433
  results: results.map(r => ({
@@ -16,8 +16,32 @@ export const ruvllmWasmTools = [
16
16
  handler: async () => {
17
17
  try {
18
18
  const mod = await loadRuvllmWasm();
19
- const status = await mod.getRuvllmStatus();
20
- return { content: [{ type: 'text', text: JSON.stringify(status, null, 2) }] };
19
+ const wasmStatus = await mod.getRuvllmStatus();
20
+ // Also include native ruvllm CJS backend status (ADR-086)
21
+ let nativeBackend = { available: false };
22
+ try {
23
+ const { getIntelligenceStats } = await import('../memory/intelligence.js');
24
+ const iStats = getIntelligenceStats();
25
+ const { getSONAStats } = await import('../memory/sona-optimizer.js');
26
+ const sStats = await getSONAStats();
27
+ nativeBackend = {
28
+ available: iStats._ruvllmBackend === 'active',
29
+ coordinator: iStats._ruvllmBackend || 'unavailable',
30
+ trajectories: iStats._ruvllmTrajectories || 0,
31
+ contrastiveTrainer: sStats._contrastiveTrainer !== 'unavailable' ? 'active' : 'unavailable',
32
+ trainingBackend: iStats._trainingBackend || 'unknown',
33
+ };
34
+ }
35
+ catch { /* not initialized yet */ }
36
+ // Graph database status (ADR-087)
37
+ let graphStatus = { available: false };
38
+ try {
39
+ const { getGraphStats } = await import('../ruvector/graph-backend.js');
40
+ const gs = await getGraphStats();
41
+ graphStatus = { available: gs.backend === 'graph-node', ...gs };
42
+ }
43
+ catch { /* not loaded */ }
44
+ return { content: [{ type: 'text', text: JSON.stringify({ wasm: wasmStatus, native: nativeBackend, graph: graphStatus }, null, 2) }] };
21
45
  }
22
46
  catch (err) {
23
47
  return { content: [{ type: 'text', text: JSON.stringify({ error: String(err) }) }], isError: true };
@@ -250,7 +250,15 @@ export declare function findSimilarPatterns(query: string, options?: {
250
250
  /**
251
251
  * Get intelligence system statistics
252
252
  */
253
- export declare function getIntelligenceStats(): IntelligenceStats;
253
+ export declare function getIntelligenceStats(): IntelligenceStats & {
254
+ _ruvllmBackend: string;
255
+ _ruvllmTrajectories: number;
256
+ _contrastiveTrainer?: {
257
+ triplets: number;
258
+ agents: number;
259
+ } | string;
260
+ _trainingBackend?: string;
261
+ };
254
262
  /**
255
263
  * Get SONA coordinator for advanced operations
256
264
  */
@@ -329,6 +337,11 @@ export declare function clearAllPatterns(): Promise<void>;
329
337
  * Get the neural data directory path
330
338
  */
331
339
  export declare function getNeuralDataDir(): string;
340
+ /**
341
+ * Trigger background learning on the @ruvector/ruvllm SonaCoordinator.
342
+ * No-op if ruvllm is not installed.
343
+ */
344
+ export declare function runBackgroundLearning(): Promise<void>;
332
345
  /**
333
346
  * Get persistence status
334
347
  */
@@ -559,6 +559,26 @@ class LocalReasoningBank {
559
559
  }
560
560
  }
561
561
  // ============================================================================
562
+ // @ruvector/ruvllm SonaCoordinator Integration
563
+ // ============================================================================
564
+ let ruvllmCoordinator = null;
565
+ let ruvllmLoaded = false;
566
+ async function loadRuvllmCoordinator() {
567
+ if (ruvllmLoaded)
568
+ return ruvllmCoordinator;
569
+ ruvllmLoaded = true;
570
+ try {
571
+ const { createRequire } = await import('module');
572
+ const requireCjs = createRequire(import.meta.url);
573
+ const ruvllm = requireCjs('@ruvector/ruvllm');
574
+ ruvllmCoordinator = new ruvllm.SonaCoordinator(ruvllm.DEFAULT_SONA_CONFIG);
575
+ return ruvllmCoordinator;
576
+ }
577
+ catch {
578
+ return null;
579
+ }
580
+ }
581
+ // ============================================================================
562
582
  // Module State
563
583
  // ============================================================================
564
584
  let sonaCoordinator = null;
@@ -634,6 +654,8 @@ export async function initializeIntelligence(config) {
634
654
  });
635
655
  // Load persisted stats if available
636
656
  loadPersistedStats();
657
+ // Eagerly load ruvllm coordinator so stats reflect backend status
658
+ await loadRuvllmCoordinator();
637
659
  intelligenceInitialized = true;
638
660
  return {
639
661
  success: true,
@@ -773,6 +795,26 @@ export async function recordTrajectory(steps, verdict) {
773
795
  }
774
796
  }
775
797
  }
798
+ // Forward trajectory to @ruvector/ruvllm SonaCoordinator if available
799
+ const ruvllmCoord = await loadRuvllmCoordinator();
800
+ if (ruvllmCoord) {
801
+ try {
802
+ const avgQuality = verdict === 'success' ? 1.0 : verdict === 'partial' ? 0.5 : 0.0;
803
+ ruvllmCoord.recordTrajectory({
804
+ steps: enrichedSteps.map(s => ({
805
+ state: s.content,
806
+ action: s.type,
807
+ reward: avgQuality,
808
+ embedding: s.embedding || []
809
+ })),
810
+ totalReward: avgQuality,
811
+ success: verdict === 'success'
812
+ });
813
+ }
814
+ catch {
815
+ // ruvllm recording failed silently
816
+ }
817
+ }
776
818
  globalStats.trajectoriesRecorded++;
777
819
  globalStats.lastAdaptation = Date.now();
778
820
  savePersistedStats();
@@ -837,6 +879,19 @@ export async function findSimilarPatterns(query, options) {
837
879
  export function getIntelligenceStats() {
838
880
  const sonaStats = sonaCoordinator?.stats();
839
881
  const bankStats = reasoningBank?.stats();
882
+ const ruvllmStats = ruvllmCoordinator?.stats?.() || null;
883
+ // Fetch cross-module stats for unified reporting
884
+ let contrastiveTrainer = 'unavailable';
885
+ let trainingBackend = 'unavailable';
886
+ try {
887
+ // Synchronous check — contrastiveTrainer is module-level in sona-optimizer
888
+ // We read it via the SONAOptimizer singleton if available
889
+ const sonaModule = globalThis.__claudeFlowSonaStats;
890
+ if (sonaModule) {
891
+ contrastiveTrainer = sonaModule._contrastiveTrainer || 'unavailable';
892
+ }
893
+ }
894
+ catch { /* not available */ }
840
895
  return {
841
896
  sonaEnabled: !!sonaCoordinator,
842
897
  reasoningBankSize: bankStats?.size ?? 0,
@@ -844,7 +899,11 @@ export function getIntelligenceStats() {
844
899
  signalsProcessed: globalStats.signalsProcessed,
845
900
  trajectoriesRecorded: globalStats.trajectoriesRecorded,
846
901
  lastAdaptation: globalStats.lastAdaptation,
847
- avgAdaptationTime: sonaStats?.avgAdaptationMs ?? 0
902
+ avgAdaptationTime: sonaStats?.avgAdaptationMs ?? 0,
903
+ _ruvllmBackend: ruvllmStats ? 'active' : 'unavailable',
904
+ _ruvllmTrajectories: ruvllmStats?.trajectoriesBuffered || 0,
905
+ _contrastiveTrainer: contrastiveTrainer,
906
+ _trainingBackend: trainingBackend,
848
907
  };
849
908
  }
850
909
  /**
@@ -1088,6 +1147,15 @@ export async function clearAllPatterns() {
1088
1147
  export function getNeuralDataDir() {
1089
1148
  return getDataDir();
1090
1149
  }
1150
+ /**
1151
+ * Trigger background learning on the @ruvector/ruvllm SonaCoordinator.
1152
+ * No-op if ruvllm is not installed.
1153
+ */
1154
+ export async function runBackgroundLearning() {
1155
+ const coord = await loadRuvllmCoordinator();
1156
+ if (coord)
1157
+ coord.runBackgroundLoop();
1158
+ }
1091
1159
  /**
1092
1160
  * Get persistence status
1093
1161
  */
@@ -60,7 +60,7 @@ export interface RoutingSuggestion {
60
60
  /** Whether Q-learning was used */
61
61
  usedQLearning: boolean;
62
62
  /** Source of recommendation */
63
- source: 'sona-pattern' | 'q-learning' | 'keyword-match' | 'default';
63
+ source: 'sona-native' | 'sona-pattern' | 'q-learning' | 'sona-keyword' | 'default';
64
64
  /** Alternative agents with scores */
65
65
  alternatives: Array<{
66
66
  agent: string;
@@ -87,6 +87,11 @@ export interface SONAStats {
87
87
  qLearningEnabled: boolean;
88
88
  /** Time of last learning update */
89
89
  lastUpdate: number | null;
90
+ /** Contrastive trainer status (from @ruvector/ruvllm) */
91
+ _contrastiveTrainer?: {
92
+ triplets: number;
93
+ agents: number;
94
+ } | 'unavailable';
90
95
  }
91
96
  /**
92
97
  * SONA Optimizer for adaptive routing based on trajectory outcomes
@@ -103,9 +108,20 @@ export declare class SONAOptimizer {
103
108
  private persistencePath;
104
109
  private qLearningRouter;
105
110
  private qLearningEnabled;
111
+ /** Real @ruvector/sona engine — null if native not available, undefined if not yet tried */
112
+ private sonaEngine;
106
113
  constructor(options?: {
107
114
  persistencePath?: string;
108
115
  });
116
+ /**
117
+ * Attempt to load the native @ruvector/sona engine (once).
118
+ * Sets `sonaEngine` to the engine instance or null if unavailable.
119
+ */
120
+ private loadSonaEngine;
121
+ /**
122
+ * Infer an agent type string from a SONA pattern result object.
123
+ */
124
+ private inferAgentFromPattern;
109
125
  /**
110
126
  * Initialize the optimizer and load persisted state
111
127
  */
@@ -124,13 +140,31 @@ export declare class SONAOptimizer {
124
140
  keywordsExtracted: string[];
125
141
  };
126
142
  /**
127
- * Get routing suggestion based on learned patterns
143
+ * Get routing suggestion based on learned patterns.
144
+ *
145
+ * Priority order:
146
+ * 1. Real @ruvector/sona native engine (if available and has matches)
147
+ * 2. SONA learned pattern matching (keyword overlap + confidence)
148
+ * 3. Q-learning router (if enabled)
149
+ * 4. Keyword heuristic
150
+ * 5. Default fallback
128
151
  */
129
- getRoutingSuggestion(task: string): RoutingSuggestion;
152
+ getRoutingSuggestion(task: string): Promise<RoutingSuggestion>;
130
153
  /**
131
154
  * Get optimizer statistics
132
155
  */
133
156
  getStats(): SONAStats;
157
+ /**
158
+ * Trigger contrastive training on accumulated agent embeddings.
159
+ * Returns training metrics or { trained: false } if insufficient data.
160
+ *
161
+ * @param _epochs - reserved for future use (epochs are set at ContrastiveTrainer construction)
162
+ */
163
+ trainAgentEmbeddings(_epochs?: number): Promise<{
164
+ trained: boolean;
165
+ loss?: number;
166
+ triplets?: number;
167
+ }>;
134
168
  /**
135
169
  * Apply temporal decay to pattern confidence
136
170
  * Reduces confidence of unused patterns
@@ -148,6 +182,12 @@ export declare class SONAOptimizer {
148
182
  * Import patterns (for migration or testing)
149
183
  */
150
184
  importPatterns(patterns: Record<string, LearnedPattern>): number;
185
+ /**
186
+ * Convert extracted keywords into a lightweight 384-dim embedding proxy.
187
+ * Uses a deterministic hash-scatter so each keyword set maps to a
188
+ * consistent unit-length vector compatible with ContrastiveTrainer.
189
+ */
190
+ private keywordsToEmbedding;
151
191
  /**
152
192
  * Extract meaningful keywords from task description
153
193
  */