@claude-flow/cli 3.18.2 → 3.20.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/dist/src/commands/neural.d.ts.map +1 -1
- package/dist/src/commands/neural.js +109 -14
- package/dist/src/commands/neural.js.map +1 -1
- package/dist/src/mcp-tools/agenticow-tools.d.ts.map +1 -1
- package/dist/src/mcp-tools/agenticow-tools.js +182 -2
- package/dist/src/mcp-tools/agenticow-tools.js.map +1 -1
- package/dist/src/ruvector/index.d.ts +1 -1
- package/dist/src/ruvector/index.d.ts.map +1 -1
- package/dist/src/ruvector/index.js +1 -1
- package/dist/src/ruvector/index.js.map +1 -1
- package/dist/src/ruvector/lora-adapter.d.ts +35 -0
- package/dist/src/ruvector/lora-adapter.d.ts.map +1 -1
- package/dist/src/ruvector/lora-adapter.js +108 -1
- package/dist/src/ruvector/lora-adapter.js.map +1 -1
- package/dist/src/services/native-training.d.ts +68 -0
- package/dist/src/services/native-training.d.ts.map +1 -0
- package/dist/src/services/native-training.js +141 -0
- package/dist/src/services/native-training.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neural.d.ts","sourceRoot":"","sources":["../../../src/commands/neural.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"neural.d.ts","sourceRoot":"","sources":["../../../src/commands/neural.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAiC,MAAM,aAAa,CAAC;AA0wI1E,eAAO,MAAM,aAAa,EAAE,OAmB3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -23,6 +23,9 @@ const trainCommand = {
|
|
|
23
23
|
{ name: 'hyperbolic', type: 'boolean', description: 'Enable hyperbolic attention for hierarchical patterns', default: 'false' },
|
|
24
24
|
{ name: 'contrastive', type: 'boolean', description: 'Use contrastive learning (InfoNCE)', default: 'true' },
|
|
25
25
|
{ name: 'curriculum', type: 'boolean', description: 'Enable curriculum learning', default: 'false' },
|
|
26
|
+
{ name: 'backend', type: 'string', description: 'Training backend: auto (native when available), native (@ruvector/ruvllm TrainingPipeline, disk checkpoints), wasm (RuVector MicroLoRA/InfoNCE)', default: 'auto' },
|
|
27
|
+
{ name: 'val-split', type: 'number', description: 'Validation holdout fraction 0..1 (native backend). >0 reports Best Val Loss + early stopping; 0 disables', default: '0.1' },
|
|
28
|
+
{ name: 'resume', type: 'string', description: 'Resume native training from a checkpoint path (weights on 2.5.7; epoch position on >=2.6.0). Native backend only', default: '' },
|
|
26
29
|
],
|
|
27
30
|
examples: [
|
|
28
31
|
{ command: 'claude-flow neural train -p coordination -e 100', description: 'Train coordination patterns' },
|
|
@@ -35,6 +38,22 @@ const trainCommand = {
|
|
|
35
38
|
const learningRate = parseFloat(ctx.flags['learning-rate'] || '0.01');
|
|
36
39
|
const batchSize = parseInt(ctx.flags['batch-size'] || '32', 10);
|
|
37
40
|
const dim = Math.min(parseInt(ctx.flags.dim || '256', 10), 256);
|
|
41
|
+
// #2549 follow-up — backend routing: 'native' = @ruvector/ruvllm
|
|
42
|
+
// TrainingPipeline (real epochs/early-stopping/disk checkpoints),
|
|
43
|
+
// 'wasm' = RuVector MicroLoRA/InfoNCE (pre-3.19 behavior),
|
|
44
|
+
// 'auto' = native when the module resolves, else wasm.
|
|
45
|
+
const backendFlag = String(ctx.flags.backend || 'auto');
|
|
46
|
+
// Feature: validation split + resume (native TrainingPipeline leg).
|
|
47
|
+
const valSplitRaw = parseFloat(ctx.flags['val-split'] ?? '0.1');
|
|
48
|
+
const valSplit = Number.isFinite(valSplitRaw) ? Math.max(0, Math.min(1, valSplitRaw)) : 0.1;
|
|
49
|
+
const resumePath = ctx.flags.resume ? String(ctx.flags.resume) : undefined;
|
|
50
|
+
// --resume is a native-only capability; refuse the WASM combination up
|
|
51
|
+
// front so the user gets a clear error rather than a silently-ignored flag.
|
|
52
|
+
if (resumePath && backendFlag === 'wasm') {
|
|
53
|
+
output.writeln();
|
|
54
|
+
output.writeln(output.error('--resume is only supported by the native backend; drop --backend wasm.'));
|
|
55
|
+
return { success: false, exitCode: 1 };
|
|
56
|
+
}
|
|
38
57
|
const useWasm = ctx.flags.wasm !== false;
|
|
39
58
|
const useFlash = ctx.flags.flash !== false;
|
|
40
59
|
const useMoE = ctx.flags.moe === true;
|
|
@@ -181,6 +200,50 @@ const trainCommand = {
|
|
|
181
200
|
}
|
|
182
201
|
}
|
|
183
202
|
spinner.setText(`Training with ${embeddings.length} embeddings...`);
|
|
203
|
+
// #2549 — native TrainingPipeline leg. In 'auto'/'native' mode the
|
|
204
|
+
// LoRA training runs through @ruvector/ruvllm with the checkpoint
|
|
205
|
+
// taken from the TRAINED pipeline (the old best-effort block saved
|
|
206
|
+
// a fresh adapter's untrained weights). SONA/ReasoningBank
|
|
207
|
+
// persistence in the loop below runs regardless of backend.
|
|
208
|
+
const nativeTraining = await import('../services/native-training.js');
|
|
209
|
+
const useNative = backendFlag === 'native'
|
|
210
|
+
|| (backendFlag === 'auto' && nativeTraining.nativeTrainingAvailable());
|
|
211
|
+
// --resume only works on the native pipeline; if native is unavailable
|
|
212
|
+
// (module absent), fail loudly rather than silently fresh-train.
|
|
213
|
+
if (resumePath && !useNative) {
|
|
214
|
+
spinner.fail('--resume requires the native @ruvector/ruvllm backend, which is not available');
|
|
215
|
+
return { success: false, exitCode: 1 };
|
|
216
|
+
}
|
|
217
|
+
let nativeResult = null;
|
|
218
|
+
if (useNative) {
|
|
219
|
+
spinner.setText(`Training ${patternType} on native @ruvector/ruvllm pipeline...`);
|
|
220
|
+
const path = await import('path');
|
|
221
|
+
try {
|
|
222
|
+
nativeResult = await nativeTraining.runNativeTraining({
|
|
223
|
+
embeddings,
|
|
224
|
+
epochs,
|
|
225
|
+
batchSize,
|
|
226
|
+
learningRate,
|
|
227
|
+
dim,
|
|
228
|
+
validationSplit: valSplit,
|
|
229
|
+
resumeFrom: resumePath,
|
|
230
|
+
checkpointPath: path.join(process.cwd(), '.claude-flow', 'neural', `lora-checkpoint-${Date.now()}.json`),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
// ResumeFailedError — an explicit --resume that could not load is a
|
|
235
|
+
// loud, exit-1 failure, never a silent fall-through to fresh training.
|
|
236
|
+
spinner.fail(`Resume failed: ${err.message}`);
|
|
237
|
+
return { success: false, exitCode: 1 };
|
|
238
|
+
}
|
|
239
|
+
if (!nativeResult && backendFlag === 'native') {
|
|
240
|
+
spinner.fail('Native backend requested (--backend native) but @ruvector/ruvllm training failed');
|
|
241
|
+
return { success: false, exitCode: 1 };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Native handles the LoRA leg; WASM contrastive runs when native
|
|
245
|
+
// didn't (absent module, or explicit --backend wasm).
|
|
246
|
+
const runWasmLeg = !nativeResult;
|
|
184
247
|
// Main training loop with WASM acceleration
|
|
185
248
|
for (let epoch = 0; epoch < epochs; epoch++) {
|
|
186
249
|
const epochStart = performance.now();
|
|
@@ -192,7 +255,7 @@ const trainCommand = {
|
|
|
192
255
|
if (batch.length === 0)
|
|
193
256
|
continue;
|
|
194
257
|
// Training step with contrastive learning
|
|
195
|
-
if (useContrastive && batch.length >= 3 && useWasm && wasmFeatures.length > 0) {
|
|
258
|
+
if (runWasmLeg && useContrastive && batch.length >= 3 && useWasm && wasmFeatures.length > 0) {
|
|
196
259
|
const anchor = batch[0];
|
|
197
260
|
const positives = [batch[1]];
|
|
198
261
|
const negatives = batch.slice(2);
|
|
@@ -260,17 +323,22 @@ const trainCommand = {
|
|
|
260
323
|
// Flush patterns to disk
|
|
261
324
|
flushPatterns();
|
|
262
325
|
const persistence = getPersistenceStatus();
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
326
|
+
// Checkpoint: when the native pipeline trained, its checkpoint (the
|
|
327
|
+
// TRAINED weights) was already written by runNativeTraining. The
|
|
328
|
+
// pre-3.19 fallback below saved a FRESH adapter's weights — only
|
|
329
|
+
// meaningful as a fallback when the native leg didn't run.
|
|
330
|
+
if (!nativeResult?.checkpointPath) {
|
|
331
|
+
try {
|
|
332
|
+
const { LoRAAdapter } = await import('../ruvector/lora-adapter.js');
|
|
333
|
+
const path = await import('path');
|
|
334
|
+
const cpDir = path.join(process.cwd(), '.claude-flow', 'neural');
|
|
335
|
+
const cpPath = path.join(cpDir, `lora-checkpoint-${Date.now()}.json`);
|
|
336
|
+
const adapter = new LoRAAdapter({ inputDim: dim, outputDim: dim, rank: 4 });
|
|
337
|
+
await adapter.initBackend();
|
|
338
|
+
await adapter.saveCheckpoint(cpPath);
|
|
339
|
+
}
|
|
340
|
+
catch { /* checkpoint save is best-effort */ }
|
|
272
341
|
}
|
|
273
|
-
catch { /* checkpoint save is best-effort */ }
|
|
274
342
|
output.writeln();
|
|
275
343
|
// Display results
|
|
276
344
|
const tableData = [
|
|
@@ -284,8 +352,31 @@ const trainCommand = {
|
|
|
284
352
|
{ metric: 'Total Time', value: `${(totalTime / 1000).toFixed(1)}s` },
|
|
285
353
|
{ metric: 'Avg Epoch Time', value: `${(epochTimes.reduce((a, b) => a + b, 0) / epochTimes.length).toFixed(2)}ms` },
|
|
286
354
|
];
|
|
355
|
+
// Native pipeline metrics (#2549 — the LoRA leg trained on ruvllm)
|
|
356
|
+
if (nativeResult) {
|
|
357
|
+
tableData.push({ metric: 'Backend', value: 'native (@ruvector/ruvllm TrainingPipeline)' }, { metric: 'Native Steps', value: String(nativeResult.steps) }, { metric: 'Final Loss', value: nativeResult.finalLoss.toExponential(3) });
|
|
358
|
+
// Validation metrics only surface when a holdout actually ran
|
|
359
|
+
// (bestValLoss is non-null); Early Stopped is only meaningful then.
|
|
360
|
+
if (nativeResult.bestValLoss !== null && nativeResult.bestValLoss !== undefined) {
|
|
361
|
+
tableData.push({ metric: 'Best Val Loss', value: nativeResult.bestValLoss.toExponential(3) }, { metric: 'Early Stopped', value: nativeResult.earlyStopped ? 'yes' : 'no' });
|
|
362
|
+
}
|
|
363
|
+
if (nativeResult.resumed) {
|
|
364
|
+
tableData.push({
|
|
365
|
+
metric: 'Resumed',
|
|
366
|
+
value: nativeResult.resumeMode === 'resumeFrom'
|
|
367
|
+
? `${resumePath} (epoch position restored)`
|
|
368
|
+
: `${resumePath} (weights only — epoch-position resume needs @ruvector/ruvllm >=2.6.0)`,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
if (nativeResult.checkpointPath) {
|
|
372
|
+
tableData.push({
|
|
373
|
+
metric: 'Checkpoint',
|
|
374
|
+
value: `${nativeResult.checkpointPath}${nativeResult.checkpointBytes ? ` (${(nativeResult.checkpointBytes / 1024).toFixed(1)} KB)` : ''}`,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
287
378
|
// Add WASM-specific metrics
|
|
288
|
-
if (useWasm && wasmFeatures.length > 0) {
|
|
379
|
+
if (runWasmLeg && useWasm && wasmFeatures.length > 0) {
|
|
289
380
|
const backendUsed = ruvectorStats?.backend || 'unknown';
|
|
290
381
|
tableData.push({ metric: 'Backend', value: backendUsed === 'wasm' ? 'WASM (native)' : 'JS (fallback)' }, { metric: 'WASM Features', value: wasmFeatures.slice(0, 3).join(', ') }, { metric: 'LoRA Adaptations', value: String(adaptations) }, { metric: 'Avg Loss', value: (totalLoss / Math.max(1, epochs)).toFixed(4) });
|
|
291
382
|
if (ruvectorStats?.microLoraStats) {
|
|
@@ -474,10 +565,14 @@ const statusCommand = {
|
|
|
474
565
|
details: stats._trainingBackend === 'ruvllm'
|
|
475
566
|
? await (async () => {
|
|
476
567
|
try {
|
|
477
|
-
const { nativeCheckpointsSupported } = await import('../ruvector/lora-adapter.js');
|
|
478
|
-
|
|
568
|
+
const { nativeCheckpointsSupported, latestCheckpointInfo } = await import('../ruvector/lora-adapter.js');
|
|
569
|
+
// Most important info first (truncation-friendly): backend
|
|
570
|
+
// capability, then the newest checkpoint + age when one exists.
|
|
571
|
+
const base = nativeCheckpointsSupported()
|
|
479
572
|
? 'native @ruvector/ruvllm pipeline + disk checkpoints'
|
|
480
573
|
: 'native @ruvector/ruvllm pipeline (checkpoints need >=2.5.7)';
|
|
574
|
+
const cp = latestCheckpointInfo();
|
|
575
|
+
return cp ? `${base} · latest: ${cp.filename} (${cp.ageLabel})` : base;
|
|
481
576
|
}
|
|
482
577
|
catch {
|
|
483
578
|
return 'native @ruvector/ruvllm pipeline';
|