@timmeck/brain-core 2.36.24 → 2.36.26
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/active-learning/__tests__/active-learning.test.d.ts +1 -0
- package/dist/active-learning/__tests__/active-learning.test.js +132 -0
- package/dist/active-learning/__tests__/active-learning.test.js.map +1 -0
- package/dist/active-learning/active-learner.d.ts +79 -0
- package/dist/active-learning/active-learner.js +224 -0
- package/dist/active-learning/active-learner.js.map +1 -0
- package/dist/active-learning/index.d.ts +2 -0
- package/dist/active-learning/index.js +2 -0
- package/dist/active-learning/index.js.map +1 -0
- package/dist/code-health/__tests__/code-health.test.d.ts +1 -0
- package/dist/code-health/__tests__/code-health.test.js +123 -0
- package/dist/code-health/__tests__/code-health.test.js.map +1 -0
- package/dist/code-health/health-monitor.d.ts +55 -0
- package/dist/code-health/health-monitor.js +180 -0
- package/dist/code-health/health-monitor.js.map +1 -0
- package/dist/code-health/index.d.ts +2 -0
- package/dist/code-health/index.js +2 -0
- package/dist/code-health/index.js.map +1 -0
- package/dist/consensus/__tests__/consensus.test.d.ts +1 -0
- package/dist/consensus/__tests__/consensus.test.js +159 -0
- package/dist/consensus/__tests__/consensus.test.js.map +1 -0
- package/dist/consensus/consensus-engine.d.ts +81 -0
- package/dist/consensus/consensus-engine.js +237 -0
- package/dist/consensus/consensus-engine.js.map +1 -0
- package/dist/consensus/index.d.ts +2 -0
- package/dist/consensus/index.js +2 -0
- package/dist/consensus/index.js.map +1 -0
- package/dist/feedback/__tests__/feedback-engine.test.d.ts +1 -0
- package/dist/feedback/__tests__/feedback-engine.test.js +156 -0
- package/dist/feedback/__tests__/feedback-engine.test.js.map +1 -0
- package/dist/feedback/feedback-engine.d.ts +61 -0
- package/dist/feedback/feedback-engine.js +203 -0
- package/dist/feedback/feedback-engine.js.map +1 -0
- package/dist/feedback/index.d.ts +2 -0
- package/dist/feedback/index.js +2 -0
- package/dist/feedback/index.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -1
- package/dist/knowledge-graph/__tests__/knowledge-graph.test.d.ts +1 -0
- package/dist/knowledge-graph/__tests__/knowledge-graph.test.js +215 -0
- package/dist/knowledge-graph/__tests__/knowledge-graph.test.js.map +1 -0
- package/dist/knowledge-graph/fact-extractor.d.ts +23 -0
- package/dist/knowledge-graph/fact-extractor.js +70 -0
- package/dist/knowledge-graph/fact-extractor.js.map +1 -0
- package/dist/knowledge-graph/graph-engine.d.ts +78 -0
- package/dist/knowledge-graph/graph-engine.js +276 -0
- package/dist/knowledge-graph/graph-engine.js.map +1 -0
- package/dist/knowledge-graph/index.d.ts +4 -0
- package/dist/knowledge-graph/index.js +3 -0
- package/dist/knowledge-graph/index.js.map +1 -0
- package/dist/proactive/__tests__/proactive-engine.test.d.ts +1 -0
- package/dist/proactive/__tests__/proactive-engine.test.js +183 -0
- package/dist/proactive/__tests__/proactive-engine.test.js.map +1 -0
- package/dist/proactive/index.d.ts +2 -0
- package/dist/proactive/index.js +2 -0
- package/dist/proactive/index.js.map +1 -0
- package/dist/proactive/proactive-engine.d.ts +86 -0
- package/dist/proactive/proactive-engine.js +252 -0
- package/dist/proactive/proactive-engine.js.map +1 -0
- package/dist/rag/__tests__/rag-engine.test.d.ts +1 -0
- package/dist/rag/__tests__/rag-engine.test.js +235 -0
- package/dist/rag/__tests__/rag-engine.test.js.map +1 -0
- package/dist/rag/index.d.ts +4 -0
- package/dist/rag/index.js +3 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/rag/rag-engine.d.ts +98 -0
- package/dist/rag/rag-engine.js +310 -0
- package/dist/rag/rag-engine.js.map +1 -0
- package/dist/rag/rag-indexer.d.ts +52 -0
- package/dist/rag/rag-indexer.js +144 -0
- package/dist/rag/rag-indexer.js.map +1 -0
- package/dist/research/__tests__/semantic-compressor.test.d.ts +1 -0
- package/dist/research/__tests__/semantic-compressor.test.js +153 -0
- package/dist/research/__tests__/semantic-compressor.test.js.map +1 -0
- package/dist/research/semantic-compressor.d.ts +55 -0
- package/dist/research/semantic-compressor.js +227 -0
- package/dist/research/semantic-compressor.js.map +1 -0
- package/dist/teaching/__tests__/teaching.test.d.ts +1 -0
- package/dist/teaching/__tests__/teaching.test.js +151 -0
- package/dist/teaching/__tests__/teaching.test.js.map +1 -0
- package/dist/teaching/curriculum.d.ts +32 -0
- package/dist/teaching/curriculum.js +89 -0
- package/dist/teaching/curriculum.js.map +1 -0
- package/dist/teaching/index.d.ts +4 -0
- package/dist/teaching/index.js +3 -0
- package/dist/teaching/index.js.map +1 -0
- package/dist/teaching/teaching-protocol.d.ts +74 -0
- package/dist/teaching/teaching-protocol.js +164 -0
- package/dist/teaching/teaching-protocol.js.map +1 -0
- package/dist/tool-learning/__tests__/tool-learning.test.d.ts +1 -0
- package/dist/tool-learning/__tests__/tool-learning.test.js +187 -0
- package/dist/tool-learning/__tests__/tool-learning.test.js.map +1 -0
- package/dist/tool-learning/index.d.ts +4 -0
- package/dist/tool-learning/index.js +3 -0
- package/dist/tool-learning/index.js.map +1 -0
- package/dist/tool-learning/tool-patterns.d.ts +47 -0
- package/dist/tool-learning/tool-patterns.js +125 -0
- package/dist/tool-learning/tool-patterns.js.map +1 -0
- package/dist/tool-learning/tool-tracker.d.ts +58 -0
- package/dist/tool-learning/tool-tracker.js +135 -0
- package/dist/tool-learning/tool-tracker.js.map +1 -0
- package/dist/user-model/__tests__/user-model.test.d.ts +1 -0
- package/dist/user-model/__tests__/user-model.test.js +142 -0
- package/dist/user-model/__tests__/user-model.test.js.map +1 -0
- package/dist/user-model/adaptive-context.d.ts +18 -0
- package/dist/user-model/adaptive-context.js +46 -0
- package/dist/user-model/adaptive-context.js.map +1 -0
- package/dist/user-model/index.d.ts +4 -0
- package/dist/user-model/index.js +3 -0
- package/dist/user-model/index.js.map +1 -0
- package/dist/user-model/user-model.d.ts +53 -0
- package/dist/user-model/user-model.js +204 -0
- package/dist/user-model/user-model.js.map +1 -0
- package/dist/utils/logger.js +4 -3
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
import { ActiveLearner, runActiveLearningMigration } from '../active-learner.js';
|
|
4
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
5
|
+
getLogger: () => ({
|
|
6
|
+
info: vi.fn(),
|
|
7
|
+
warn: vi.fn(),
|
|
8
|
+
error: vi.fn(),
|
|
9
|
+
debug: vi.fn(),
|
|
10
|
+
}),
|
|
11
|
+
}));
|
|
12
|
+
describe('ActiveLearner', () => {
|
|
13
|
+
let db;
|
|
14
|
+
let learner;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
db = new Database(':memory:');
|
|
17
|
+
learner = new ActiveLearner(db, { brainName: 'brain' });
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
db.close();
|
|
21
|
+
});
|
|
22
|
+
it('addGap creates a learning gap', () => {
|
|
23
|
+
const gap = learner.addGap('knowledge_void', 'quantum computing', 'No data on quantum algorithms', 0.8, 0.3);
|
|
24
|
+
expect(gap.id).toBeDefined();
|
|
25
|
+
expect(gap.gapType).toBe('knowledge_void');
|
|
26
|
+
expect(gap.topic).toBe('quantum computing');
|
|
27
|
+
expect(gap.description).toBe('No data on quantum algorithms');
|
|
28
|
+
expect(gap.impact).toBe(0.8);
|
|
29
|
+
expect(gap.ease).toBe(0.3);
|
|
30
|
+
expect(gap.status).toBe('open');
|
|
31
|
+
});
|
|
32
|
+
it('getOpenGaps returns gaps sorted by priority', () => {
|
|
33
|
+
learner.addGap('knowledge_void', 'topic-a', undefined, 0.9, 0.9); // priority = 0.81
|
|
34
|
+
learner.addGap('low_confidence', 'topic-b', undefined, 0.5, 0.5); // priority = 0.25
|
|
35
|
+
learner.addGap('unanswered', 'topic-c', undefined, 0.8, 0.7); // priority = 0.56
|
|
36
|
+
const gaps = learner.getOpenGaps();
|
|
37
|
+
expect(gaps.length).toBe(3);
|
|
38
|
+
// Sorted by impact * ease descending
|
|
39
|
+
expect(gaps[0].topic).toBe('topic-a');
|
|
40
|
+
expect(gaps[1].topic).toBe('topic-c');
|
|
41
|
+
expect(gaps[2].topic).toBe('topic-b');
|
|
42
|
+
});
|
|
43
|
+
it('planLearning selects strategy based on gap type', () => {
|
|
44
|
+
const voidGap = learner.addGap('knowledge_void', 'void-topic');
|
|
45
|
+
const lowConf = learner.addGap('low_confidence', 'low-conf-topic');
|
|
46
|
+
const unanswered = learner.addGap('unanswered', 'unanswered-topic');
|
|
47
|
+
const crossBrain = learner.addGap('cross_brain', 'cross-topic');
|
|
48
|
+
expect(learner.planLearning(voidGap.id).strategy).toBe('research_mission');
|
|
49
|
+
expect(learner.planLearning(lowConf.id).strategy).toBe('experiment');
|
|
50
|
+
expect(learner.planLearning(unanswered.id).strategy).toBe('ask_user');
|
|
51
|
+
expect(learner.planLearning(crossBrain.id).strategy).toBe('teach_request');
|
|
52
|
+
});
|
|
53
|
+
it('prioritize sorts gaps by impact * ease descending', () => {
|
|
54
|
+
const gaps = [
|
|
55
|
+
{ gapType: 'knowledge_void', topic: 'a', impact: 0.3, ease: 0.3, status: 'open' },
|
|
56
|
+
{ gapType: 'low_confidence', topic: 'b', impact: 0.9, ease: 0.9, status: 'open' },
|
|
57
|
+
{ gapType: 'unanswered', topic: 'c', impact: 0.5, ease: 0.8, status: 'open' },
|
|
58
|
+
];
|
|
59
|
+
const sorted = learner.prioritize(gaps);
|
|
60
|
+
expect(sorted[0].topic).toBe('b'); // 0.81
|
|
61
|
+
expect(sorted[1].topic).toBe('c'); // 0.40
|
|
62
|
+
expect(sorted[2].topic).toBe('a'); // 0.09
|
|
63
|
+
});
|
|
64
|
+
it('closeGap records outcome and marks closed', () => {
|
|
65
|
+
const gap = learner.addGap('knowledge_void', 'test-close');
|
|
66
|
+
learner.planLearning(gap.id);
|
|
67
|
+
const closed = learner.closeGap(gap.id, 'success');
|
|
68
|
+
expect(closed).toBe(true);
|
|
69
|
+
// Verify it's no longer in open gaps
|
|
70
|
+
const openGaps = learner.getOpenGaps();
|
|
71
|
+
const found = openGaps.find(g => g.id === gap.id);
|
|
72
|
+
expect(found).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
it('strategy success tracking in getStatus', () => {
|
|
75
|
+
const g1 = learner.addGap('knowledge_void', 'g1');
|
|
76
|
+
const g2 = learner.addGap('low_confidence', 'g2');
|
|
77
|
+
const g3 = learner.addGap('unanswered', 'g3');
|
|
78
|
+
learner.planLearning(g1.id);
|
|
79
|
+
learner.planLearning(g2.id);
|
|
80
|
+
learner.planLearning(g3.id);
|
|
81
|
+
learner.closeGap(g1.id, 'success');
|
|
82
|
+
learner.closeGap(g2.id, 'failure');
|
|
83
|
+
learner.closeGap(g3.id, 'success');
|
|
84
|
+
const status = learner.getStatus();
|
|
85
|
+
// 3 plan strategies (pending) + 3 close strategies = 6 total
|
|
86
|
+
// 2 success out of 6
|
|
87
|
+
expect(status.strategySuccessRate).toBeCloseTo(2 / 6, 2);
|
|
88
|
+
});
|
|
89
|
+
it('identifyGaps returns empty for no sources', () => {
|
|
90
|
+
const gaps = learner.identifyGaps();
|
|
91
|
+
expect(gaps).toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
it('identifyGaps finds gaps from sources', () => {
|
|
94
|
+
const gaps = learner.identifyGaps({
|
|
95
|
+
knowledgeVoids: [{ topic: 'blockchain', description: 'No data' }],
|
|
96
|
+
lowConfidenceFacts: [{ topic: 'AI safety', confidence: 0.1 }],
|
|
97
|
+
ragMisses: [{ query: 'quantum entanglement' }],
|
|
98
|
+
});
|
|
99
|
+
expect(gaps.length).toBe(3);
|
|
100
|
+
expect(gaps[0].gapType).toBe('knowledge_void');
|
|
101
|
+
expect(gaps[1].gapType).toBe('low_confidence');
|
|
102
|
+
expect(gaps[2].gapType).toBe('unanswered');
|
|
103
|
+
});
|
|
104
|
+
it('gap limit enforcement', () => {
|
|
105
|
+
const smallLearner = new ActiveLearner(db, { brainName: 'brain', maxOpenGaps: 3 });
|
|
106
|
+
smallLearner.addGap('knowledge_void', 'g1');
|
|
107
|
+
smallLearner.addGap('knowledge_void', 'g2');
|
|
108
|
+
smallLearner.addGap('knowledge_void', 'g3');
|
|
109
|
+
expect(() => smallLearner.addGap('knowledge_void', 'g4'))
|
|
110
|
+
.toThrow(/Maximum open gaps/);
|
|
111
|
+
});
|
|
112
|
+
it('migration is idempotent', () => {
|
|
113
|
+
runActiveLearningMigration(db);
|
|
114
|
+
runActiveLearningMigration(db);
|
|
115
|
+
const tables = db
|
|
116
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'learning%'")
|
|
117
|
+
.all();
|
|
118
|
+
expect(tables.length).toBe(2); // learning_gaps + learning_strategies
|
|
119
|
+
});
|
|
120
|
+
it('getStatus returns correct summary', () => {
|
|
121
|
+
learner.addGap('knowledge_void', 'open-gap');
|
|
122
|
+
const g2 = learner.addGap('low_confidence', 'to-close');
|
|
123
|
+
learner.planLearning(g2.id);
|
|
124
|
+
learner.closeGap(g2.id, 'success');
|
|
125
|
+
const status = learner.getStatus();
|
|
126
|
+
expect(status.totalGaps).toBe(2);
|
|
127
|
+
expect(status.openGaps).toBe(1);
|
|
128
|
+
expect(status.closedGaps).toBe(1);
|
|
129
|
+
expect(status.strategySuccessRate).toBeGreaterThan(0);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=active-learning.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"active-learning.test.js","sourceRoot":"","sources":["../../../src/active-learning/__tests__/active-learning.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { ThoughtStream } from '../consciousness/thought-stream.js';
|
|
3
|
+
export interface ActiveLearnerConfig {
|
|
4
|
+
brainName: string;
|
|
5
|
+
maxOpenGaps?: number;
|
|
6
|
+
}
|
|
7
|
+
export type GapType = 'knowledge_void' | 'low_confidence' | 'unanswered' | 'cross_brain';
|
|
8
|
+
export type GapStatus = 'open' | 'investigating' | 'closed';
|
|
9
|
+
export type StrategyOutcome = 'success' | 'failure' | 'partial' | 'pending';
|
|
10
|
+
export interface LearningGap {
|
|
11
|
+
id?: number;
|
|
12
|
+
gapType: GapType;
|
|
13
|
+
topic: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
impact: number;
|
|
16
|
+
ease: number;
|
|
17
|
+
strategy?: string;
|
|
18
|
+
status: GapStatus;
|
|
19
|
+
createdAt?: string;
|
|
20
|
+
closedAt?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface LearningStrategy {
|
|
23
|
+
id?: number;
|
|
24
|
+
gapId: number;
|
|
25
|
+
strategy: string;
|
|
26
|
+
outcome: StrategyOutcome;
|
|
27
|
+
createdAt?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface GapSources {
|
|
30
|
+
ragMisses?: Array<{
|
|
31
|
+
query: string;
|
|
32
|
+
}>;
|
|
33
|
+
lowConfidenceFacts?: Array<{
|
|
34
|
+
topic: string;
|
|
35
|
+
confidence: number;
|
|
36
|
+
}>;
|
|
37
|
+
knowledgeVoids?: Array<{
|
|
38
|
+
topic: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export interface PlanResult {
|
|
43
|
+
gapId: number;
|
|
44
|
+
strategy: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ActiveLearnerStatus {
|
|
47
|
+
totalGaps: number;
|
|
48
|
+
openGaps: number;
|
|
49
|
+
closedGaps: number;
|
|
50
|
+
strategySuccessRate: number;
|
|
51
|
+
}
|
|
52
|
+
export declare function runActiveLearningMigration(db: Database.Database): void;
|
|
53
|
+
export declare class ActiveLearner {
|
|
54
|
+
private readonly db;
|
|
55
|
+
private readonly config;
|
|
56
|
+
private readonly log;
|
|
57
|
+
private ts;
|
|
58
|
+
private readonly stmtInsertGap;
|
|
59
|
+
private readonly stmtUpdateGapStatus;
|
|
60
|
+
private readonly stmtUpdateGapStrategy;
|
|
61
|
+
private readonly stmtGetGap;
|
|
62
|
+
private readonly stmtOpenGaps;
|
|
63
|
+
private readonly stmtOpenGapCount;
|
|
64
|
+
private readonly stmtInsertStrategy;
|
|
65
|
+
private readonly stmtTotalGaps;
|
|
66
|
+
private readonly stmtClosedGaps;
|
|
67
|
+
private readonly stmtTotalStrategies;
|
|
68
|
+
private readonly stmtSuccessfulStrategies;
|
|
69
|
+
constructor(db: Database.Database, config: ActiveLearnerConfig);
|
|
70
|
+
setThoughtStream(stream: ThoughtStream): void;
|
|
71
|
+
identifyGaps(sources?: GapSources): LearningGap[];
|
|
72
|
+
planLearning(gapId: number): PlanResult | null;
|
|
73
|
+
prioritize(gaps: LearningGap[]): LearningGap[];
|
|
74
|
+
closeGap(gapId: number, outcome: StrategyOutcome): boolean;
|
|
75
|
+
addGap(type: GapType, topic: string, description?: string, impact?: number, ease?: number): LearningGap;
|
|
76
|
+
getOpenGaps(limit?: number): LearningGap[];
|
|
77
|
+
getStatus(): ActiveLearnerStatus;
|
|
78
|
+
private toGap;
|
|
79
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// ── Migration ───────────────────────────────────────────
|
|
3
|
+
export function runActiveLearningMigration(db) {
|
|
4
|
+
db.exec(`
|
|
5
|
+
CREATE TABLE IF NOT EXISTS learning_gaps (
|
|
6
|
+
id INTEGER PRIMARY KEY,
|
|
7
|
+
gap_type TEXT NOT NULL,
|
|
8
|
+
topic TEXT NOT NULL,
|
|
9
|
+
description TEXT,
|
|
10
|
+
impact REAL DEFAULT 0.5,
|
|
11
|
+
ease REAL DEFAULT 0.5,
|
|
12
|
+
strategy TEXT,
|
|
13
|
+
status TEXT DEFAULT 'open' CHECK(status IN ('open','investigating','closed')),
|
|
14
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
15
|
+
closed_at TEXT
|
|
16
|
+
);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_learning_gaps_status ON learning_gaps(status);
|
|
18
|
+
CREATE INDEX IF NOT EXISTS idx_learning_gaps_type ON learning_gaps(gap_type);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS learning_strategies (
|
|
21
|
+
id INTEGER PRIMARY KEY,
|
|
22
|
+
gap_id INTEGER REFERENCES learning_gaps(id),
|
|
23
|
+
strategy TEXT NOT NULL,
|
|
24
|
+
outcome TEXT CHECK(outcome IN ('success','failure','partial','pending')),
|
|
25
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
26
|
+
);
|
|
27
|
+
CREATE INDEX IF NOT EXISTS idx_learning_strategies_gap ON learning_strategies(gap_id);
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
// ── Engine ──────────────────────────────────────────────
|
|
31
|
+
export class ActiveLearner {
|
|
32
|
+
db;
|
|
33
|
+
config;
|
|
34
|
+
log = getLogger();
|
|
35
|
+
ts = null;
|
|
36
|
+
// Prepared statements
|
|
37
|
+
stmtInsertGap;
|
|
38
|
+
stmtUpdateGapStatus;
|
|
39
|
+
stmtUpdateGapStrategy;
|
|
40
|
+
stmtGetGap;
|
|
41
|
+
stmtOpenGaps;
|
|
42
|
+
stmtOpenGapCount;
|
|
43
|
+
stmtInsertStrategy;
|
|
44
|
+
stmtTotalGaps;
|
|
45
|
+
stmtClosedGaps;
|
|
46
|
+
stmtTotalStrategies;
|
|
47
|
+
stmtSuccessfulStrategies;
|
|
48
|
+
constructor(db, config) {
|
|
49
|
+
this.db = db;
|
|
50
|
+
this.config = {
|
|
51
|
+
brainName: config.brainName,
|
|
52
|
+
maxOpenGaps: config.maxOpenGaps ?? 50,
|
|
53
|
+
};
|
|
54
|
+
runActiveLearningMigration(db);
|
|
55
|
+
this.stmtInsertGap = db.prepare(`INSERT INTO learning_gaps (gap_type, topic, description, impact, ease)
|
|
56
|
+
VALUES (?, ?, ?, ?, ?)`);
|
|
57
|
+
this.stmtUpdateGapStatus = db.prepare(`UPDATE learning_gaps SET status = ?, closed_at = CASE WHEN ? = 'closed' THEN datetime('now') ELSE closed_at END WHERE id = ?`);
|
|
58
|
+
this.stmtUpdateGapStrategy = db.prepare('UPDATE learning_gaps SET strategy = ?, status = \'investigating\' WHERE id = ?');
|
|
59
|
+
this.stmtGetGap = db.prepare('SELECT * FROM learning_gaps WHERE id = ?');
|
|
60
|
+
this.stmtOpenGaps = db.prepare("SELECT * FROM learning_gaps WHERE status = 'open' OR status = 'investigating' ORDER BY (impact * ease) DESC LIMIT ?");
|
|
61
|
+
this.stmtOpenGapCount = db.prepare("SELECT COUNT(*) as cnt FROM learning_gaps WHERE status = 'open' OR status = 'investigating'");
|
|
62
|
+
this.stmtInsertStrategy = db.prepare('INSERT INTO learning_strategies (gap_id, strategy, outcome) VALUES (?, ?, ?)');
|
|
63
|
+
this.stmtTotalGaps = db.prepare('SELECT COUNT(*) as cnt FROM learning_gaps');
|
|
64
|
+
this.stmtClosedGaps = db.prepare("SELECT COUNT(*) as cnt FROM learning_gaps WHERE status = 'closed'");
|
|
65
|
+
this.stmtTotalStrategies = db.prepare('SELECT COUNT(*) as cnt FROM learning_strategies');
|
|
66
|
+
this.stmtSuccessfulStrategies = db.prepare("SELECT COUNT(*) as cnt FROM learning_strategies WHERE outcome = 'success'");
|
|
67
|
+
this.log.debug(`[ActiveLearner] Initialized for ${this.config.brainName}`);
|
|
68
|
+
}
|
|
69
|
+
// ── Setters ──────────────────────────────────────────
|
|
70
|
+
setThoughtStream(stream) {
|
|
71
|
+
this.ts = stream;
|
|
72
|
+
}
|
|
73
|
+
// ── Core: Identify Gaps ──────────────────────────────
|
|
74
|
+
identifyGaps(sources) {
|
|
75
|
+
const gaps = [];
|
|
76
|
+
this.ts?.emit('active-learning', 'analyzing', 'Scanning for knowledge gaps...', 'routine');
|
|
77
|
+
// 1. Knowledge voids: topics with no facts
|
|
78
|
+
if (sources?.knowledgeVoids) {
|
|
79
|
+
for (const void_ of sources.knowledgeVoids) {
|
|
80
|
+
gaps.push({
|
|
81
|
+
gapType: 'knowledge_void',
|
|
82
|
+
topic: void_.topic,
|
|
83
|
+
description: void_.description ?? `No knowledge found about "${void_.topic}"`,
|
|
84
|
+
impact: 0.6,
|
|
85
|
+
ease: 0.5,
|
|
86
|
+
status: 'open',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 2. Low confidence facts
|
|
91
|
+
if (sources?.lowConfidenceFacts) {
|
|
92
|
+
for (const fact of sources.lowConfidenceFacts) {
|
|
93
|
+
if (fact.confidence < 0.3) {
|
|
94
|
+
gaps.push({
|
|
95
|
+
gapType: 'low_confidence',
|
|
96
|
+
topic: fact.topic,
|
|
97
|
+
description: `Low confidence (${fact.confidence.toFixed(2)}) on "${fact.topic}"`,
|
|
98
|
+
impact: 0.5,
|
|
99
|
+
ease: 0.6,
|
|
100
|
+
status: 'open',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// 3. Unanswered queries (RAG misses)
|
|
106
|
+
if (sources?.ragMisses) {
|
|
107
|
+
for (const miss of sources.ragMisses) {
|
|
108
|
+
gaps.push({
|
|
109
|
+
gapType: 'unanswered',
|
|
110
|
+
topic: miss.query,
|
|
111
|
+
description: `Query with 0 RAG results: "${miss.query}"`,
|
|
112
|
+
impact: 0.7,
|
|
113
|
+
ease: 0.4,
|
|
114
|
+
status: 'open',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.ts?.emit('active-learning', 'discovering', `Found ${gaps.length} knowledge gaps`, gaps.length > 5 ? 'notable' : 'routine');
|
|
119
|
+
this.log.debug(`[ActiveLearner] Identified ${gaps.length} gaps`);
|
|
120
|
+
return gaps;
|
|
121
|
+
}
|
|
122
|
+
// ── Core: Plan Learning ──────────────────────────────
|
|
123
|
+
planLearning(gapId) {
|
|
124
|
+
const row = this.stmtGetGap.get(gapId);
|
|
125
|
+
if (!row)
|
|
126
|
+
return null;
|
|
127
|
+
const gap = this.toGap(row);
|
|
128
|
+
let strategy;
|
|
129
|
+
switch (gap.gapType) {
|
|
130
|
+
case 'knowledge_void':
|
|
131
|
+
strategy = 'research_mission';
|
|
132
|
+
break;
|
|
133
|
+
case 'low_confidence':
|
|
134
|
+
strategy = 'experiment';
|
|
135
|
+
break;
|
|
136
|
+
case 'unanswered':
|
|
137
|
+
strategy = 'ask_user';
|
|
138
|
+
break;
|
|
139
|
+
case 'cross_brain':
|
|
140
|
+
strategy = 'teach_request';
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
strategy = 'research_mission';
|
|
144
|
+
}
|
|
145
|
+
// Update gap with chosen strategy
|
|
146
|
+
this.stmtUpdateGapStrategy.run(strategy, gapId);
|
|
147
|
+
// Record strategy choice
|
|
148
|
+
this.stmtInsertStrategy.run(gapId, strategy, 'pending');
|
|
149
|
+
this.ts?.emit('active-learning', 'reflecting', `Plan for gap #${gapId}: ${strategy}`, 'routine');
|
|
150
|
+
this.log.debug(`[ActiveLearner] Plan for #${gapId}: ${strategy}`);
|
|
151
|
+
return { gapId, strategy };
|
|
152
|
+
}
|
|
153
|
+
// ── Core: Prioritize ────────────────────────────────
|
|
154
|
+
prioritize(gaps) {
|
|
155
|
+
return [...gaps].sort((a, b) => (b.impact * b.ease) - (a.impact * a.ease));
|
|
156
|
+
}
|
|
157
|
+
// ── Core: Close Gap ──────────────────────────────────
|
|
158
|
+
closeGap(gapId, outcome) {
|
|
159
|
+
const row = this.stmtGetGap.get(gapId);
|
|
160
|
+
if (!row)
|
|
161
|
+
return false;
|
|
162
|
+
this.stmtUpdateGapStatus.run('closed', 'closed', gapId);
|
|
163
|
+
// Record strategy outcome
|
|
164
|
+
this.stmtInsertStrategy.run(gapId, row.strategy ?? 'unknown', outcome);
|
|
165
|
+
this.ts?.emit('active-learning', outcome === 'success' ? 'discovering' : 'reflecting', `Gap #${gapId} closed: ${outcome}`, outcome === 'success' ? 'notable' : 'routine');
|
|
166
|
+
this.log.debug(`[ActiveLearner] Closed gap #${gapId}: ${outcome}`);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
// ── Core: Add Gap ────────────────────────────────────
|
|
170
|
+
addGap(type, topic, description, impact, ease) {
|
|
171
|
+
// Check maxOpenGaps limit
|
|
172
|
+
const openCount = this.stmtOpenGapCount.get().cnt;
|
|
173
|
+
if (openCount >= this.config.maxOpenGaps) {
|
|
174
|
+
this.log.warn(`[ActiveLearner] Max open gaps (${this.config.maxOpenGaps}) reached, rejecting new gap`);
|
|
175
|
+
throw new Error(`Maximum open gaps (${this.config.maxOpenGaps}) reached`);
|
|
176
|
+
}
|
|
177
|
+
const impactVal = impact ?? 0.5;
|
|
178
|
+
const easeVal = ease ?? 0.5;
|
|
179
|
+
const info = this.stmtInsertGap.run(type, topic, description ?? null, impactVal, easeVal);
|
|
180
|
+
this.ts?.emit('active-learning', 'reflecting', `New gap: ${topic} (${type})`, 'routine');
|
|
181
|
+
return {
|
|
182
|
+
id: Number(info.lastInsertRowid),
|
|
183
|
+
gapType: type,
|
|
184
|
+
topic,
|
|
185
|
+
description,
|
|
186
|
+
impact: impactVal,
|
|
187
|
+
ease: easeVal,
|
|
188
|
+
status: 'open',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// ── Core: Get Open Gaps ──────────────────────────────
|
|
192
|
+
getOpenGaps(limit = 20) {
|
|
193
|
+
const rows = this.stmtOpenGaps.all(limit);
|
|
194
|
+
return rows.map(r => this.toGap(r));
|
|
195
|
+
}
|
|
196
|
+
// ── Core: Status ─────────────────────────────────────
|
|
197
|
+
getStatus() {
|
|
198
|
+
const totalGaps = this.stmtTotalGaps.get().cnt;
|
|
199
|
+
const openGaps = this.stmtOpenGapCount.get().cnt;
|
|
200
|
+
const closedGaps = this.stmtClosedGaps.get().cnt;
|
|
201
|
+
const totalStrategies = this.stmtTotalStrategies.get().cnt;
|
|
202
|
+
const successfulStrategies = this.stmtSuccessfulStrategies.get().cnt;
|
|
203
|
+
const strategySuccessRate = totalStrategies > 0
|
|
204
|
+
? successfulStrategies / totalStrategies
|
|
205
|
+
: 0;
|
|
206
|
+
return { totalGaps, openGaps, closedGaps, strategySuccessRate };
|
|
207
|
+
}
|
|
208
|
+
// ── Private: Row Mapping ─────────────────────────────
|
|
209
|
+
toGap(row) {
|
|
210
|
+
return {
|
|
211
|
+
id: row.id,
|
|
212
|
+
gapType: row.gap_type,
|
|
213
|
+
topic: row.topic,
|
|
214
|
+
description: row.description ?? undefined,
|
|
215
|
+
impact: row.impact,
|
|
216
|
+
ease: row.ease,
|
|
217
|
+
strategy: row.strategy ?? undefined,
|
|
218
|
+
status: row.status,
|
|
219
|
+
createdAt: row.created_at,
|
|
220
|
+
closedAt: row.closed_at ?? undefined,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=active-learner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"active-learner.js","sourceRoot":"","sources":["../../src/active-learning/active-learner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/active-learning/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
import { CodeHealthMonitor, runCodeHealthMigration } from '../health-monitor.js';
|
|
4
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
5
|
+
getLogger: () => ({
|
|
6
|
+
info: vi.fn(),
|
|
7
|
+
warn: vi.fn(),
|
|
8
|
+
error: vi.fn(),
|
|
9
|
+
debug: vi.fn(),
|
|
10
|
+
}),
|
|
11
|
+
}));
|
|
12
|
+
describe('CodeHealthMonitor', () => {
|
|
13
|
+
let db;
|
|
14
|
+
let monitor;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
db = new Database(':memory:');
|
|
17
|
+
monitor = new CodeHealthMonitor(db, { brainName: 'brain' });
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
db.close();
|
|
21
|
+
});
|
|
22
|
+
it('migration is idempotent', () => {
|
|
23
|
+
// Migration already ran in constructor, run again — should not throw
|
|
24
|
+
runCodeHealthMigration(db);
|
|
25
|
+
runCodeHealthMigration(db);
|
|
26
|
+
const tables = db
|
|
27
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='code_health_scans'")
|
|
28
|
+
.all();
|
|
29
|
+
expect(tables.length).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
it('scan stores result in DB', () => {
|
|
32
|
+
const result = monitor.scan('/test/project');
|
|
33
|
+
expect(result.id).toBeDefined();
|
|
34
|
+
expect(result.projectPath).toBe('/test/project');
|
|
35
|
+
expect(typeof result.complexityScore).toBe('number');
|
|
36
|
+
expect(typeof result.duplicationScore).toBe('number');
|
|
37
|
+
expect(typeof result.depHealthScore).toBe('number');
|
|
38
|
+
expect(typeof result.testRatio).toBe('number');
|
|
39
|
+
expect(typeof result.techDebtScore).toBe('number');
|
|
40
|
+
expect(typeof result.fileCount).toBe('number');
|
|
41
|
+
// Verify persisted
|
|
42
|
+
const row = db.prepare('SELECT * FROM code_health_scans WHERE id = ?').get(result.id);
|
|
43
|
+
expect(row).toBeDefined();
|
|
44
|
+
expect(row.project_path).toBe('/test/project');
|
|
45
|
+
});
|
|
46
|
+
it('scan returns defaults with proper scores', () => {
|
|
47
|
+
const result = monitor.scan('/my/app');
|
|
48
|
+
expect(result.complexityScore).toBeGreaterThanOrEqual(0);
|
|
49
|
+
expect(result.complexityScore).toBeLessThanOrEqual(100);
|
|
50
|
+
expect(result.duplicationScore).toBe(0); // placeholder
|
|
51
|
+
expect(result.depHealthScore).toBeGreaterThanOrEqual(0);
|
|
52
|
+
expect(result.depHealthScore).toBeLessThanOrEqual(1);
|
|
53
|
+
expect(result.testRatio).toBeGreaterThanOrEqual(0);
|
|
54
|
+
expect(result.testRatio).toBeLessThanOrEqual(1);
|
|
55
|
+
expect(result.fileCount).toBeGreaterThan(0);
|
|
56
|
+
});
|
|
57
|
+
it('trends returns scan history', () => {
|
|
58
|
+
monitor.scan('/project/a');
|
|
59
|
+
monitor.scan('/project/a');
|
|
60
|
+
monitor.scan('/project/a');
|
|
61
|
+
const trendData = monitor.trends('/project/a');
|
|
62
|
+
expect(trendData.length).toBe(3);
|
|
63
|
+
// Most recent first
|
|
64
|
+
expect(trendData[0].scan.id).toBeGreaterThan(trendData[1].scan.id);
|
|
65
|
+
});
|
|
66
|
+
it('trends computes deltas between scans', () => {
|
|
67
|
+
monitor.scan('/project/a');
|
|
68
|
+
monitor.scan('/project/a');
|
|
69
|
+
const trendData = monitor.trends('/project/a');
|
|
70
|
+
expect(trendData.length).toBe(2);
|
|
71
|
+
// First entry (newest) should have deltas
|
|
72
|
+
expect(trendData[0].deltas).not.toBeNull();
|
|
73
|
+
expect(typeof trendData[0].deltas.complexityScore).toBe('number');
|
|
74
|
+
expect(typeof trendData[0].deltas.techDebtScore).toBe('number');
|
|
75
|
+
expect(typeof trendData[0].deltas.fileCount).toBe('number');
|
|
76
|
+
// Last entry (oldest) has no previous, so deltas = null
|
|
77
|
+
expect(trendData[1].deltas).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
it('getStatus returns empty state', () => {
|
|
80
|
+
const status = monitor.getStatus();
|
|
81
|
+
expect(status.totalScans).toBe(0);
|
|
82
|
+
expect(status.lastScan).toBeNull();
|
|
83
|
+
expect(status.avgTechDebt).toBe(0);
|
|
84
|
+
});
|
|
85
|
+
it('getStatus with data returns correct values', () => {
|
|
86
|
+
monitor.scan('/project/x');
|
|
87
|
+
monitor.scan('/project/y');
|
|
88
|
+
const status = monitor.getStatus();
|
|
89
|
+
expect(status.totalScans).toBe(2);
|
|
90
|
+
expect(status.lastScan).not.toBeNull();
|
|
91
|
+
expect(status.lastScan.projectPath).toBe('/project/y');
|
|
92
|
+
expect(status.avgTechDebt).toBeGreaterThan(0);
|
|
93
|
+
});
|
|
94
|
+
it('tech debt calculation is weighted composite', () => {
|
|
95
|
+
const result = monitor.scan('/project/test');
|
|
96
|
+
// techDebt = complexity*0.3 + duplication*0.3 + (1-testRatio)*100*0.2 + (1-depHealth)*100*0.2
|
|
97
|
+
const expected = result.complexityScore * 0.3 +
|
|
98
|
+
result.duplicationScore * 0.3 +
|
|
99
|
+
(1 - result.testRatio) * 100 * 0.2 +
|
|
100
|
+
(1 - result.depHealthScore) * 100 * 0.2;
|
|
101
|
+
expect(result.techDebtScore).toBeCloseTo(expected, 5);
|
|
102
|
+
});
|
|
103
|
+
it('dep health scoring considers deps ratio', () => {
|
|
104
|
+
// Different project paths produce different estimated dep counts
|
|
105
|
+
const result1 = monitor.scan('/a');
|
|
106
|
+
const result2 = monitor.scan('/very-long-project-name-for-different-stats');
|
|
107
|
+
// Both should be valid scores
|
|
108
|
+
expect(result1.depHealthScore).toBeGreaterThanOrEqual(0);
|
|
109
|
+
expect(result1.depHealthScore).toBeLessThanOrEqual(1);
|
|
110
|
+
expect(result2.depHealthScore).toBeGreaterThanOrEqual(0);
|
|
111
|
+
expect(result2.depHealthScore).toBeLessThanOrEqual(1);
|
|
112
|
+
});
|
|
113
|
+
it('scan multiple projects keeps separate histories', () => {
|
|
114
|
+
monitor.scan('/project/alpha');
|
|
115
|
+
monitor.scan('/project/alpha');
|
|
116
|
+
monitor.scan('/project/beta');
|
|
117
|
+
const alphaHistory = monitor.trends('/project/alpha');
|
|
118
|
+
const betaHistory = monitor.trends('/project/beta');
|
|
119
|
+
expect(alphaHistory.length).toBe(2);
|
|
120
|
+
expect(betaHistory.length).toBe(1);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=code-health.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-health.test.js","sourceRoot":"","sources":["../../../src/code-health/__tests__/code-health.test.ts"],"names":[],"mappings":"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"}
|