@cleocode/core 2026.4.37 → 2026.4.39
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/hooks/handlers/task-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/task-hooks.js +11 -0
- package/dist/hooks/handlers/task-hooks.js.map +1 -1
- package/dist/index.js +1048 -33
- package/dist/index.js.map +4 -4
- package/dist/internal.d.ts +3 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -1
- package/dist/internal.js.map +1 -1
- package/dist/memory/brain-lifecycle.d.ts +2 -0
- package/dist/memory/brain-lifecycle.d.ts.map +1 -1
- package/dist/memory/decisions.d.ts.map +1 -1
- package/dist/memory/decisions.js +18 -0
- package/dist/memory/decisions.js.map +1 -1
- package/dist/memory/engine-compat.d.ts +17 -0
- package/dist/memory/engine-compat.d.ts.map +1 -1
- package/dist/memory/engine-compat.js +36 -0
- package/dist/memory/engine-compat.js.map +1 -1
- package/dist/memory/graph-memory-bridge.d.ts +158 -0
- package/dist/memory/graph-memory-bridge.d.ts.map +1 -0
- package/dist/memory/graph-memory-bridge.js +519 -0
- package/dist/memory/graph-memory-bridge.js.map +1 -0
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/learnings.d.ts.map +1 -1
- package/dist/memory/learnings.js +18 -0
- package/dist/memory/learnings.js.map +1 -1
- package/dist/memory/llm-extraction.js.map +1 -1
- package/dist/memory/patterns.d.ts.map +1 -1
- package/dist/memory/patterns.js +18 -0
- package/dist/memory/patterns.js.map +1 -1
- package/dist/memory/quality-feedback.d.ts +129 -0
- package/dist/memory/quality-feedback.d.ts.map +1 -0
- package/dist/memory/quality-feedback.js +449 -0
- package/dist/memory/quality-feedback.js.map +1 -0
- package/dist/memory/sleep-consolidation.d.ts +98 -0
- package/dist/memory/sleep-consolidation.d.ts.map +1 -0
- package/dist/memory/sleep-consolidation.js +706 -0
- package/dist/memory/sleep-consolidation.js.map +1 -0
- package/dist/memory/temporal-supersession.d.ts +155 -0
- package/dist/memory/temporal-supersession.d.ts.map +1 -0
- package/dist/memory/temporal-supersession.js +406 -0
- package/dist/memory/temporal-supersession.js.map +1 -0
- package/dist/tasks/complete.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/hooks/handlers/task-hooks.ts +11 -0
- package/src/internal.ts +12 -0
- package/src/memory/__tests__/graph-memory-bridge.test.ts +357 -0
- package/src/memory/__tests__/llm-extraction.test.ts +17 -0
- package/src/memory/__tests__/quality-feedback.test.ts +418 -0
- package/src/memory/__tests__/sleep-consolidation.test.ts +790 -0
- package/src/memory/__tests__/temporal-supersession.test.ts +534 -0
- package/src/memory/brain-lifecycle.ts +13 -0
- package/src/memory/decisions.ts +24 -0
- package/src/memory/engine-compat.ts +37 -0
- package/src/memory/graph-memory-bridge.ts +751 -0
- package/src/memory/index.ts +2 -0
- package/src/memory/learnings.ts +24 -0
- package/src/memory/patterns.ts +24 -0
- package/src/memory/quality-feedback.ts +640 -0
- package/src/memory/sleep-consolidation.ts +932 -0
- package/src/memory/temporal-supersession.ts +568 -0
- package/src/store/__tests__/performance-safety.test.ts +4 -4
- package/src/tasks/complete.ts +20 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Quality Feedback Loop — BRAIN self-improvement system.
|
|
3
|
+
*
|
|
4
|
+
* Closes the retrieval→usage→outcome loop so that memory quality scores
|
|
5
|
+
* reflect real-world utility, not just insert-time heuristics.
|
|
6
|
+
*
|
|
7
|
+
* Three operations:
|
|
8
|
+
*
|
|
9
|
+
* 1. trackMemoryUsage — record whether a retrieved memory was actually used
|
|
10
|
+
* by an agent after task completion.
|
|
11
|
+
*
|
|
12
|
+
* 2. correlateOutcomes — scan the retrieval log, join against task outcomes,
|
|
13
|
+
* and apply quality adjustments:
|
|
14
|
+
* - Memory retrieved before a successful task completion: +0.05
|
|
15
|
+
* - Memory retrieved before a failed task: -0.05
|
|
16
|
+
* - Memory never retrieved in 30 days: flagged for pruning
|
|
17
|
+
*
|
|
18
|
+
* 3. getMemoryQualityReport — dashboard metrics over the entire brain.db.
|
|
19
|
+
*
|
|
20
|
+
* Schema addition: brain_usage_log (entry_id, task_id, used, outcome, created_at).
|
|
21
|
+
* The table is self-healing — created on first access.
|
|
22
|
+
*
|
|
23
|
+
* @task T555
|
|
24
|
+
*/
|
|
25
|
+
import { typedAll } from '../store/typed-query.js';
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Internal: schema bootstrap
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Ensure brain_usage_log exists. Safe to call multiple times — uses
|
|
31
|
+
* CREATE TABLE IF NOT EXISTS. Returns silently on error (best-effort).
|
|
32
|
+
*/
|
|
33
|
+
async function ensureUsageLogTable(projectRoot) {
|
|
34
|
+
const { getBrainDb, getBrainNativeDb } = await import('../store/brain-sqlite.js');
|
|
35
|
+
await getBrainDb(projectRoot);
|
|
36
|
+
const nativeDb = getBrainNativeDb();
|
|
37
|
+
if (!nativeDb)
|
|
38
|
+
return;
|
|
39
|
+
try {
|
|
40
|
+
nativeDb
|
|
41
|
+
.prepare(`CREATE TABLE IF NOT EXISTS brain_usage_log (
|
|
42
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
43
|
+
entry_id TEXT NOT NULL,
|
|
44
|
+
task_id TEXT,
|
|
45
|
+
used INTEGER NOT NULL DEFAULT 0,
|
|
46
|
+
outcome TEXT NOT NULL DEFAULT 'unknown',
|
|
47
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
48
|
+
)`)
|
|
49
|
+
.run();
|
|
50
|
+
// Index to speed up correlateOutcomes JOIN on entry_id.
|
|
51
|
+
nativeDb
|
|
52
|
+
.prepare(`CREATE INDEX IF NOT EXISTS idx_brain_usage_log_entry_id
|
|
53
|
+
ON brain_usage_log(entry_id)`)
|
|
54
|
+
.run();
|
|
55
|
+
// Index to speed up pruning scan (entries never retrieved).
|
|
56
|
+
nativeDb
|
|
57
|
+
.prepare(`CREATE INDEX IF NOT EXISTS idx_brain_usage_log_task_id
|
|
58
|
+
ON brain_usage_log(task_id)`)
|
|
59
|
+
.run();
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// best-effort: DDL failures are non-fatal
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Ensure prune_candidate column exists on all typed brain tables.
|
|
67
|
+
* Added lazily so existing schemas are not broken.
|
|
68
|
+
*/
|
|
69
|
+
async function ensurePruneCandidateColumn(projectRoot) {
|
|
70
|
+
const { getBrainDb, getBrainNativeDb } = await import('../store/brain-sqlite.js');
|
|
71
|
+
await getBrainDb(projectRoot);
|
|
72
|
+
const nativeDb = getBrainNativeDb();
|
|
73
|
+
if (!nativeDb)
|
|
74
|
+
return;
|
|
75
|
+
const tables = [
|
|
76
|
+
'brain_decisions',
|
|
77
|
+
'brain_patterns',
|
|
78
|
+
'brain_learnings',
|
|
79
|
+
'brain_observations',
|
|
80
|
+
];
|
|
81
|
+
for (const tbl of tables) {
|
|
82
|
+
try {
|
|
83
|
+
nativeDb.prepare(`ALTER TABLE ${tbl} ADD COLUMN prune_candidate INTEGER DEFAULT 0`).run();
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Column already exists — silently continue
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// 1. trackMemoryUsage
|
|
92
|
+
// ============================================================================
|
|
93
|
+
/**
|
|
94
|
+
* Record whether a retrieved memory entry was actually used by an agent.
|
|
95
|
+
*
|
|
96
|
+
* Call this after task completion, once the agent has decided which retrieved
|
|
97
|
+
* entries were referenced. Inserts a row into brain_usage_log; the
|
|
98
|
+
* correlateOutcomes pass will read these rows to adjust quality scores.
|
|
99
|
+
*
|
|
100
|
+
* @param projectRoot - Project root directory
|
|
101
|
+
* @param memoryId - The brain entry ID (e.g. "O-...", "D-...", "P-...")
|
|
102
|
+
* @param used - Whether the agent actually used this entry
|
|
103
|
+
* @param taskId - Optional task ID for outcome correlation
|
|
104
|
+
* @param outcome - Optional task outcome; defaults to 'unknown' until correlated
|
|
105
|
+
*/
|
|
106
|
+
export async function trackMemoryUsage(projectRoot, memoryId, used, taskId, outcome = 'unknown') {
|
|
107
|
+
if (!memoryId?.trim())
|
|
108
|
+
return;
|
|
109
|
+
await ensureUsageLogTable(projectRoot);
|
|
110
|
+
const { getBrainNativeDb } = await import('../store/brain-sqlite.js');
|
|
111
|
+
const nativeDb = getBrainNativeDb();
|
|
112
|
+
if (!nativeDb)
|
|
113
|
+
return;
|
|
114
|
+
const now = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
115
|
+
try {
|
|
116
|
+
nativeDb
|
|
117
|
+
.prepare(`INSERT INTO brain_usage_log (entry_id, task_id, used, outcome, created_at)
|
|
118
|
+
VALUES (?, ?, ?, ?, ?)`)
|
|
119
|
+
.run(memoryId, taskId ?? null, used ? 1 : 0, outcome, now);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// best-effort
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// 2. correlateOutcomes
|
|
127
|
+
// ============================================================================
|
|
128
|
+
/**
|
|
129
|
+
* Resolve the table name for a brain entry based on its ID prefix.
|
|
130
|
+
*/
|
|
131
|
+
function tableForId(id) {
|
|
132
|
+
if (id.startsWith('D-') || /^D\d/.test(id))
|
|
133
|
+
return 'brain_decisions';
|
|
134
|
+
if (id.startsWith('P-') || /^P\d/.test(id))
|
|
135
|
+
return 'brain_patterns';
|
|
136
|
+
if (id.startsWith('L-') || /^L\d/.test(id))
|
|
137
|
+
return 'brain_learnings';
|
|
138
|
+
if (id.startsWith('O-') || id.startsWith('CM-') || /^O/.test(id))
|
|
139
|
+
return 'brain_observations';
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Apply a quality delta (+0.05 or -0.05) to a brain entry, clamped to [0.0, 1.0].
|
|
144
|
+
*/
|
|
145
|
+
function applyQualityDelta(nativeDb, table, id, delta, now) {
|
|
146
|
+
if (!nativeDb)
|
|
147
|
+
return;
|
|
148
|
+
try {
|
|
149
|
+
nativeDb
|
|
150
|
+
.prepare(`UPDATE ${table}
|
|
151
|
+
SET quality_score = MAX(0.0, MIN(1.0, COALESCE(quality_score, 0.5) + ?)),
|
|
152
|
+
updated_at = ?
|
|
153
|
+
WHERE id = ?`)
|
|
154
|
+
.run(delta, now, id);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// best-effort: column may differ in older schemas
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Analyse the retrieval log and usage log against task outcomes, then
|
|
162
|
+
* adjust quality scores to reflect real-world utility.
|
|
163
|
+
*
|
|
164
|
+
* Algorithm:
|
|
165
|
+
* 1. Read brain_usage_log where outcome != 'unknown' — these are rows
|
|
166
|
+
* already tagged with a definitive outcome.
|
|
167
|
+
* 2. For success rows: boost quality_score by +0.05 for each entry used.
|
|
168
|
+
* 3. For failure rows: penalise quality_score by -0.05 for each entry used.
|
|
169
|
+
* 4. Flag entries whose citation_count = 0 AND last retrieval (if any) is
|
|
170
|
+
* older than 30 days as prune candidates.
|
|
171
|
+
*
|
|
172
|
+
* This is designed to be idempotent — running it twice on the same data
|
|
173
|
+
* applies the delta twice (small, intentional drift toward ground truth).
|
|
174
|
+
* Callers should schedule it once per session end or per task batch.
|
|
175
|
+
*
|
|
176
|
+
* @param projectRoot - Project root directory
|
|
177
|
+
* @returns Summary of changes made
|
|
178
|
+
*/
|
|
179
|
+
export async function correlateOutcomes(projectRoot) {
|
|
180
|
+
await ensureUsageLogTable(projectRoot);
|
|
181
|
+
await ensurePruneCandidateColumn(projectRoot);
|
|
182
|
+
const { getBrainDb, getBrainNativeDb } = await import('../store/brain-sqlite.js');
|
|
183
|
+
await getBrainDb(projectRoot);
|
|
184
|
+
const nativeDb = getBrainNativeDb();
|
|
185
|
+
const ranAt = new Date().toISOString();
|
|
186
|
+
if (!nativeDb) {
|
|
187
|
+
return { boosted: 0, penalized: 0, flaggedForPruning: 0, ranAt };
|
|
188
|
+
}
|
|
189
|
+
const now = ranAt.replace('T', ' ').slice(0, 19);
|
|
190
|
+
let boosted = 0;
|
|
191
|
+
let penalized = 0;
|
|
192
|
+
// Aggregate: for each (entry_id, outcome) pair sum the 'used' flags so we
|
|
193
|
+
// do a single UPDATE per entry rather than one per log row.
|
|
194
|
+
let usageRows = [];
|
|
195
|
+
try {
|
|
196
|
+
usageRows = typedAll(nativeDb.prepare(`SELECT entry_id, outcome, SUM(used) AS used_count
|
|
197
|
+
FROM brain_usage_log
|
|
198
|
+
WHERE outcome IN ('success', 'failure')
|
|
199
|
+
GROUP BY entry_id, outcome`));
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// brain_usage_log may not exist yet on this DB — treat as empty
|
|
203
|
+
usageRows = [];
|
|
204
|
+
}
|
|
205
|
+
for (const row of usageRows) {
|
|
206
|
+
const table = tableForId(row.entry_id);
|
|
207
|
+
if (!table)
|
|
208
|
+
continue;
|
|
209
|
+
if (row.outcome === 'success' && row.used_count > 0) {
|
|
210
|
+
applyQualityDelta(nativeDb, table, row.entry_id, 0.05, now);
|
|
211
|
+
boosted++;
|
|
212
|
+
}
|
|
213
|
+
else if (row.outcome === 'failure' && row.used_count > 0) {
|
|
214
|
+
applyQualityDelta(nativeDb, table, row.entry_id, -0.05, now);
|
|
215
|
+
penalized++;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// ---- Step 2: flag stale entries for pruning ----
|
|
219
|
+
const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
|
|
220
|
+
.toISOString()
|
|
221
|
+
.replace('T', ' ')
|
|
222
|
+
.slice(0, 19);
|
|
223
|
+
let flaggedForPruning = 0;
|
|
224
|
+
const pruneTargetTables = [
|
|
225
|
+
{ table: 'brain_decisions', dateCol: 'created_at' },
|
|
226
|
+
{ table: 'brain_patterns', dateCol: 'extracted_at' },
|
|
227
|
+
{ table: 'brain_learnings', dateCol: 'created_at' },
|
|
228
|
+
{ table: 'brain_observations', dateCol: 'created_at' },
|
|
229
|
+
];
|
|
230
|
+
for (const { table, dateCol } of pruneTargetTables) {
|
|
231
|
+
try {
|
|
232
|
+
// Entries with zero citation_count whose creation date is older than 30 days.
|
|
233
|
+
const result = nativeDb
|
|
234
|
+
.prepare(`UPDATE ${table}
|
|
235
|
+
SET prune_candidate = 1
|
|
236
|
+
WHERE COALESCE(citation_count, 0) = 0
|
|
237
|
+
AND ${dateCol} < ?`)
|
|
238
|
+
.run(cutoffDate);
|
|
239
|
+
flaggedForPruning += result.changes ?? 0;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// best-effort
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return { boosted, penalized, flaggedForPruning, ranAt };
|
|
246
|
+
}
|
|
247
|
+
// ============================================================================
|
|
248
|
+
// 3. getMemoryQualityReport
|
|
249
|
+
// ============================================================================
|
|
250
|
+
/**
|
|
251
|
+
* Return dashboard-level quality metrics for the BRAIN memory system.
|
|
252
|
+
*
|
|
253
|
+
* Aggregates across all four typed tables (decisions, patterns, learnings,
|
|
254
|
+
* observations) and the retrieval log to produce a single report object.
|
|
255
|
+
*
|
|
256
|
+
* @param projectRoot - Project root directory
|
|
257
|
+
* @returns Quality metrics report
|
|
258
|
+
*/
|
|
259
|
+
export async function getMemoryQualityReport(projectRoot) {
|
|
260
|
+
await ensureUsageLogTable(projectRoot);
|
|
261
|
+
const { getBrainDb, getBrainNativeDb } = await import('../store/brain-sqlite.js');
|
|
262
|
+
await getBrainDb(projectRoot);
|
|
263
|
+
const nativeDb = getBrainNativeDb();
|
|
264
|
+
const emptyReport = {
|
|
265
|
+
totalRetrievals: 0,
|
|
266
|
+
uniqueEntriesRetrieved: 0,
|
|
267
|
+
usageRate: 0,
|
|
268
|
+
topRetrieved: [],
|
|
269
|
+
neverRetrieved: [],
|
|
270
|
+
qualityDistribution: { low: 0, medium: 0, high: 0 },
|
|
271
|
+
tierDistribution: { short: 0, medium: 0, long: 0, unknown: 0 },
|
|
272
|
+
noiseRatio: 0,
|
|
273
|
+
};
|
|
274
|
+
if (!nativeDb)
|
|
275
|
+
return emptyReport;
|
|
276
|
+
let totalRetrievals = 0;
|
|
277
|
+
let uniqueEntriesRetrieved = 0;
|
|
278
|
+
try {
|
|
279
|
+
const logCount = typedAll(nativeDb.prepare('SELECT COUNT(*) AS cnt FROM brain_retrieval_log'));
|
|
280
|
+
totalRetrievals = logCount[0]?.cnt ?? 0;
|
|
281
|
+
const uniqueCount = typedAll(nativeDb.prepare(`SELECT COUNT(DISTINCT value) AS cnt
|
|
282
|
+
FROM brain_retrieval_log,
|
|
283
|
+
json_each('["' || replace(entry_ids, ',', '","') || '"]')`));
|
|
284
|
+
uniqueEntriesRetrieved = uniqueCount[0]?.cnt ?? 0;
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// brain_retrieval_log not yet created — harmless
|
|
288
|
+
}
|
|
289
|
+
// ---- Usage rate ----
|
|
290
|
+
let usageRate = 0;
|
|
291
|
+
try {
|
|
292
|
+
const totalUsage = typedAll(nativeDb.prepare('SELECT COUNT(*) AS cnt FROM brain_usage_log'));
|
|
293
|
+
const usedCount = typedAll(nativeDb.prepare('SELECT COUNT(*) AS cnt FROM brain_usage_log WHERE used = 1'));
|
|
294
|
+
const total = totalUsage[0]?.cnt ?? 0;
|
|
295
|
+
const used = usedCount[0]?.cnt ?? 0;
|
|
296
|
+
usageRate = total > 0 ? used / total : 0;
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// brain_usage_log not yet created
|
|
300
|
+
}
|
|
301
|
+
const topRetrieved = [];
|
|
302
|
+
try {
|
|
303
|
+
const rows = typedAll(nativeDb.prepare(`SELECT id,
|
|
304
|
+
'decision' AS type,
|
|
305
|
+
decision AS title,
|
|
306
|
+
COALESCE(citation_count, 0) AS citation_count
|
|
307
|
+
FROM brain_decisions
|
|
308
|
+
UNION ALL
|
|
309
|
+
SELECT id,
|
|
310
|
+
'pattern' AS type,
|
|
311
|
+
pattern AS title,
|
|
312
|
+
COALESCE(citation_count, 0) AS citation_count
|
|
313
|
+
FROM brain_patterns
|
|
314
|
+
UNION ALL
|
|
315
|
+
SELECT id,
|
|
316
|
+
'learning' AS type,
|
|
317
|
+
insight AS title,
|
|
318
|
+
COALESCE(citation_count, 0) AS citation_count
|
|
319
|
+
FROM brain_learnings
|
|
320
|
+
UNION ALL
|
|
321
|
+
SELECT id,
|
|
322
|
+
'observation' AS type,
|
|
323
|
+
title AS title,
|
|
324
|
+
COALESCE(citation_count, 0) AS citation_count
|
|
325
|
+
FROM brain_observations
|
|
326
|
+
ORDER BY citation_count DESC
|
|
327
|
+
LIMIT 10`));
|
|
328
|
+
for (const r of rows) {
|
|
329
|
+
topRetrieved.push({
|
|
330
|
+
id: r.id,
|
|
331
|
+
type: r.type,
|
|
332
|
+
title: String(r.title ?? '').slice(0, 120),
|
|
333
|
+
citationCount: r.citation_count,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
// best-effort
|
|
339
|
+
}
|
|
340
|
+
const neverRetrieved = [];
|
|
341
|
+
try {
|
|
342
|
+
const rows = typedAll(nativeDb.prepare(`SELECT id,
|
|
343
|
+
'decision' AS type,
|
|
344
|
+
decision AS title,
|
|
345
|
+
COALESCE(quality_score, 0.5) AS quality_score
|
|
346
|
+
FROM brain_decisions
|
|
347
|
+
WHERE COALESCE(citation_count, 0) = 0
|
|
348
|
+
UNION ALL
|
|
349
|
+
SELECT id,
|
|
350
|
+
'pattern' AS type,
|
|
351
|
+
pattern AS title,
|
|
352
|
+
COALESCE(quality_score, 0.5) AS quality_score
|
|
353
|
+
FROM brain_patterns
|
|
354
|
+
WHERE COALESCE(citation_count, 0) = 0
|
|
355
|
+
UNION ALL
|
|
356
|
+
SELECT id,
|
|
357
|
+
'learning' AS type,
|
|
358
|
+
insight AS title,
|
|
359
|
+
COALESCE(quality_score, 0.5) AS quality_score
|
|
360
|
+
FROM brain_learnings
|
|
361
|
+
WHERE COALESCE(citation_count, 0) = 0
|
|
362
|
+
UNION ALL
|
|
363
|
+
SELECT id,
|
|
364
|
+
'observation' AS type,
|
|
365
|
+
title AS title,
|
|
366
|
+
COALESCE(quality_score, 0.5) AS quality_score
|
|
367
|
+
FROM brain_observations
|
|
368
|
+
WHERE COALESCE(citation_count, 0) = 0
|
|
369
|
+
ORDER BY quality_score ASC
|
|
370
|
+
LIMIT 10`));
|
|
371
|
+
for (const r of rows) {
|
|
372
|
+
neverRetrieved.push({
|
|
373
|
+
id: r.id,
|
|
374
|
+
type: r.type,
|
|
375
|
+
title: String(r.title ?? '').slice(0, 120),
|
|
376
|
+
qualityScore: r.quality_score,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
// best-effort
|
|
382
|
+
}
|
|
383
|
+
let qualityDistribution = { low: 0, medium: 0, high: 0 };
|
|
384
|
+
try {
|
|
385
|
+
const rows = typedAll(nativeDb.prepare(`SELECT
|
|
386
|
+
SUM(CASE WHEN qs < 0.3 THEN 1 ELSE 0 END) AS low,
|
|
387
|
+
SUM(CASE WHEN qs >= 0.3 AND qs <= 0.6 THEN 1 ELSE 0 END) AS medium,
|
|
388
|
+
SUM(CASE WHEN qs > 0.6 THEN 1 ELSE 0 END) AS high
|
|
389
|
+
FROM (
|
|
390
|
+
SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_decisions
|
|
391
|
+
UNION ALL
|
|
392
|
+
SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_patterns
|
|
393
|
+
UNION ALL
|
|
394
|
+
SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_learnings
|
|
395
|
+
UNION ALL
|
|
396
|
+
SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_observations
|
|
397
|
+
)`));
|
|
398
|
+
if (rows[0]) {
|
|
399
|
+
qualityDistribution = {
|
|
400
|
+
low: rows[0].low ?? 0,
|
|
401
|
+
medium: rows[0].medium ?? 0,
|
|
402
|
+
high: rows[0].high ?? 0,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
catch {
|
|
407
|
+
// best-effort
|
|
408
|
+
}
|
|
409
|
+
const tierDistribution = { short: 0, medium: 0, long: 0, unknown: 0 };
|
|
410
|
+
try {
|
|
411
|
+
const rows = typedAll(nativeDb.prepare(`SELECT memory_tier AS tier, COUNT(*) AS cnt
|
|
412
|
+
FROM (
|
|
413
|
+
SELECT memory_tier FROM brain_decisions
|
|
414
|
+
UNION ALL
|
|
415
|
+
SELECT memory_tier FROM brain_patterns
|
|
416
|
+
UNION ALL
|
|
417
|
+
SELECT memory_tier FROM brain_learnings
|
|
418
|
+
UNION ALL
|
|
419
|
+
SELECT memory_tier FROM brain_observations
|
|
420
|
+
)
|
|
421
|
+
GROUP BY memory_tier`));
|
|
422
|
+
for (const r of rows) {
|
|
423
|
+
const tier = r.tier?.toLowerCase() ?? 'unknown';
|
|
424
|
+
if (tier === 'short' || tier === 'medium' || tier === 'long') {
|
|
425
|
+
tierDistribution[tier] += r.cnt;
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
tierDistribution.unknown += r.cnt;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
// memory_tier column may not exist on older schemas
|
|
434
|
+
}
|
|
435
|
+
// ---- Noise ratio ----
|
|
436
|
+
const totalEntries = qualityDistribution.low + qualityDistribution.medium + qualityDistribution.high;
|
|
437
|
+
const noiseRatio = totalEntries > 0 ? qualityDistribution.low / totalEntries : 0;
|
|
438
|
+
return {
|
|
439
|
+
totalRetrievals,
|
|
440
|
+
uniqueEntriesRetrieved,
|
|
441
|
+
usageRate,
|
|
442
|
+
topRetrieved,
|
|
443
|
+
neverRetrieved,
|
|
444
|
+
qualityDistribution,
|
|
445
|
+
tierDistribution,
|
|
446
|
+
noiseRatio,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=quality-feedback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality-feedback.js","sourceRoot":"","sources":["../../src/memory/quality-feedback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sleep-Time Consolidation — LLM-driven background memory hygiene for CLEO BRAIN.
|
|
3
|
+
*
|
|
4
|
+
* Implements the "sleep-time compute" pattern inspired by Letta OS: after a
|
|
5
|
+
* session ends, a cheap LLM pass runs in the background to:
|
|
6
|
+
* 1. Merge near-duplicate entries (embedding similarity > 0.85)
|
|
7
|
+
* 2. Prune short-tier stale entries with low quality (7d old, quality < 0.4)
|
|
8
|
+
* 3. Synthesize frequently-cited learnings into higher-quality patterns
|
|
9
|
+
* 4. Extract cross-cutting insights from clusters of related observations
|
|
10
|
+
*
|
|
11
|
+
* All LLM calls use `claude-haiku-4-5-20251001` (cheapest available model).
|
|
12
|
+
* No API key = silent no-op for LLM steps; structural steps still run.
|
|
13
|
+
* All errors are caught and logged — nothing here may block session end.
|
|
14
|
+
*
|
|
15
|
+
* ## Configuration
|
|
16
|
+
*
|
|
17
|
+
* Add to `config.json` under `brain.sleepConsolidation`:
|
|
18
|
+
* ```json
|
|
19
|
+
* {
|
|
20
|
+
* "brain": {
|
|
21
|
+
* "sleepConsolidation": {
|
|
22
|
+
* "enabled": true
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @task T555
|
|
29
|
+
* @epic T549
|
|
30
|
+
* @see packages/core/src/memory/observer-reflector.ts (Observer/Reflector pattern)
|
|
31
|
+
* @see packages/core/src/memory/brain-lifecycle.ts (runConsolidation)
|
|
32
|
+
*/
|
|
33
|
+
/** Count of changes from the merge-duplicates step. */
|
|
34
|
+
export interface MergeDuplicatesResult {
|
|
35
|
+
/** Number of duplicate entries merged (soft-evicted clones). */
|
|
36
|
+
merged: number;
|
|
37
|
+
/** Number of LLM merge decisions made. */
|
|
38
|
+
llmDecisions: number;
|
|
39
|
+
}
|
|
40
|
+
/** Count of changes from the prune-stale step. */
|
|
41
|
+
export interface PruneStaleResult {
|
|
42
|
+
/** Number of entries soft-evicted. */
|
|
43
|
+
pruned: number;
|
|
44
|
+
/** Number of entries the LLM decided to preserve. */
|
|
45
|
+
preserved: number;
|
|
46
|
+
}
|
|
47
|
+
/** Count of changes from the strengthen-patterns step. */
|
|
48
|
+
export interface StrengthenPatternsResult {
|
|
49
|
+
/** Number of high-citation learnings synthesized. */
|
|
50
|
+
synthesized: number;
|
|
51
|
+
/** Number of new patterns generated. */
|
|
52
|
+
patternsGenerated: number;
|
|
53
|
+
}
|
|
54
|
+
/** Count of changes from the generate-insights step. */
|
|
55
|
+
export interface GenerateInsightsResult {
|
|
56
|
+
/** Number of observation clusters processed. */
|
|
57
|
+
clustersProcessed: number;
|
|
58
|
+
/** Number of new insight observations stored. */
|
|
59
|
+
insightsStored: number;
|
|
60
|
+
}
|
|
61
|
+
/** Aggregated result from the full sleep consolidation run. */
|
|
62
|
+
export interface SleepConsolidationResult {
|
|
63
|
+
/** Whether the run was enabled and fully attempted. */
|
|
64
|
+
ran: boolean;
|
|
65
|
+
/** Step 1: merge duplicates. */
|
|
66
|
+
mergeDuplicates: MergeDuplicatesResult;
|
|
67
|
+
/** Step 2: prune stale entries. */
|
|
68
|
+
pruneStale: PruneStaleResult;
|
|
69
|
+
/** Step 3: strengthen frequently-cited patterns. */
|
|
70
|
+
strengthenPatterns: StrengthenPatternsResult;
|
|
71
|
+
/** Step 4: generate cross-cutting insights. */
|
|
72
|
+
generateInsights: GenerateInsightsResult;
|
|
73
|
+
}
|
|
74
|
+
/** Sleep consolidation configuration resolved from config.json. */
|
|
75
|
+
export interface SleepConsolidationConfig {
|
|
76
|
+
enabled: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Run the full sleep-time consolidation pipeline for CLEO BRAIN.
|
|
80
|
+
*
|
|
81
|
+
* This is the main entry point for LLM-driven background memory hygiene.
|
|
82
|
+
* It is designed to run after session end (via setImmediate) and must never
|
|
83
|
+
* throw — all errors are caught and logged.
|
|
84
|
+
*
|
|
85
|
+
* Steps (in order):
|
|
86
|
+
* 1. Merge duplicates — embedding-similarity-based dedup with LLM confirmation
|
|
87
|
+
* 2. Prune stale — evict low-quality short-tier entries; LLM may preserve some
|
|
88
|
+
* 3. Strengthen patterns — synthesize frequently-cited learnings into patterns
|
|
89
|
+
* 4. Generate insights — extract cross-cutting insights from observation clusters
|
|
90
|
+
*
|
|
91
|
+
* Graceful degradation: when no Anthropic API key is available, LLM steps
|
|
92
|
+
* silently skip their LLM call and fall back to structural heuristics.
|
|
93
|
+
*
|
|
94
|
+
* @param projectRoot - Project root directory for brain.db resolution.
|
|
95
|
+
* @returns Aggregated result counts from each step.
|
|
96
|
+
*/
|
|
97
|
+
export declare function runSleepConsolidation(projectRoot: string): Promise<SleepConsolidationResult>;
|
|
98
|
+
//# sourceMappingURL=sleep-consolidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sleep-consolidation.d.ts","sourceRoot":"","sources":["../../src/memory/sleep-consolidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AA0EH,uDAAuD;AACvD,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,wBAAwB;IACvC,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,wDAAwD;AACxD,MAAM,WAAW,sBAAsB;IACrC,gDAAgD;IAChD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,+DAA+D;AAC/D,MAAM,WAAW,wBAAwB;IACvC,uDAAuD;IACvD,GAAG,EAAE,OAAO,CAAC;IACb,gCAAgC;IAChC,eAAe,EAAE,qBAAqB,CAAC;IACvC,mCAAmC;IACnC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,oDAAoD;IACpD,kBAAkB,EAAE,wBAAwB,CAAC;IAC7C,+CAA+C;IAC/C,gBAAgB,EAAE,sBAAsB,CAAC;CAC1C;AAMD,mEAAmE;AACnE,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;CAClB;AAsrBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,wBAAwB,CAAC,CA0DnC"}
|