@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,153 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
4
|
+
getLogger: () => ({
|
|
5
|
+
info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn(),
|
|
6
|
+
}),
|
|
7
|
+
}));
|
|
8
|
+
import { SemanticCompressor, runSemanticCompressorMigration } from '../semantic-compressor.js';
|
|
9
|
+
// ── Helpers ──────────────────────────────────────────────────
|
|
10
|
+
function createTestDb() {
|
|
11
|
+
return new Database(':memory:');
|
|
12
|
+
}
|
|
13
|
+
function createEmbedding(values) {
|
|
14
|
+
const arr = new Float32Array(values);
|
|
15
|
+
return Buffer.from(arr.buffer);
|
|
16
|
+
}
|
|
17
|
+
function createNormalizedEmbedding(seed, dims = 4) {
|
|
18
|
+
const arr = new Float32Array(dims);
|
|
19
|
+
for (let i = 0; i < dims; i++) {
|
|
20
|
+
arr[i] = Math.sin(seed + i);
|
|
21
|
+
}
|
|
22
|
+
let norm = 0;
|
|
23
|
+
for (let i = 0; i < dims; i++)
|
|
24
|
+
norm += arr[i] * arr[i];
|
|
25
|
+
norm = Math.sqrt(norm);
|
|
26
|
+
if (norm > 0)
|
|
27
|
+
for (let i = 0; i < dims; i++)
|
|
28
|
+
arr[i] /= norm;
|
|
29
|
+
return Buffer.from(arr.buffer);
|
|
30
|
+
}
|
|
31
|
+
function insertTestVector(db, collection, sourceId, preview, embedding) {
|
|
32
|
+
db.prepare('INSERT INTO rag_vectors (collection, source_id, text_hash, text_preview, embedding) VALUES (?, ?, ?, ?, ?)').run(collection, sourceId, `hash-${sourceId}`, preview, embedding);
|
|
33
|
+
}
|
|
34
|
+
// ── Tests ───────────────────────────────────────────────────
|
|
35
|
+
describe('SemanticCompressor', () => {
|
|
36
|
+
let db;
|
|
37
|
+
let compressor;
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
db = createTestDb();
|
|
40
|
+
compressor = new SemanticCompressor(db, { brainName: 'test', minClusterSize: 2, similarityThreshold: 0.9 });
|
|
41
|
+
});
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
try {
|
|
44
|
+
db.close();
|
|
45
|
+
}
|
|
46
|
+
catch { /* ignore */ }
|
|
47
|
+
});
|
|
48
|
+
it('creates compressed_clusters table on migration', () => {
|
|
49
|
+
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='compressed_clusters'").all();
|
|
50
|
+
expect(tables).toHaveLength(1);
|
|
51
|
+
});
|
|
52
|
+
it('migration is idempotent', () => {
|
|
53
|
+
runSemanticCompressorMigration(db);
|
|
54
|
+
runSemanticCompressorMigration(db);
|
|
55
|
+
const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='compressed_clusters'").all();
|
|
56
|
+
expect(tables).toHaveLength(1);
|
|
57
|
+
});
|
|
58
|
+
it('returns empty result for empty collection', async () => {
|
|
59
|
+
const result = await compressor.compress('empty-collection');
|
|
60
|
+
expect(result.clustersFound).toBe(0);
|
|
61
|
+
expect(result.itemsCompressed).toBe(0);
|
|
62
|
+
expect(result.metaInsightsCreated).toBe(0);
|
|
63
|
+
});
|
|
64
|
+
it('does not cluster items below similarity threshold', async () => {
|
|
65
|
+
// Insert items with very different embeddings
|
|
66
|
+
insertTestVector(db, 'test-col', 1, 'item 1', createEmbedding([1, 0, 0, 0]));
|
|
67
|
+
insertTestVector(db, 'test-col', 2, 'item 2', createEmbedding([0, 1, 0, 0]));
|
|
68
|
+
insertTestVector(db, 'test-col', 3, 'item 3', createEmbedding([0, 0, 1, 0]));
|
|
69
|
+
const result = await compressor.compress('test-col');
|
|
70
|
+
expect(result.clustersFound).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
it('clusters similar items together', async () => {
|
|
73
|
+
// Insert items with nearly identical embeddings
|
|
74
|
+
const base = [0.5, 0.5, 0.5, 0.5];
|
|
75
|
+
insertTestVector(db, 'test-col', 1, 'similar item 1', createEmbedding(base));
|
|
76
|
+
insertTestVector(db, 'test-col', 2, 'similar item 2', createEmbedding(base));
|
|
77
|
+
insertTestVector(db, 'test-col', 3, 'similar item 3', createEmbedding(base));
|
|
78
|
+
const result = await compressor.compress('test-col');
|
|
79
|
+
expect(result.clustersFound).toBe(1);
|
|
80
|
+
expect(result.itemsCompressed).toBe(3);
|
|
81
|
+
expect(result.metaInsightsCreated).toBe(1);
|
|
82
|
+
});
|
|
83
|
+
it('generates meta-text from previews', async () => {
|
|
84
|
+
const base = [0.5, 0.5, 0.5, 0.5];
|
|
85
|
+
insertTestVector(db, 'test-col', 1, 'alpha', createEmbedding(base));
|
|
86
|
+
insertTestVector(db, 'test-col', 2, 'beta', createEmbedding(base));
|
|
87
|
+
insertTestVector(db, 'test-col', 3, 'gamma', createEmbedding(base));
|
|
88
|
+
await compressor.compress('test-col');
|
|
89
|
+
const clusters = db.prepare('SELECT * FROM compressed_clusters WHERE collection = ?').all('test-col');
|
|
90
|
+
expect(clusters).toHaveLength(1);
|
|
91
|
+
expect(clusters[0].summary).toContain('alpha');
|
|
92
|
+
expect(clusters[0].summary).toContain('beta');
|
|
93
|
+
});
|
|
94
|
+
it('tracks stats correctly', async () => {
|
|
95
|
+
const base = [0.5, 0.5, 0.5, 0.5];
|
|
96
|
+
insertTestVector(db, 'col-a', 1, 'a1', createEmbedding(base));
|
|
97
|
+
insertTestVector(db, 'col-a', 2, 'a2', createEmbedding(base));
|
|
98
|
+
insertTestVector(db, 'col-a', 3, 'a3', createEmbedding(base));
|
|
99
|
+
await compressor.compress('col-a');
|
|
100
|
+
const stats = compressor.getStats();
|
|
101
|
+
expect(stats.totalClusters).toBe(1);
|
|
102
|
+
expect(stats.byCollection).toHaveLength(1);
|
|
103
|
+
expect(stats.byCollection[0].collection).toBe('col-a');
|
|
104
|
+
expect(stats.byCollection[0].clusterCount).toBe(1);
|
|
105
|
+
expect(stats.byCollection[0].memberCount).toBe(3);
|
|
106
|
+
});
|
|
107
|
+
it('returns empty stats when no clusters exist', () => {
|
|
108
|
+
const stats = compressor.getStats();
|
|
109
|
+
expect(stats.totalClusters).toBe(0);
|
|
110
|
+
expect(stats.byCollection).toHaveLength(0);
|
|
111
|
+
});
|
|
112
|
+
it('respects maxClusterSize limit', async () => {
|
|
113
|
+
const compressorSmall = new SemanticCompressor(db, {
|
|
114
|
+
brainName: 'test',
|
|
115
|
+
minClusterSize: 2,
|
|
116
|
+
maxClusterSize: 3,
|
|
117
|
+
similarityThreshold: 0.9,
|
|
118
|
+
});
|
|
119
|
+
const base = [0.5, 0.5, 0.5, 0.5];
|
|
120
|
+
for (let i = 1; i <= 6; i++) {
|
|
121
|
+
insertTestVector(db, 'big-col', i, `item ${i}`, createEmbedding(base));
|
|
122
|
+
}
|
|
123
|
+
const result = await compressorSmall.compress('big-col');
|
|
124
|
+
// With maxClusterSize=3, the 6 items should be split into 2 clusters
|
|
125
|
+
expect(result.clustersFound).toBeGreaterThanOrEqual(2);
|
|
126
|
+
// Each cluster should have at most 3 items
|
|
127
|
+
const clusters = db.prepare('SELECT member_ids FROM compressed_clusters WHERE collection = ?').all('big-col');
|
|
128
|
+
for (const cluster of clusters) {
|
|
129
|
+
const members = JSON.parse(cluster.member_ids);
|
|
130
|
+
expect(members.length).toBeLessThanOrEqual(3);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
it('skips compression without rag vectors', async () => {
|
|
134
|
+
// Compress a collection that has no vectors
|
|
135
|
+
const result = await compressor.compress('nonexistent');
|
|
136
|
+
expect(result.clustersFound).toBe(0);
|
|
137
|
+
});
|
|
138
|
+
it('uses LLM for summary when available', async () => {
|
|
139
|
+
const mockLLM = {
|
|
140
|
+
call: vi.fn().mockResolvedValue({ text: 'LLM generated summary' }),
|
|
141
|
+
};
|
|
142
|
+
compressor.setLLMService(mockLLM);
|
|
143
|
+
const base = [0.5, 0.5, 0.5, 0.5];
|
|
144
|
+
insertTestVector(db, 'llm-col', 1, 'item 1', createEmbedding(base));
|
|
145
|
+
insertTestVector(db, 'llm-col', 2, 'item 2', createEmbedding(base));
|
|
146
|
+
insertTestVector(db, 'llm-col', 3, 'item 3', createEmbedding(base));
|
|
147
|
+
await compressor.compress('llm-col');
|
|
148
|
+
expect(mockLLM.call).toHaveBeenCalled();
|
|
149
|
+
const clusters = db.prepare('SELECT summary FROM compressed_clusters WHERE collection = ?').all('llm-col');
|
|
150
|
+
expect(clusters[0].summary).toBe('LLM generated summary');
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
//# sourceMappingURL=semantic-compressor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-compressor.test.js","sourceRoot":"","sources":["../../../src/research/__tests__/semantic-compressor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { ThoughtStream } from '../consciousness/thought-stream.js';
|
|
3
|
+
import type { RAGEngine } from '../rag/rag-engine.js';
|
|
4
|
+
import type { LLMService } from '../llm/llm-service.js';
|
|
5
|
+
export interface SemanticCompressorConfig {
|
|
6
|
+
brainName: string;
|
|
7
|
+
/** Minimum items to form a cluster. Default: 3 */
|
|
8
|
+
minClusterSize?: number;
|
|
9
|
+
/** Cosine similarity threshold. Default: 0.85 */
|
|
10
|
+
similarityThreshold?: number;
|
|
11
|
+
/** Maximum items per cluster. Default: 20 */
|
|
12
|
+
maxClusterSize?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CompressResult {
|
|
15
|
+
clustersFound: number;
|
|
16
|
+
itemsCompressed: number;
|
|
17
|
+
metaInsightsCreated: number;
|
|
18
|
+
}
|
|
19
|
+
export interface CompressedCluster {
|
|
20
|
+
id?: number;
|
|
21
|
+
collection: string;
|
|
22
|
+
member_ids: number[];
|
|
23
|
+
summary: string;
|
|
24
|
+
created_at: string;
|
|
25
|
+
}
|
|
26
|
+
export interface CompressorStats {
|
|
27
|
+
totalClusters: number;
|
|
28
|
+
byCollection: Array<{
|
|
29
|
+
collection: string;
|
|
30
|
+
clusterCount: number;
|
|
31
|
+
memberCount: number;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export declare function runSemanticCompressorMigration(db: Database.Database): void;
|
|
35
|
+
export declare class SemanticCompressor {
|
|
36
|
+
private readonly db;
|
|
37
|
+
private readonly config;
|
|
38
|
+
private readonly log;
|
|
39
|
+
private ts;
|
|
40
|
+
private rag;
|
|
41
|
+
private llm;
|
|
42
|
+
private readonly stmtInsertCluster;
|
|
43
|
+
private readonly stmtGetClusters;
|
|
44
|
+
private readonly stmtTotalClusters;
|
|
45
|
+
private readonly stmtClustersByCollection;
|
|
46
|
+
private readonly stmtGetVectorsByCollection;
|
|
47
|
+
constructor(db: Database.Database, config: SemanticCompressorConfig);
|
|
48
|
+
setRAGEngine(rag: RAGEngine): void;
|
|
49
|
+
setLLMService(llm: LLMService): void;
|
|
50
|
+
setThoughtStream(ts: ThoughtStream): void;
|
|
51
|
+
compress(collection: string, threshold?: number): Promise<CompressResult>;
|
|
52
|
+
getStats(): CompressorStats;
|
|
53
|
+
private parseEmbedding;
|
|
54
|
+
private cosineSimilarity;
|
|
55
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { getLogger } from '../utils/logger.js';
|
|
2
|
+
// ── Migration ───────────────────────────────────────────
|
|
3
|
+
export function runSemanticCompressorMigration(db) {
|
|
4
|
+
db.exec(`
|
|
5
|
+
CREATE TABLE IF NOT EXISTS compressed_clusters (
|
|
6
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
+
collection TEXT NOT NULL,
|
|
8
|
+
member_ids TEXT NOT NULL,
|
|
9
|
+
summary TEXT NOT NULL,
|
|
10
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
11
|
+
);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_compressed_clusters_collection ON compressed_clusters(collection);
|
|
13
|
+
`);
|
|
14
|
+
}
|
|
15
|
+
// ── Engine ──────────────────────────────────────────────
|
|
16
|
+
export class SemanticCompressor {
|
|
17
|
+
db;
|
|
18
|
+
config;
|
|
19
|
+
log = getLogger();
|
|
20
|
+
ts = null;
|
|
21
|
+
rag = null;
|
|
22
|
+
llm = null;
|
|
23
|
+
// ── Prepared statements ──────────────────────────────
|
|
24
|
+
stmtInsertCluster;
|
|
25
|
+
stmtGetClusters;
|
|
26
|
+
stmtTotalClusters;
|
|
27
|
+
stmtClustersByCollection;
|
|
28
|
+
stmtGetVectorsByCollection;
|
|
29
|
+
constructor(db, config) {
|
|
30
|
+
this.db = db;
|
|
31
|
+
this.config = {
|
|
32
|
+
brainName: config.brainName,
|
|
33
|
+
minClusterSize: config.minClusterSize ?? 3,
|
|
34
|
+
similarityThreshold: config.similarityThreshold ?? 0.85,
|
|
35
|
+
maxClusterSize: config.maxClusterSize ?? 20,
|
|
36
|
+
};
|
|
37
|
+
runSemanticCompressorMigration(db);
|
|
38
|
+
// Also ensure rag_vectors table exists for querying
|
|
39
|
+
// (RAGEngine should have already created it, but be defensive)
|
|
40
|
+
db.exec(`
|
|
41
|
+
CREATE TABLE IF NOT EXISTS rag_vectors (
|
|
42
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
+
collection TEXT NOT NULL,
|
|
44
|
+
source_id INTEGER NOT NULL,
|
|
45
|
+
text_hash TEXT NOT NULL,
|
|
46
|
+
text_preview TEXT,
|
|
47
|
+
embedding BLOB NOT NULL,
|
|
48
|
+
metadata TEXT,
|
|
49
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
50
|
+
UNIQUE(collection, source_id)
|
|
51
|
+
);
|
|
52
|
+
`);
|
|
53
|
+
this.stmtInsertCluster = db.prepare(`
|
|
54
|
+
INSERT INTO compressed_clusters (collection, member_ids, summary)
|
|
55
|
+
VALUES (?, ?, ?)
|
|
56
|
+
`);
|
|
57
|
+
this.stmtGetClusters = db.prepare('SELECT * FROM compressed_clusters WHERE collection = ? ORDER BY created_at DESC');
|
|
58
|
+
this.stmtTotalClusters = db.prepare('SELECT COUNT(*) as cnt FROM compressed_clusters');
|
|
59
|
+
this.stmtClustersByCollection = db.prepare(`
|
|
60
|
+
SELECT collection, COUNT(*) as cluster_count, member_ids
|
|
61
|
+
FROM compressed_clusters
|
|
62
|
+
GROUP BY collection
|
|
63
|
+
`);
|
|
64
|
+
this.stmtGetVectorsByCollection = db.prepare('SELECT id, collection, source_id, text_preview, embedding FROM rag_vectors WHERE collection = ?');
|
|
65
|
+
this.log.info(`[SemanticCompressor] Initialized for ${this.config.brainName}`);
|
|
66
|
+
}
|
|
67
|
+
// ── Setters ──────────────────────────────────────────
|
|
68
|
+
setRAGEngine(rag) { this.rag = rag; }
|
|
69
|
+
setLLMService(llm) { this.llm = llm; }
|
|
70
|
+
setThoughtStream(ts) { this.ts = ts; }
|
|
71
|
+
// ── Core Operations ──────────────────────────────────
|
|
72
|
+
async compress(collection, threshold) {
|
|
73
|
+
const simThreshold = threshold ?? this.config.similarityThreshold;
|
|
74
|
+
// Load all vectors for the collection
|
|
75
|
+
const rows = this.stmtGetVectorsByCollection.all(collection);
|
|
76
|
+
if (rows.length === 0) {
|
|
77
|
+
this.log.debug(`[SemanticCompressor] No items in collection "${collection}"`);
|
|
78
|
+
return { clustersFound: 0, itemsCompressed: 0, metaInsightsCreated: 0 };
|
|
79
|
+
}
|
|
80
|
+
// Parse embeddings
|
|
81
|
+
const items = rows.map(row => ({
|
|
82
|
+
id: row.id,
|
|
83
|
+
sourceId: row.source_id,
|
|
84
|
+
preview: row.text_preview ?? '',
|
|
85
|
+
embedding: this.parseEmbedding(row.embedding),
|
|
86
|
+
}));
|
|
87
|
+
// Compute pairwise cosine similarity and build adjacency
|
|
88
|
+
const neighborMap = new Map();
|
|
89
|
+
for (let i = 0; i < items.length; i++) {
|
|
90
|
+
for (let j = i + 1; j < items.length; j++) {
|
|
91
|
+
const sim = this.cosineSimilarity(items[i].embedding, items[j].embedding);
|
|
92
|
+
if (sim >= simThreshold) {
|
|
93
|
+
if (!neighborMap.has(i))
|
|
94
|
+
neighborMap.set(i, new Set());
|
|
95
|
+
if (!neighborMap.has(j))
|
|
96
|
+
neighborMap.set(j, new Set());
|
|
97
|
+
neighborMap.get(i).add(j);
|
|
98
|
+
neighborMap.get(j).add(i);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Greedy clustering
|
|
103
|
+
const assigned = new Set();
|
|
104
|
+
const clusters = [];
|
|
105
|
+
// Sort by neighbor count descending (most connected first)
|
|
106
|
+
const indices = Array.from({ length: items.length }, (_, i) => i);
|
|
107
|
+
indices.sort((a, b) => (neighborMap.get(b)?.size ?? 0) - (neighborMap.get(a)?.size ?? 0));
|
|
108
|
+
for (const idx of indices) {
|
|
109
|
+
if (assigned.has(idx))
|
|
110
|
+
continue;
|
|
111
|
+
const neighbors = neighborMap.get(idx);
|
|
112
|
+
if (!neighbors || neighbors.size === 0)
|
|
113
|
+
continue;
|
|
114
|
+
const cluster = [idx];
|
|
115
|
+
assigned.add(idx);
|
|
116
|
+
for (const neighbor of neighbors) {
|
|
117
|
+
if (assigned.has(neighbor))
|
|
118
|
+
continue;
|
|
119
|
+
if (cluster.length >= this.config.maxClusterSize)
|
|
120
|
+
break;
|
|
121
|
+
cluster.push(neighbor);
|
|
122
|
+
assigned.add(neighbor);
|
|
123
|
+
}
|
|
124
|
+
if (cluster.length >= this.config.minClusterSize) {
|
|
125
|
+
clusters.push(cluster);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Create meta-insights for each cluster
|
|
129
|
+
let metaInsightsCreated = 0;
|
|
130
|
+
let totalCompressed = 0;
|
|
131
|
+
for (const cluster of clusters) {
|
|
132
|
+
const memberIds = cluster.map(i => items[i].id);
|
|
133
|
+
const previews = cluster.map(i => items[i].preview).filter(p => p.length > 0);
|
|
134
|
+
const metaText = previews.join(' | ').slice(0, 500);
|
|
135
|
+
let summary;
|
|
136
|
+
if (this.llm) {
|
|
137
|
+
try {
|
|
138
|
+
const response = await this.llm.call('summarize', `Summarize these related items in 1-2 sentences:\n${metaText}`, { maxTokens: 150 });
|
|
139
|
+
summary = response?.text ?? metaText;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
summary = metaText;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
summary = metaText;
|
|
147
|
+
}
|
|
148
|
+
this.stmtInsertCluster.run(collection, JSON.stringify(memberIds), summary);
|
|
149
|
+
metaInsightsCreated++;
|
|
150
|
+
totalCompressed += cluster.length;
|
|
151
|
+
}
|
|
152
|
+
this.log.info(`[SemanticCompressor] Compressed ${totalCompressed} items into ${clusters.length} cluster(s) in "${collection}"`);
|
|
153
|
+
this.ts?.emit('semantic-compressor', 'analyzing', `Compressed ${totalCompressed} items into ${clusters.length} cluster(s)`, clusters.length > 0 ? 'notable' : 'routine');
|
|
154
|
+
return {
|
|
155
|
+
clustersFound: clusters.length,
|
|
156
|
+
itemsCompressed: totalCompressed,
|
|
157
|
+
metaInsightsCreated,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
getStats() {
|
|
161
|
+
const totalRow = this.stmtTotalClusters.get();
|
|
162
|
+
// Get per-collection stats
|
|
163
|
+
const rows = this.stmtClustersByCollection.all();
|
|
164
|
+
// We need to re-query to get accurate member counts per collection
|
|
165
|
+
const byCollectionMap = new Map();
|
|
166
|
+
for (const row of rows) {
|
|
167
|
+
const existing = byCollectionMap.get(row.collection);
|
|
168
|
+
const memberIds = JSON.parse(row.member_ids);
|
|
169
|
+
if (existing) {
|
|
170
|
+
existing.clusterCount++;
|
|
171
|
+
existing.memberCount += memberIds.length;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
byCollectionMap.set(row.collection, {
|
|
175
|
+
clusterCount: 1,
|
|
176
|
+
memberCount: memberIds.length,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Actually, the GROUP BY already gives us cluster_count per collection,
|
|
181
|
+
// but member_ids is only one row's value. Let's fix this by iterating all clusters.
|
|
182
|
+
const allClusters = this.db.prepare('SELECT collection, member_ids FROM compressed_clusters').all();
|
|
183
|
+
const statsMap = new Map();
|
|
184
|
+
for (const cluster of allClusters) {
|
|
185
|
+
const memberIds = JSON.parse(cluster.member_ids);
|
|
186
|
+
const existing = statsMap.get(cluster.collection);
|
|
187
|
+
if (existing) {
|
|
188
|
+
existing.clusterCount++;
|
|
189
|
+
existing.memberCount += memberIds.length;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
statsMap.set(cluster.collection, {
|
|
193
|
+
clusterCount: 1,
|
|
194
|
+
memberCount: memberIds.length,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const byCollection = Array.from(statsMap.entries()).map(([collection, stats]) => ({
|
|
199
|
+
collection,
|
|
200
|
+
clusterCount: stats.clusterCount,
|
|
201
|
+
memberCount: stats.memberCount,
|
|
202
|
+
}));
|
|
203
|
+
return {
|
|
204
|
+
totalClusters: totalRow.cnt,
|
|
205
|
+
byCollection,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
// ── Private Helpers ──────────────────────────────────
|
|
209
|
+
parseEmbedding(blob) {
|
|
210
|
+
return new Float32Array(blob.buffer, blob.byteOffset, blob.byteLength / 4);
|
|
211
|
+
}
|
|
212
|
+
cosineSimilarity(a, b) {
|
|
213
|
+
if (a.length !== b.length || a.length === 0)
|
|
214
|
+
return 0;
|
|
215
|
+
let dot = 0;
|
|
216
|
+
let normA = 0;
|
|
217
|
+
let normB = 0;
|
|
218
|
+
for (let i = 0; i < a.length; i++) {
|
|
219
|
+
dot += a[i] * b[i];
|
|
220
|
+
normA += a[i] * a[i];
|
|
221
|
+
normB += b[i] * b[i];
|
|
222
|
+
}
|
|
223
|
+
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
224
|
+
return denom === 0 ? 0 : dot / denom;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=semantic-compressor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-compressor.js","sourceRoot":"","sources":["../../src/research/semantic-compressor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
import { TeachingProtocol, runTeachingMigration } from '../teaching-protocol.js';
|
|
4
|
+
import { Curriculum, runCurriculumMigration } from '../curriculum.js';
|
|
5
|
+
vi.mock('../../utils/logger.js', () => ({
|
|
6
|
+
getLogger: () => ({
|
|
7
|
+
info: vi.fn(),
|
|
8
|
+
warn: vi.fn(),
|
|
9
|
+
error: vi.fn(),
|
|
10
|
+
debug: vi.fn(),
|
|
11
|
+
}),
|
|
12
|
+
}));
|
|
13
|
+
describe('TeachingProtocol', () => {
|
|
14
|
+
let db;
|
|
15
|
+
let protocol;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
db = new Database(':memory:');
|
|
18
|
+
protocol = new TeachingProtocol(db, { brainName: 'brain' });
|
|
19
|
+
});
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
db.close();
|
|
22
|
+
});
|
|
23
|
+
it('teach creates a sent lesson', () => {
|
|
24
|
+
const lesson = protocol.teach('trading-brain', {
|
|
25
|
+
domain: 'error-handling',
|
|
26
|
+
principle: 'Always validate input before processing',
|
|
27
|
+
evidence: 'Observed 30% fewer crashes after validation',
|
|
28
|
+
applicability: 0.8,
|
|
29
|
+
});
|
|
30
|
+
expect(lesson.id).toBeDefined();
|
|
31
|
+
expect(lesson.direction).toBe('sent');
|
|
32
|
+
expect(lesson.targetBrain).toBe('trading-brain');
|
|
33
|
+
expect(lesson.sourceBrain).toBe('brain');
|
|
34
|
+
expect(lesson.domain).toBe('error-handling');
|
|
35
|
+
expect(lesson.principle).toBe('Always validate input before processing');
|
|
36
|
+
expect(lesson.applicability).toBe(0.8);
|
|
37
|
+
});
|
|
38
|
+
it('learn accepts relevant lesson', () => {
|
|
39
|
+
const result = protocol.learn({
|
|
40
|
+
sourceBrain: 'trading-brain',
|
|
41
|
+
domain: 'code patterns',
|
|
42
|
+
principle: 'Error handling reduces code bugs significantly',
|
|
43
|
+
evidence: 'Proven in production for 6 months',
|
|
44
|
+
applicability: 0.9,
|
|
45
|
+
});
|
|
46
|
+
// Contains keywords matching 'brain' domain ('error', 'code', 'bug')
|
|
47
|
+
expect(result.relevanceScore).toBeGreaterThan(0);
|
|
48
|
+
expect(result.accepted).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
it('learn rejects irrelevant lesson', () => {
|
|
51
|
+
const result = protocol.learn({
|
|
52
|
+
sourceBrain: 'marketing-brain',
|
|
53
|
+
domain: 'astronomy',
|
|
54
|
+
principle: 'Stars rotate around galactic center',
|
|
55
|
+
applicability: 0.1,
|
|
56
|
+
});
|
|
57
|
+
// No keyword overlap with 'brain' domain
|
|
58
|
+
expect(result.relevanceScore).toBeLessThan(0.3);
|
|
59
|
+
expect(result.accepted).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
it('requestLesson creates a request record', () => {
|
|
62
|
+
const request = protocol.requestLesson('trading-brain', 'market signals');
|
|
63
|
+
expect(request.id).toBeDefined();
|
|
64
|
+
expect(request.direction).toBe('sent');
|
|
65
|
+
expect(request.targetBrain).toBe('trading-brain');
|
|
66
|
+
expect(request.domain).toBe('market signals');
|
|
67
|
+
expect(request.principle).toContain('REQUEST');
|
|
68
|
+
});
|
|
69
|
+
it('getHistory returns lessons in order', () => {
|
|
70
|
+
protocol.teach('trading-brain', { domain: 'a', principle: 'First' });
|
|
71
|
+
protocol.teach('marketing-brain', { domain: 'b', principle: 'Second' });
|
|
72
|
+
protocol.learn({ sourceBrain: 'trading-brain', domain: 'c', principle: 'Third about error code' });
|
|
73
|
+
const all = protocol.getHistory();
|
|
74
|
+
expect(all.length).toBe(3);
|
|
75
|
+
// Most recent first
|
|
76
|
+
expect(all[0].principle).toContain('Third');
|
|
77
|
+
const sent = protocol.getHistory('sent');
|
|
78
|
+
expect(sent.length).toBe(2);
|
|
79
|
+
const received = protocol.getHistory('received');
|
|
80
|
+
expect(received.length).toBe(1);
|
|
81
|
+
});
|
|
82
|
+
it('getStatus returns correct counts', () => {
|
|
83
|
+
protocol.teach('trading-brain', { domain: 'x', principle: 'A' });
|
|
84
|
+
protocol.teach('marketing-brain', { domain: 'y', principle: 'B' });
|
|
85
|
+
protocol.learn({ sourceBrain: 'trading-brain', domain: 'z', principle: 'Error code bug fix', applicability: 0.9 });
|
|
86
|
+
const status = protocol.getStatus();
|
|
87
|
+
expect(status.totalSent).toBe(2);
|
|
88
|
+
expect(status.totalReceived).toBe(1);
|
|
89
|
+
expect(status.acceptedCount).toBeGreaterThanOrEqual(1);
|
|
90
|
+
expect(typeof status.avgRelevance).toBe('number');
|
|
91
|
+
});
|
|
92
|
+
it('migration is idempotent (teaching)', () => {
|
|
93
|
+
runTeachingMigration(db);
|
|
94
|
+
runTeachingMigration(db);
|
|
95
|
+
const tables = db
|
|
96
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='teaching_lessons'")
|
|
97
|
+
.all();
|
|
98
|
+
expect(tables.length).toBe(1);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe('Curriculum', () => {
|
|
102
|
+
let db;
|
|
103
|
+
let curriculum;
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
db = new Database(':memory:');
|
|
106
|
+
curriculum = new Curriculum(db);
|
|
107
|
+
});
|
|
108
|
+
afterEach(() => {
|
|
109
|
+
db.close();
|
|
110
|
+
});
|
|
111
|
+
it('registerPrinciple stores item', () => {
|
|
112
|
+
const item = curriculum.registerPrinciple('brain', 'error-handling', 'Always validate input', 0.8);
|
|
113
|
+
expect(item.id).toBeDefined();
|
|
114
|
+
expect(item.brainName).toBe('brain');
|
|
115
|
+
expect(item.domain).toBe('error-handling');
|
|
116
|
+
expect(item.strength).toBe(0.8);
|
|
117
|
+
expect(item.teachable).toBe(false);
|
|
118
|
+
});
|
|
119
|
+
it('getTeachable returns only teachable items', () => {
|
|
120
|
+
const item1 = curriculum.registerPrinciple('brain', 'd1', 'P1', 0.9);
|
|
121
|
+
curriculum.registerPrinciple('brain', 'd2', 'P2', 0.7);
|
|
122
|
+
// Nothing teachable yet
|
|
123
|
+
expect(curriculum.getTeachable('brain').length).toBe(0);
|
|
124
|
+
// Mark one as teachable
|
|
125
|
+
curriculum.markTeachable(item1.id);
|
|
126
|
+
const teachable = curriculum.getTeachable('brain');
|
|
127
|
+
expect(teachable.length).toBe(1);
|
|
128
|
+
expect(teachable[0].principle).toBe('P1');
|
|
129
|
+
expect(teachable[0].teachable).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
it('getStatus returns summary', () => {
|
|
132
|
+
curriculum.registerPrinciple('brain', 'd1', 'P1', 0.9);
|
|
133
|
+
curriculum.registerPrinciple('trading-brain', 'd2', 'P2', 0.7);
|
|
134
|
+
const item3 = curriculum.registerPrinciple('brain', 'd3', 'P3', 0.6);
|
|
135
|
+
curriculum.markTeachable(item3.id);
|
|
136
|
+
const status = curriculum.getStatus();
|
|
137
|
+
expect(status.totalPrinciples).toBe(3);
|
|
138
|
+
expect(status.teachableCount).toBe(1);
|
|
139
|
+
expect(status.byBrain['brain']).toBe(2);
|
|
140
|
+
expect(status.byBrain['trading-brain']).toBe(1);
|
|
141
|
+
});
|
|
142
|
+
it('migration is idempotent (curriculum)', () => {
|
|
143
|
+
runCurriculumMigration(db);
|
|
144
|
+
runCurriculumMigration(db);
|
|
145
|
+
const tables = db
|
|
146
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='curriculum_items'")
|
|
147
|
+
.all();
|
|
148
|
+
expect(tables.length).toBe(1);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=teaching.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teaching.test.js","sourceRoot":"","sources":["../../../src/teaching/__tests__/teaching.test.ts"],"names":[],"mappings":"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"}
|