claude-flow 3.5.21 → 3.5.23
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/.claude/helpers/hook-handler.cjs +4 -2
- package/README.md +9 -7
- package/package.json +1 -1
- package/v3/@claude-flow/cli/README.md +9 -7
- package/v3/@claude-flow/cli/dist/src/commands/hooks.js +698 -55
- package/v3/@claude-flow/cli/dist/src/commands/init.js +3 -1
- package/v3/@claude-flow/cli/dist/src/commands/neural.js +11 -5
- package/v3/@claude-flow/cli/dist/src/index.d.ts +1 -1
- package/v3/@claude-flow/cli/dist/src/index.js +2 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/coordination-tools.js +191 -12
- package/v3/@claude-flow/cli/dist/src/mcp-tools/hive-mind-tools.js +224 -23
- package/v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +1 -0
- package/v3/@claude-flow/cli/dist/src/memory/ewc-consolidation.d.ts +24 -0
- package/v3/@claude-flow/cli/dist/src/memory/ewc-consolidation.js +59 -0
- package/v3/@claude-flow/cli/dist/src/memory/intelligence.d.ts +53 -0
- package/v3/@claude-flow/cli/dist/src/memory/intelligence.js +225 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.d.ts +7 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +27 -1
- package/v3/@claude-flow/cli/dist/src/ruvector/index.d.ts +4 -0
- package/v3/@claude-flow/cli/dist/src/ruvector/index.js +12 -0
- package/v3/@claude-flow/cli/dist/src/services/ruvector-training.d.ts +9 -1
- package/v3/@claude-flow/cli/dist/src/services/ruvector-training.js +223 -39
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.d.ts +4 -0
- package/v3/@claude-flow/cli/dist/src/services/worker-daemon.js +33 -5
- package/v3/@claude-flow/cli/package.json +1 -1
|
@@ -9,6 +9,78 @@ import { join } from 'node:path';
|
|
|
9
9
|
const STORAGE_DIR = '.claude-flow';
|
|
10
10
|
const HIVE_DIR = 'hive-mind';
|
|
11
11
|
const HIVE_FILE = 'state.json';
|
|
12
|
+
/**
|
|
13
|
+
* Calculate required votes for a given strategy and total node count.
|
|
14
|
+
*/
|
|
15
|
+
function calculateRequiredVotes(strategy, totalNodes, quorumPreset = 'majority') {
|
|
16
|
+
if (totalNodes <= 0)
|
|
17
|
+
return 1;
|
|
18
|
+
switch (strategy) {
|
|
19
|
+
case 'bft':
|
|
20
|
+
// BFT: requires 2/3 + 1 of total nodes
|
|
21
|
+
return Math.floor((totalNodes * 2) / 3) + 1;
|
|
22
|
+
case 'raft':
|
|
23
|
+
// Raft: simple majority
|
|
24
|
+
return Math.floor(totalNodes / 2) + 1;
|
|
25
|
+
case 'quorum':
|
|
26
|
+
switch (quorumPreset) {
|
|
27
|
+
case 'unanimous':
|
|
28
|
+
return totalNodes;
|
|
29
|
+
case 'supermajority':
|
|
30
|
+
return Math.floor((totalNodes * 2) / 3) + 1;
|
|
31
|
+
case 'majority':
|
|
32
|
+
default:
|
|
33
|
+
return Math.floor(totalNodes / 2) + 1;
|
|
34
|
+
}
|
|
35
|
+
default:
|
|
36
|
+
return Math.floor(totalNodes / 2) + 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Detect Byzantine behavior: a voter who has cast conflicting votes
|
|
41
|
+
* across proposals in the same round (same type, overlapping time).
|
|
42
|
+
* Here we check if the voter already voted differently on this proposal
|
|
43
|
+
* (which shouldn't happen if we block double-votes, so this checks
|
|
44
|
+
* cross-proposal conflicting votes for same type within the pending set).
|
|
45
|
+
*/
|
|
46
|
+
function detectByzantineVoters(pending, currentProposal, voterId, newVote) {
|
|
47
|
+
// Check if voter cast opposite votes on proposals of the same type
|
|
48
|
+
for (const p of pending) {
|
|
49
|
+
if (p.proposalId === currentProposal.proposalId)
|
|
50
|
+
continue;
|
|
51
|
+
if (p.type !== currentProposal.type)
|
|
52
|
+
continue;
|
|
53
|
+
if (voterId in p.votes && p.votes[voterId] !== newVote) {
|
|
54
|
+
return true; // Conflicting vote detected
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Try to resolve a proposal based on its strategy.
|
|
61
|
+
* Returns 'approved', 'rejected', or null if still pending.
|
|
62
|
+
*/
|
|
63
|
+
function tryResolveProposal(proposal, totalNodes) {
|
|
64
|
+
const votesFor = Object.values(proposal.votes).filter(v => v).length;
|
|
65
|
+
const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
|
|
66
|
+
const required = calculateRequiredVotes(proposal.strategy, totalNodes, proposal.quorumPreset);
|
|
67
|
+
if (votesFor >= required)
|
|
68
|
+
return 'approved';
|
|
69
|
+
if (votesAgainst >= required)
|
|
70
|
+
return 'rejected';
|
|
71
|
+
// For quorum with 'unanimous', also reject if any vote is against
|
|
72
|
+
if (proposal.strategy === 'quorum' && proposal.quorumPreset === 'unanimous' && votesAgainst > 0) {
|
|
73
|
+
return 'rejected';
|
|
74
|
+
}
|
|
75
|
+
// Check if it's impossible to reach quorum (remaining potential votes can't tip it)
|
|
76
|
+
const totalVotes = Object.keys(proposal.votes).length;
|
|
77
|
+
const remaining = totalNodes - totalVotes;
|
|
78
|
+
if (votesFor + remaining < required && votesAgainst + remaining < required) {
|
|
79
|
+
// Deadlock: neither side can win -- reject
|
|
80
|
+
return 'rejected';
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
12
84
|
function getHiveDir() {
|
|
13
85
|
return join(process.cwd(), STORAGE_DIR, HIVE_DIR);
|
|
14
86
|
}
|
|
@@ -300,7 +372,7 @@ export const hiveMindTools = [
|
|
|
300
372
|
},
|
|
301
373
|
{
|
|
302
374
|
name: 'hive-mind_consensus',
|
|
303
|
-
description: 'Propose or vote on consensus',
|
|
375
|
+
description: 'Propose or vote on consensus with BFT, Raft, or Quorum strategies',
|
|
304
376
|
category: 'hive-mind',
|
|
305
377
|
inputSchema: {
|
|
306
378
|
type: 'object',
|
|
@@ -311,14 +383,36 @@ export const hiveMindTools = [
|
|
|
311
383
|
value: { description: 'Proposal value (for propose)' },
|
|
312
384
|
vote: { type: 'boolean', description: 'Vote (true=for, false=against)' },
|
|
313
385
|
voterId: { type: 'string', description: 'Voter agent ID' },
|
|
386
|
+
strategy: { type: 'string', enum: ['bft', 'raft', 'quorum'], description: 'Consensus strategy (default: raft)' },
|
|
387
|
+
quorumPreset: { type: 'string', enum: ['unanimous', 'majority', 'supermajority'], description: 'Quorum threshold preset (for quorum strategy, default: majority)' },
|
|
388
|
+
term: { type: 'number', description: 'Term number (for raft strategy)' },
|
|
389
|
+
timeoutMs: { type: 'number', description: 'Timeout in ms for raft re-proposal (default: 30000)' },
|
|
314
390
|
},
|
|
315
391
|
required: ['action'],
|
|
316
392
|
},
|
|
317
393
|
handler: async (input) => {
|
|
318
394
|
const state = loadHiveState();
|
|
319
395
|
const action = input.action;
|
|
396
|
+
const strategy = input.strategy || 'raft';
|
|
397
|
+
const totalNodes = state.workers.length || 1;
|
|
320
398
|
if (action === 'propose') {
|
|
321
399
|
const proposalId = `proposal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
400
|
+
const quorumPreset = input.quorumPreset || 'majority';
|
|
401
|
+
const term = input.term || (state.queen?.term ?? 1);
|
|
402
|
+
const timeoutMs = input.timeoutMs || 30000;
|
|
403
|
+
// Raft: check if there's already a pending proposal for this term
|
|
404
|
+
if (strategy === 'raft') {
|
|
405
|
+
const existingTermProposal = state.consensus.pending.find(p => p.strategy === 'raft' && p.term === term && p.status === 'pending');
|
|
406
|
+
if (existingTermProposal) {
|
|
407
|
+
return {
|
|
408
|
+
action,
|
|
409
|
+
error: `Raft term ${term} already has a pending proposal: ${existingTermProposal.proposalId}. Wait for resolution or use a higher term.`,
|
|
410
|
+
existingProposalId: existingTermProposal.proposalId,
|
|
411
|
+
term,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const required = calculateRequiredVotes(strategy, totalNodes, quorumPreset);
|
|
322
416
|
const proposal = {
|
|
323
417
|
proposalId,
|
|
324
418
|
type: input.type || 'general',
|
|
@@ -327,6 +421,11 @@ export const hiveMindTools = [
|
|
|
327
421
|
proposedAt: new Date().toISOString(),
|
|
328
422
|
votes: {},
|
|
329
423
|
status: 'pending',
|
|
424
|
+
strategy,
|
|
425
|
+
term: strategy === 'raft' ? term : undefined,
|
|
426
|
+
quorumPreset: strategy === 'quorum' ? quorumPreset : undefined,
|
|
427
|
+
byzantineVoters: strategy === 'bft' ? [] : undefined,
|
|
428
|
+
timeoutAt: strategy === 'raft' ? new Date(Date.now() + timeoutMs).toISOString() : undefined,
|
|
330
429
|
};
|
|
331
430
|
state.consensus.pending.push(proposal);
|
|
332
431
|
saveHiveState(state);
|
|
@@ -334,40 +433,115 @@ export const hiveMindTools = [
|
|
|
334
433
|
action,
|
|
335
434
|
proposalId,
|
|
336
435
|
type: proposal.type,
|
|
436
|
+
strategy,
|
|
337
437
|
status: 'pending',
|
|
338
|
-
|
|
438
|
+
required,
|
|
439
|
+
totalNodes,
|
|
440
|
+
term: proposal.term,
|
|
441
|
+
quorumPreset: proposal.quorumPreset,
|
|
442
|
+
timeoutAt: proposal.timeoutAt,
|
|
339
443
|
};
|
|
340
444
|
}
|
|
341
445
|
if (action === 'vote') {
|
|
342
446
|
const proposal = state.consensus.pending.find(p => p.proposalId === input.proposalId);
|
|
343
447
|
if (!proposal) {
|
|
344
|
-
return { action, error: 'Proposal not found' };
|
|
448
|
+
return { action, error: 'Proposal not found or already resolved' };
|
|
345
449
|
}
|
|
346
450
|
const voterId = input.voterId;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
451
|
+
if (!voterId) {
|
|
452
|
+
return { action, error: 'voterId is required for voting' };
|
|
453
|
+
}
|
|
454
|
+
const voteValue = input.vote;
|
|
455
|
+
const proposalStrategy = proposal.strategy || 'raft';
|
|
456
|
+
const required = calculateRequiredVotes(proposalStrategy, totalNodes, proposal.quorumPreset);
|
|
457
|
+
// Prevent double-voting
|
|
458
|
+
if (voterId in proposal.votes) {
|
|
459
|
+
const previousVote = proposal.votes[voterId];
|
|
460
|
+
if (previousVote === voteValue) {
|
|
461
|
+
return {
|
|
462
|
+
action,
|
|
463
|
+
error: `Voter ${voterId} has already cast the same vote on this proposal`,
|
|
464
|
+
proposalId: proposal.proposalId,
|
|
465
|
+
existingVote: previousVote,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
// Conflicting vote from same voter
|
|
469
|
+
if (proposalStrategy === 'bft') {
|
|
470
|
+
// BFT: detect as Byzantine behavior
|
|
471
|
+
if (!proposal.byzantineVoters)
|
|
472
|
+
proposal.byzantineVoters = [];
|
|
473
|
+
if (!proposal.byzantineVoters.includes(voterId)) {
|
|
474
|
+
proposal.byzantineVoters.push(voterId);
|
|
475
|
+
}
|
|
476
|
+
// Remove their vote entirely -- Byzantine voter is excluded
|
|
477
|
+
delete proposal.votes[voterId];
|
|
478
|
+
saveHiveState(state);
|
|
479
|
+
return {
|
|
480
|
+
action,
|
|
481
|
+
proposalId: proposal.proposalId,
|
|
482
|
+
voterId,
|
|
483
|
+
byzantineDetected: true,
|
|
484
|
+
message: `Byzantine behavior detected: voter ${voterId} attempted conflicting vote. Vote invalidated.`,
|
|
485
|
+
byzantineVoters: proposal.byzantineVoters,
|
|
486
|
+
status: proposal.status,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
if (proposalStrategy === 'raft') {
|
|
490
|
+
// Raft: only one vote per node per term, reject the change
|
|
491
|
+
return {
|
|
492
|
+
action,
|
|
493
|
+
error: `Raft: voter ${voterId} already voted in term ${proposal.term}. Cannot change vote.`,
|
|
494
|
+
proposalId: proposal.proposalId,
|
|
495
|
+
term: proposal.term,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
// Quorum: reject double-vote
|
|
499
|
+
return {
|
|
500
|
+
action,
|
|
501
|
+
error: `Voter ${voterId} has already voted on this proposal`,
|
|
355
502
|
proposalId: proposal.proposalId,
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
// BFT: check for cross-proposal Byzantine behavior
|
|
506
|
+
if (proposalStrategy === 'bft') {
|
|
507
|
+
const isByzantine = detectByzantineVoters(state.consensus.pending, proposal, voterId, voteValue);
|
|
508
|
+
if (isByzantine) {
|
|
509
|
+
if (!proposal.byzantineVoters)
|
|
510
|
+
proposal.byzantineVoters = [];
|
|
511
|
+
if (!proposal.byzantineVoters.includes(voterId)) {
|
|
512
|
+
proposal.byzantineVoters.push(voterId);
|
|
513
|
+
}
|
|
514
|
+
saveHiveState(state);
|
|
515
|
+
return {
|
|
516
|
+
action,
|
|
517
|
+
proposalId: proposal.proposalId,
|
|
518
|
+
voterId,
|
|
519
|
+
byzantineDetected: true,
|
|
520
|
+
message: `Byzantine behavior detected: voter ${voterId} cast conflicting votes across proposals of same type. Vote rejected.`,
|
|
521
|
+
byzantineVoters: proposal.byzantineVoters,
|
|
522
|
+
status: proposal.status,
|
|
523
|
+
};
|
|
524
|
+
}
|
|
362
525
|
}
|
|
363
|
-
|
|
364
|
-
|
|
526
|
+
// Record the vote
|
|
527
|
+
proposal.votes[voterId] = voteValue;
|
|
528
|
+
const votesFor = Object.values(proposal.votes).filter(v => v).length;
|
|
529
|
+
const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
|
|
530
|
+
// Try to resolve
|
|
531
|
+
const resolution = tryResolveProposal(proposal, totalNodes);
|
|
532
|
+
let resolved = false;
|
|
533
|
+
if (resolution !== null) {
|
|
534
|
+
resolved = true;
|
|
535
|
+
proposal.status = resolution;
|
|
365
536
|
state.consensus.history.push({
|
|
366
537
|
proposalId: proposal.proposalId,
|
|
367
538
|
type: proposal.type,
|
|
368
|
-
result:
|
|
539
|
+
result: resolution,
|
|
369
540
|
votes: { for: votesFor, against: votesAgainst },
|
|
370
541
|
decidedAt: new Date().toISOString(),
|
|
542
|
+
strategy: proposalStrategy,
|
|
543
|
+
term: proposal.term,
|
|
544
|
+
byzantineDetected: proposal.byzantineVoters?.length ? proposal.byzantineVoters : undefined,
|
|
371
545
|
});
|
|
372
546
|
state.consensus.pending = state.consensus.pending.filter(p => p.proposalId !== proposal.proposalId);
|
|
373
547
|
}
|
|
@@ -376,10 +550,17 @@ export const hiveMindTools = [
|
|
|
376
550
|
action,
|
|
377
551
|
proposalId: proposal.proposalId,
|
|
378
552
|
voterId,
|
|
379
|
-
vote:
|
|
553
|
+
vote: voteValue,
|
|
554
|
+
strategy: proposalStrategy,
|
|
380
555
|
votesFor,
|
|
381
556
|
votesAgainst,
|
|
557
|
+
required,
|
|
558
|
+
totalNodes,
|
|
559
|
+
resolved,
|
|
560
|
+
result: resolved ? resolution : undefined,
|
|
382
561
|
status: proposal.status,
|
|
562
|
+
term: proposal.term,
|
|
563
|
+
byzantineVoters: proposal.byzantineVoters?.length ? proposal.byzantineVoters : undefined,
|
|
383
564
|
};
|
|
384
565
|
}
|
|
385
566
|
if (action === 'status') {
|
|
@@ -388,21 +569,37 @@ export const hiveMindTools = [
|
|
|
388
569
|
// Check history
|
|
389
570
|
const historical = state.consensus.history.find(h => h.proposalId === input.proposalId);
|
|
390
571
|
if (historical) {
|
|
391
|
-
return { action, ...historical, historical: true };
|
|
572
|
+
return { action, ...historical, historical: true, resolved: true };
|
|
392
573
|
}
|
|
393
574
|
return { action, error: 'Proposal not found' };
|
|
394
575
|
}
|
|
395
576
|
const votesFor = Object.values(proposal.votes).filter(v => v).length;
|
|
396
577
|
const votesAgainst = Object.values(proposal.votes).filter(v => !v).length;
|
|
578
|
+
const proposalStrategy = proposal.strategy || 'raft';
|
|
579
|
+
const required = calculateRequiredVotes(proposalStrategy, totalNodes, proposal.quorumPreset);
|
|
580
|
+
// Raft: check timeout
|
|
581
|
+
let timedOut = false;
|
|
582
|
+
if (proposalStrategy === 'raft' && proposal.timeoutAt) {
|
|
583
|
+
timedOut = new Date().getTime() > new Date(proposal.timeoutAt).getTime();
|
|
584
|
+
}
|
|
397
585
|
return {
|
|
398
586
|
action,
|
|
399
587
|
proposalId: proposal.proposalId,
|
|
400
588
|
type: proposal.type,
|
|
589
|
+
strategy: proposalStrategy,
|
|
401
590
|
status: proposal.status,
|
|
402
591
|
votesFor,
|
|
403
592
|
votesAgainst,
|
|
404
593
|
totalVotes: Object.keys(proposal.votes).length,
|
|
405
|
-
|
|
594
|
+
required,
|
|
595
|
+
totalNodes,
|
|
596
|
+
resolved: false,
|
|
597
|
+
term: proposal.term,
|
|
598
|
+
quorumPreset: proposal.quorumPreset,
|
|
599
|
+
byzantineVoters: proposal.byzantineVoters?.length ? proposal.byzantineVoters : undefined,
|
|
600
|
+
timedOut,
|
|
601
|
+
timeoutAt: proposal.timeoutAt,
|
|
602
|
+
hint: timedOut ? `Raft timeout reached. Re-propose with term ${(proposal.term || 1) + 1}.` : undefined,
|
|
406
603
|
};
|
|
407
604
|
}
|
|
408
605
|
if (action === 'list') {
|
|
@@ -411,8 +608,12 @@ export const hiveMindTools = [
|
|
|
411
608
|
pending: state.consensus.pending.map(p => ({
|
|
412
609
|
proposalId: p.proposalId,
|
|
413
610
|
type: p.type,
|
|
611
|
+
strategy: p.strategy || 'raft',
|
|
414
612
|
proposedAt: p.proposedAt,
|
|
415
613
|
totalVotes: Object.keys(p.votes).length,
|
|
614
|
+
required: calculateRequiredVotes(p.strategy || 'raft', totalNodes, p.quorumPreset),
|
|
615
|
+
term: p.term,
|
|
616
|
+
status: p.status,
|
|
416
617
|
})),
|
|
417
618
|
recentHistory: state.consensus.history.slice(-5),
|
|
418
619
|
};
|
|
@@ -197,6 +197,30 @@ export declare class EWCConsolidator {
|
|
|
197
197
|
* Reset Fisher matrix (use with caution - allows forgetting)
|
|
198
198
|
*/
|
|
199
199
|
resetFisher(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Update Fisher matrix from pattern confidence changes.
|
|
202
|
+
* Called by SONA after distillLearning to track which patterns
|
|
203
|
+
* are important and should be protected from forgetting.
|
|
204
|
+
*
|
|
205
|
+
* Uses online averaging: F_new = alpha * F_old + (1-alpha) * F_current
|
|
206
|
+
*
|
|
207
|
+
* @param confidenceChanges - Array of {id, embedding, oldConf, newConf}
|
|
208
|
+
*/
|
|
209
|
+
updateFisherFromConfidences(confidenceChanges: {
|
|
210
|
+
id: string;
|
|
211
|
+
embedding: number[];
|
|
212
|
+
oldConf: number;
|
|
213
|
+
newConf: number;
|
|
214
|
+
}[]): void;
|
|
215
|
+
/**
|
|
216
|
+
* Compute consolidation penalty for a proposed confidence update.
|
|
217
|
+
* Used by SONA to check whether a pattern update would cause forgetting.
|
|
218
|
+
*
|
|
219
|
+
* @param oldConfidence - Current confidence value
|
|
220
|
+
* @param newConfidence - Proposed new confidence value
|
|
221
|
+
* @returns Penalty value (higher = more forgetting risk)
|
|
222
|
+
*/
|
|
223
|
+
computeConfidencePenalty(oldConfidence: number, newConfidence: number): number;
|
|
200
224
|
/**
|
|
201
225
|
* Clear all patterns and history (full reset)
|
|
202
226
|
*/
|
|
@@ -342,6 +342,65 @@ export class EWCConsolidator {
|
|
|
342
342
|
resetFisher() {
|
|
343
343
|
this.globalFisher = new Array(this.config.dimensions).fill(0);
|
|
344
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Update Fisher matrix from pattern confidence changes.
|
|
347
|
+
* Called by SONA after distillLearning to track which patterns
|
|
348
|
+
* are important and should be protected from forgetting.
|
|
349
|
+
*
|
|
350
|
+
* Uses online averaging: F_new = alpha * F_old + (1-alpha) * F_current
|
|
351
|
+
*
|
|
352
|
+
* @param confidenceChanges - Array of {id, embedding, oldConf, newConf}
|
|
353
|
+
*/
|
|
354
|
+
updateFisherFromConfidences(confidenceChanges) {
|
|
355
|
+
if (confidenceChanges.length === 0)
|
|
356
|
+
return;
|
|
357
|
+
const alpha = this.config.fisherDecayRate;
|
|
358
|
+
const currentFisher = new Array(this.config.dimensions).fill(0);
|
|
359
|
+
let sampleCount = 0;
|
|
360
|
+
for (const change of confidenceChanges) {
|
|
361
|
+
if (!change.embedding || change.embedding.length === 0)
|
|
362
|
+
continue;
|
|
363
|
+
const confDelta = Math.abs(change.newConf - change.oldConf);
|
|
364
|
+
if (confDelta === 0)
|
|
365
|
+
continue;
|
|
366
|
+
sampleCount++;
|
|
367
|
+
const len = Math.min(change.embedding.length, this.config.dimensions);
|
|
368
|
+
// Squared gradient proxy: embedding scaled by confidence change magnitude
|
|
369
|
+
for (let i = 0; i < len; i++) {
|
|
370
|
+
const grad = change.embedding[i] * confDelta;
|
|
371
|
+
currentFisher[i] += grad * grad;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (sampleCount > 0) {
|
|
375
|
+
for (let i = 0; i < this.config.dimensions; i++) {
|
|
376
|
+
currentFisher[i] /= sampleCount;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Online EMA: F_new = alpha * F_old + (1-alpha) * F_current
|
|
380
|
+
for (let i = 0; i < this.config.dimensions; i++) {
|
|
381
|
+
this.globalFisher[i] = alpha * this.globalFisher[i] + (1 - alpha) * currentFisher[i];
|
|
382
|
+
}
|
|
383
|
+
this.saveToDisk();
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Compute consolidation penalty for a proposed confidence update.
|
|
387
|
+
* Used by SONA to check whether a pattern update would cause forgetting.
|
|
388
|
+
*
|
|
389
|
+
* @param oldConfidence - Current confidence value
|
|
390
|
+
* @param newConfidence - Proposed new confidence value
|
|
391
|
+
* @returns Penalty value (higher = more forgetting risk)
|
|
392
|
+
*/
|
|
393
|
+
computeConfidencePenalty(oldConfidence, newConfidence) {
|
|
394
|
+
// Use the global Fisher to estimate penalty for scalar confidence change
|
|
395
|
+
// Average Fisher value represents overall importance
|
|
396
|
+
let avgFisher = 0;
|
|
397
|
+
for (let i = 0; i < this.globalFisher.length; i++) {
|
|
398
|
+
avgFisher += this.globalFisher[i];
|
|
399
|
+
}
|
|
400
|
+
avgFisher = this.globalFisher.length > 0 ? avgFisher / this.globalFisher.length : 0;
|
|
401
|
+
const diff = newConfidence - oldConfidence;
|
|
402
|
+
return (this.config.lambda / 2) * avgFisher * diff * diff;
|
|
403
|
+
}
|
|
345
404
|
/**
|
|
346
405
|
* Clear all patterns and history (full reset)
|
|
347
406
|
*/
|
|
@@ -76,6 +76,7 @@ declare class LocalSonaCoordinator {
|
|
|
76
76
|
private signalCount;
|
|
77
77
|
private trajectories;
|
|
78
78
|
private adaptationTimes;
|
|
79
|
+
private currentTrajectorySteps;
|
|
79
80
|
constructor(config: SonaConfig);
|
|
80
81
|
/**
|
|
81
82
|
* Record a signal - O(1) operation
|
|
@@ -98,6 +99,37 @@ declare class LocalSonaCoordinator {
|
|
|
98
99
|
* Get average adaptation time
|
|
99
100
|
*/
|
|
100
101
|
getAvgAdaptationTime(): number;
|
|
102
|
+
/**
|
|
103
|
+
* Add a step to the current in-progress trajectory
|
|
104
|
+
*/
|
|
105
|
+
addTrajectoryStep(step: TrajectoryStep): void;
|
|
106
|
+
/**
|
|
107
|
+
* End the current trajectory with a verdict and apply RL updates.
|
|
108
|
+
* Reward mapping: success=1.0, partial=0.5, failure=-0.5
|
|
109
|
+
*
|
|
110
|
+
* For successful/partial trajectories, boosts confidence of similar patterns
|
|
111
|
+
* in the ReasoningBank. For failures, reduces confidence scores.
|
|
112
|
+
*/
|
|
113
|
+
endTrajectory(verdict: 'success' | 'failure' | 'partial', bank: LocalReasoningBank): Promise<{
|
|
114
|
+
reward: number;
|
|
115
|
+
patternsUpdated: number;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Distill learning from recent successful trajectories.
|
|
119
|
+
* Applies LoRA-style confidence updates and integrates EWC++ consolidation.
|
|
120
|
+
*
|
|
121
|
+
* For each successful trajectory step with high confidence,
|
|
122
|
+
* increases the pattern's stored confidence by loraLearningRate * reward.
|
|
123
|
+
* Before applying updates, checks EWC penalty to prevent catastrophic forgetting.
|
|
124
|
+
*/
|
|
125
|
+
distillLearning(bank: LocalReasoningBank): Promise<{
|
|
126
|
+
patternsDistilled: number;
|
|
127
|
+
ewcPenalty: number;
|
|
128
|
+
}>;
|
|
129
|
+
/**
|
|
130
|
+
* Get current trajectory steps (for inspection)
|
|
131
|
+
*/
|
|
132
|
+
getCurrentTrajectorySteps(): TrajectoryStep[];
|
|
101
133
|
/**
|
|
102
134
|
* Get statistics
|
|
103
135
|
*/
|
|
@@ -221,6 +253,27 @@ export declare function getSonaCoordinator(): LocalSonaCoordinator | null;
|
|
|
221
253
|
* Get ReasoningBank for advanced operations
|
|
222
254
|
*/
|
|
223
255
|
export declare function getReasoningBank(): LocalReasoningBank | null;
|
|
256
|
+
/**
|
|
257
|
+
* End the current trajectory with a verdict and apply RL updates.
|
|
258
|
+
* This is the public API for the SONA RL loop.
|
|
259
|
+
*
|
|
260
|
+
* @param verdict - 'success' (reward=1.0), 'partial' (0.5), or 'failure' (-0.5)
|
|
261
|
+
* @returns Update statistics or null if not initialized
|
|
262
|
+
*/
|
|
263
|
+
export declare function endTrajectoryWithVerdict(verdict: 'success' | 'failure' | 'partial'): Promise<{
|
|
264
|
+
reward: number;
|
|
265
|
+
patternsUpdated: number;
|
|
266
|
+
} | null>;
|
|
267
|
+
/**
|
|
268
|
+
* Distill learning from recent successful trajectories.
|
|
269
|
+
* Applies LoRA-style confidence updates with EWC++ consolidation protection.
|
|
270
|
+
*
|
|
271
|
+
* @returns Distillation statistics or null if not initialized
|
|
272
|
+
*/
|
|
273
|
+
export declare function distillLearning(): Promise<{
|
|
274
|
+
patternsDistilled: number;
|
|
275
|
+
ewcPenalty: number;
|
|
276
|
+
} | null>;
|
|
224
277
|
/**
|
|
225
278
|
* Clear intelligence state
|
|
226
279
|
*/
|