@morningljn/mnemo 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +2 -0
- package/dist/config.js +28 -0
- package/dist/config.js.map +1 -0
- package/dist/dream-engine.d.ts +17 -0
- package/dist/dream-engine.js +144 -0
- package/dist/dream-engine.js.map +1 -0
- package/dist/dream.d.ts +2 -0
- package/dist/dream.js +20 -0
- package/dist/dream.js.map +1 -0
- package/dist/init.js +4 -24
- package/dist/init.js.map +1 -1
- package/dist/llm-client.d.ts +10 -0
- package/dist/llm-client.js +55 -0
- package/dist/llm-client.js.map +1 -0
- package/dist/resources.d.ts +22 -8
- package/dist/resources.js +66 -20
- package/dist/resources.js.map +1 -1
- package/dist/retriever.js +12 -5
- package/dist/retriever.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +2 -2
- package/dist/server.js +40 -6
- package/dist/server.js.map +1 -1
- package/dist/store.d.ts +23 -1
- package/dist/store.js +169 -4
- package/dist/store.js.map +1 -1
- package/dist/types.d.ts +41 -1
- package/docs/superpowers/plans/2026-05-16-llm-dream.md +973 -0
- package/docs/superpowers/plans/2026-05-16-memory-dreaming.md +626 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/design.md +71 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/proposal.md +32 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/specs/compact-search/spec.md +16 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/specs/dream-cycle/spec.md +38 -0
- package/openspec/changes/archive/2026-05-16-memory-dreaming/tasks.md +27 -0
- package/openspec/changes/llm-dream/.openspec.yaml +2 -0
- package/openspec/changes/llm-dream/design.md +84 -0
- package/openspec/changes/llm-dream/proposal.md +36 -0
- package/openspec/changes/llm-dream/specs/dream-cycle/spec.md +42 -0
- package/openspec/changes/llm-dream/specs/llm-client/spec.md +57 -0
- package/openspec/changes/llm-dream/specs/llm-dream-engine/spec.md +72 -0
- package/openspec/changes/llm-dream/tasks.md +32 -0
- package/openspec/specs/compact-search/spec.md +16 -0
- package/openspec/specs/dream-cycle/spec.md +38 -0
- package/package.json +3 -2
- package/src/config.ts +29 -0
- package/src/dream-engine.ts +162 -0
- package/src/dream.ts +20 -0
- package/src/init.ts +4 -24
- package/src/llm-client.ts +59 -0
- package/src/resources.ts +77 -21
- package/src/retriever.ts +9 -5
- package/src/schema.ts +2 -2
- package/src/server.ts +46 -7
- package/src/store.ts +198 -5
- package/src/types.ts +41 -1
- package/tests/dream-engine.test.ts +163 -0
- package/tests/llm-client.test.ts +105 -0
- package/tests/resource.test.ts +25 -23
- package/tests/store.test.ts +130 -2
package/tests/store.test.ts
CHANGED
|
@@ -153,15 +153,31 @@ describe('logRetrieval', () => {
|
|
|
153
153
|
})
|
|
154
154
|
|
|
155
155
|
describe('runLearning', () => {
|
|
156
|
-
it('demotes
|
|
156
|
+
it('demotes moderate retrieval low helpful facts', () => {
|
|
157
157
|
const id = store.addFact('demote me', 'general')
|
|
158
|
-
store.connection.prepare('UPDATE facts SET retrieval_count =
|
|
158
|
+
store.connection.prepare('UPDATE facts SET retrieval_count = 50, helpful_count = 1, trust_score = 1.0 WHERE fact_id = ?').run(id)
|
|
159
159
|
const result = store.runLearning()
|
|
160
160
|
const row = store.connection.prepare('SELECT trust_score FROM facts WHERE fact_id = ?').get(id) as any
|
|
161
161
|
expect(row.trust_score).toBeLessThan(1.0)
|
|
162
162
|
expect(result.demoted).toBeGreaterThanOrEqual(1)
|
|
163
163
|
})
|
|
164
164
|
|
|
165
|
+
it('protects high frequency facts from demotion', () => {
|
|
166
|
+
const id = store.addFact('高频角色设定', 'identity')
|
|
167
|
+
store.connection.prepare('UPDATE facts SET retrieval_count = 200, helpful_count = 2, trust_score = 0.9 WHERE fact_id = ?').run(id)
|
|
168
|
+
store.runLearning()
|
|
169
|
+
const row = store.connection.prepare('SELECT trust_score FROM facts WHERE fact_id = ?').get(id) as any
|
|
170
|
+
expect(row.trust_score).toBe(0.9)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('still demotes moderate frequency facts with low trust', () => {
|
|
174
|
+
const id = store.addFact('中频低信任', 'general')
|
|
175
|
+
store.connection.prepare('UPDATE facts SET retrieval_count = 50, helpful_count = 0, trust_score = 0.3 WHERE fact_id = ?').run(id)
|
|
176
|
+
store.runLearning()
|
|
177
|
+
const row = store.connection.prepare('SELECT trust_score FROM facts WHERE fact_id = ?').get(id) as any
|
|
178
|
+
expect(row.trust_score).toBeLessThan(0.3)
|
|
179
|
+
})
|
|
180
|
+
|
|
165
181
|
it('promotes high helpful rate facts', () => {
|
|
166
182
|
const id = store.addFact('promote me', 'general')
|
|
167
183
|
store.connection.prepare('UPDATE facts SET retrieval_count = 50, helpful_count = 20, trust_score = 0.5 WHERE fact_id = ?').run(id)
|
|
@@ -214,3 +230,115 @@ describe('runAudit', () => {
|
|
|
214
230
|
expect(report.long_without_summary.length).toBeGreaterThanOrEqual(1)
|
|
215
231
|
})
|
|
216
232
|
})
|
|
233
|
+
|
|
234
|
+
describe('dream - backup', () => {
|
|
235
|
+
it('creates backup before dream', async () => {
|
|
236
|
+
store.addFact('test fact for backup', 'general')
|
|
237
|
+
const result = await store.backupDatabase()
|
|
238
|
+
expect(result).toBeTruthy()
|
|
239
|
+
expect(result).toContain('dream-')
|
|
240
|
+
expect(result).toContain('.db')
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
describe('dream - compress', () => {
|
|
245
|
+
it('generates summary for long facts without summary', () => {
|
|
246
|
+
const longContent = '用户偏好使用 TypeScript 开发前端项目。偏好 React 框架进行组件化开发。' + '额外补充说明'.repeat(50)
|
|
247
|
+
store.addFact(longContent, 'coding_style')
|
|
248
|
+
const result = store.compressLongFacts()
|
|
249
|
+
expect(result).toBeGreaterThanOrEqual(1)
|
|
250
|
+
const row = store.connection.prepare('SELECT summary FROM facts WHERE content = ?').get(longContent) as any
|
|
251
|
+
expect(row.summary).toBeTruthy()
|
|
252
|
+
expect(row.summary.length).toBeLessThanOrEqual(150)
|
|
253
|
+
expect(row.summary).toContain('TypeScript')
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('skips facts with existing summary', () => {
|
|
257
|
+
const longContent = 'x'.repeat(300)
|
|
258
|
+
const id = store.addFact(longContent, 'general')
|
|
259
|
+
store.connection.prepare('UPDATE facts SET summary = ? WHERE fact_id = ?').run('existing summary', id)
|
|
260
|
+
const result = store.compressLongFacts()
|
|
261
|
+
expect(result).toBe(0)
|
|
262
|
+
const row = store.connection.prepare('SELECT summary FROM facts WHERE fact_id = ?').get(id) as any
|
|
263
|
+
expect(row.summary).toBe('existing summary')
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
it('skips short facts', () => {
|
|
267
|
+
store.addFact('short fact', 'general')
|
|
268
|
+
const result = store.compressLongFacts()
|
|
269
|
+
expect(result).toBe(0)
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
describe('dream - merge', () => {
|
|
274
|
+
it('merges overlapping facts in same category', () => {
|
|
275
|
+
store.addFact('用户偏好使用 TypeScript 编写前端代码', 'coding_style')
|
|
276
|
+
store.addFact('用户偏好使用 TypeScript 编写后端代码', 'coding_style')
|
|
277
|
+
const result = store.mergeOverlappingFacts()
|
|
278
|
+
expect(result.merged).toBeGreaterThanOrEqual(1)
|
|
279
|
+
expect(result.details.length).toBeGreaterThanOrEqual(1)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('protects high frequency facts from deletion', () => {
|
|
283
|
+
const id1 = store.addFact('用户偏好使用 TypeScript 编写前端代码', 'coding_style')
|
|
284
|
+
const id2 = store.addFact('用户偏好使用 TypeScript 编写前端代码扩展', 'coding_style')
|
|
285
|
+
store.connection.prepare('UPDATE facts SET retrieval_count = 200 WHERE fact_id = ?').run(id1)
|
|
286
|
+
const result = store.mergeOverlappingFacts()
|
|
287
|
+
const kept = store.connection.prepare('SELECT fact_id FROM facts WHERE fact_id = ?').get(id1) as any
|
|
288
|
+
expect(kept).toBeTruthy()
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('does not merge facts across categories', () => {
|
|
292
|
+
store.addFact('用户偏好使用 TypeScript 编写前端代码', 'coding_style')
|
|
293
|
+
store.addFact('用户偏好使用 TypeScript 编写前端代码', 'general')
|
|
294
|
+
const result = store.mergeOverlappingFacts()
|
|
295
|
+
expect(result.merged).toBe(0)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
it('does not merge when both facts are high frequency', () => {
|
|
299
|
+
const id1 = store.addFact('高频测试事实 AAA 长内容匹配', 'coding_style')
|
|
300
|
+
const id2 = store.addFact('高频测试事实 BBB 长内容匹配', 'coding_style')
|
|
301
|
+
store.connection.prepare('UPDATE facts SET retrieval_count = 200 WHERE fact_id IN (?, ?)').run(id1, id2)
|
|
302
|
+
const result = store.mergeOverlappingFacts()
|
|
303
|
+
// Both facts should still exist
|
|
304
|
+
const row1 = store.connection.prepare('SELECT fact_id FROM facts WHERE fact_id = ?').get(id1) as any
|
|
305
|
+
const row2 = store.connection.prepare('SELECT fact_id FROM facts WHERE fact_id = ?').get(id2) as any
|
|
306
|
+
expect(row1).toBeTruthy()
|
|
307
|
+
expect(row2).toBeTruthy()
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
describe('dream - reclassify', () => {
|
|
312
|
+
it('moves miscategorized facts from general to correct category', () => {
|
|
313
|
+
const id = store.addFact('编码规范:文件不超过 500 行', 'general')
|
|
314
|
+
const result = store.reclassifyFacts()
|
|
315
|
+
expect(result).toBeGreaterThanOrEqual(1)
|
|
316
|
+
const row = store.connection.prepare('SELECT category FROM facts WHERE fact_id = ?').get(id) as any
|
|
317
|
+
expect(row.category).toBe('coding_style')
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
it('skips already categorized facts', () => {
|
|
321
|
+
store.addFact('编码规范:文件不超过 500 行', 'coding_style')
|
|
322
|
+
const result = store.reclassifyFacts()
|
|
323
|
+
expect(result).toBe(0)
|
|
324
|
+
})
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
describe('dream - runDream', () => {
|
|
328
|
+
it('runs full dream cycle and returns report', async () => {
|
|
329
|
+
// 长文 fact(触发压缩)
|
|
330
|
+
store.addFact('用户偏好使用 TypeScript 开发前端。使用 React 框架。' + 'x'.repeat(250), 'coding_style')
|
|
331
|
+
// 重叠 fact(触发合并)
|
|
332
|
+
store.addFact('用户偏好使用 TypeScript 开发前端代码', 'coding_style')
|
|
333
|
+
// 分类错误 fact(触发重分类)
|
|
334
|
+
store.addFact('编码规范:文件不超过 500 行', 'general')
|
|
335
|
+
|
|
336
|
+
const report = await store.runDream({ skipBackup: true })
|
|
337
|
+
expect(report.compressed).toBeGreaterThanOrEqual(0)
|
|
338
|
+
expect(report.merged).toBeGreaterThanOrEqual(0)
|
|
339
|
+
expect(report.reclassified).toBeGreaterThanOrEqual(0)
|
|
340
|
+
expect(report.health.total).toBeGreaterThanOrEqual(1)
|
|
341
|
+
expect(report.health.coverage).toBeTruthy()
|
|
342
|
+
expect(report.fallback).toBe(true) // 测试环境无 Ollama,应降级到规则引擎
|
|
343
|
+
})
|
|
344
|
+
})
|