hippo-memory 0.32.0 ā 0.33.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/README.md +8 -0
- package/dist/cli.js +83 -8
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -0
- package/dist/config.js.map +1 -1
- package/dist/consolidate.d.ts +5 -1
- package/dist/consolidate.d.ts.map +1 -1
- package/dist/consolidate.js +64 -10
- package/dist/consolidate.js.map +1 -1
- package/dist/dag.d.ts +20 -0
- package/dist/dag.d.ts.map +1 -0
- package/dist/dag.js +104 -0
- package/dist/dag.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +23 -1
- package/dist/db.js.map +1 -1
- package/dist/extract.d.ts +14 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +87 -0
- package/dist/extract.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +6 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +3 -0
- package/dist/memory.js.map +1 -1
- package/dist/multihop.d.ts +11 -0
- package/dist/multihop.d.ts.map +1 -0
- package/dist/multihop.js +32 -0
- package/dist/multihop.js.map +1 -0
- package/dist/search.d.ts +9 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +140 -7
- package/dist/search.js.map +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +14 -3
- package/dist/store.js.map +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,6 +60,14 @@ hippo recall "data pipeline issues" --budget 2000
|
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
63
|
+
### What's new in v0.33.0
|
|
64
|
+
|
|
65
|
+
- **Fact extraction at sleep time.** `hippo sleep` now extracts standalone facts from episodic memories via LLM, stored as semantic-layer entries that score 1.3x higher and auto-deduplicate against their raw source in search results.
|
|
66
|
+
- **DAG summarization.** Extracted facts cluster by entity similarity into summary nodes. When a summary matches your query, its children drill down into results automatically.
|
|
67
|
+
- **Multi-hop retrieval.** `hippo recall --multihop` chains two search passes via entity tags discovered in the first pass, finding connections that single-pass search misses.
|
|
68
|
+
- **`hippo dag --stats`** shows how your memory is organized across DAG levels.
|
|
69
|
+
- **Performance fix.** Temporal scoring refactored from O(N^2) to O(N), eliminating stack overflow risk on large stores.
|
|
70
|
+
|
|
63
71
|
### What's new in v0.32.0
|
|
64
72
|
|
|
65
73
|
- **Correction without deletion.** `hippo supersede <old-id> "<new content>"` links the old memory as historical truth and creates a successor. Default recall shows only current beliefs; the old one stays in the store so you can audit what changed and when.
|
package/dist/cli.js
CHANGED
|
@@ -53,6 +53,7 @@ import { auditMemories } from './audit.js';
|
|
|
53
53
|
import { runEval, bootstrapCorpus, compareSummaries } from './eval.js';
|
|
54
54
|
import { refineStore } from './refine-llm.js';
|
|
55
55
|
import { wmPush, wmRead, wmClear, wmFlush } from './working-memory.js';
|
|
56
|
+
import { multihopSearch } from './multihop.js';
|
|
56
57
|
// ---------------------------------------------------------------------------
|
|
57
58
|
// Helpers
|
|
58
59
|
// ---------------------------------------------------------------------------
|
|
@@ -377,7 +378,7 @@ function setupDailySchedule(globalRoot) {
|
|
|
377
378
|
}
|
|
378
379
|
}
|
|
379
380
|
}
|
|
380
|
-
function cmdRemember(hippoRoot, text, flags) {
|
|
381
|
+
async function cmdRemember(hippoRoot, text, flags) {
|
|
381
382
|
const useGlobal = Boolean(flags['global']);
|
|
382
383
|
const targetRoot = useGlobal ? getGlobalRoot() : hippoRoot;
|
|
383
384
|
if (useGlobal) {
|
|
@@ -437,6 +438,28 @@ function cmdRemember(hippoRoot, text, flags) {
|
|
|
437
438
|
// Silently ignore embedding errors
|
|
438
439
|
});
|
|
439
440
|
}
|
|
441
|
+
const config = loadConfig(targetRoot);
|
|
442
|
+
const shouldExtract = flags['extract'] || config.extraction.enabled === true;
|
|
443
|
+
const apiKey = process.env.ANTHROPIC_API_KEY ?? '';
|
|
444
|
+
if (shouldExtract && apiKey) {
|
|
445
|
+
try {
|
|
446
|
+
const { extractFacts, storeExtractedFacts } = await import('./extract.js');
|
|
447
|
+
const facts = await extractFacts(entry.content, {
|
|
448
|
+
apiKey,
|
|
449
|
+
model: config.extraction.model,
|
|
450
|
+
});
|
|
451
|
+
if (facts.length > 0) {
|
|
452
|
+
storeExtractedFacts(targetRoot, entry, facts);
|
|
453
|
+
console.error(` extracted ${facts.length} fact(s)`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
catch {
|
|
457
|
+
// Extraction is best-effort ā never block remember
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
else if (shouldExtract && !apiKey) {
|
|
461
|
+
console.error(' (extraction skipped: ANTHROPIC_API_KEY not set)');
|
|
462
|
+
}
|
|
440
463
|
}
|
|
441
464
|
function cmdSupersede(hippoRoot, oldId, newContent, flags) {
|
|
442
465
|
requireInit(hippoRoot);
|
|
@@ -535,8 +558,19 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
535
558
|
: undefined;
|
|
536
559
|
const recallExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
537
560
|
const recallActiveScope = recallExplicitScope || detectScope();
|
|
561
|
+
const useMultihop = flags['multihop'] === true || config.multihop.enabled;
|
|
538
562
|
let results;
|
|
539
|
-
if (
|
|
563
|
+
if (useMultihop) {
|
|
564
|
+
const allEntries = [...localEntries, ...globalEntries];
|
|
565
|
+
results = multihopSearch(query, allEntries, {
|
|
566
|
+
budget,
|
|
567
|
+
hippoRoot,
|
|
568
|
+
minResults,
|
|
569
|
+
includeSuperseded,
|
|
570
|
+
asOf,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
else if (usePhysics && !hasGlobal) {
|
|
540
574
|
results = await physicsSearch(query, localEntries, {
|
|
541
575
|
budget,
|
|
542
576
|
hippoRoot,
|
|
@@ -1296,7 +1330,7 @@ function cmdDedup(hippoRoot, flags) {
|
|
|
1296
1330
|
console.log(` ... and ${result.pairs.length - 15} more (run with --dry-run to see all)`);
|
|
1297
1331
|
}
|
|
1298
1332
|
}
|
|
1299
|
-
function cmdSleep(hippoRoot, flags) {
|
|
1333
|
+
async function cmdSleep(hippoRoot, flags) {
|
|
1300
1334
|
// Tee stdout/stderr to a log file when --log-file is set. The SessionEnd
|
|
1301
1335
|
// hook uses this so the output is captured somewhere the SessionStart hook
|
|
1302
1336
|
// can re-display it next time the agent UI starts.
|
|
@@ -1335,7 +1369,7 @@ function cmdSleep(hippoRoot, flags) {
|
|
|
1335
1369
|
}
|
|
1336
1370
|
}
|
|
1337
1371
|
try {
|
|
1338
|
-
cmdSleepCore(hippoRoot, flags);
|
|
1372
|
+
await cmdSleepCore(hippoRoot, flags);
|
|
1339
1373
|
if (logFile)
|
|
1340
1374
|
console.log('[hippo] sleep complete');
|
|
1341
1375
|
}
|
|
@@ -1349,7 +1383,7 @@ function cmdSleep(hippoRoot, flags) {
|
|
|
1349
1383
|
restoreStdout();
|
|
1350
1384
|
}
|
|
1351
1385
|
}
|
|
1352
|
-
function cmdSleepCore(hippoRoot, flags) {
|
|
1386
|
+
async function cmdSleepCore(hippoRoot, flags) {
|
|
1353
1387
|
requireInit(hippoRoot);
|
|
1354
1388
|
// Auto-learn from git before consolidating (unless --no-learn)
|
|
1355
1389
|
if (!flags['no-learn']) {
|
|
@@ -1366,7 +1400,7 @@ function cmdSleepCore(hippoRoot, flags) {
|
|
|
1366
1400
|
}
|
|
1367
1401
|
const dryRun = Boolean(flags['dry-run']);
|
|
1368
1402
|
console.log(`Running consolidation${dryRun ? ' (dry run)' : ''}...`);
|
|
1369
|
-
const result = consolidate(hippoRoot, { dryRun });
|
|
1403
|
+
const result = await consolidate(hippoRoot, { dryRun });
|
|
1370
1404
|
console.log(`\nResults:`);
|
|
1371
1405
|
console.log(` Active memories: ${result.decayed}`);
|
|
1372
1406
|
console.log(` Removed (decayed): ${result.removed}`);
|
|
@@ -3374,6 +3408,44 @@ function cmdWm(hippoRoot, args, flags) {
|
|
|
3374
3408
|
console.error('Usage: hippo wm <push|read|clear|flush>');
|
|
3375
3409
|
process.exit(1);
|
|
3376
3410
|
}
|
|
3411
|
+
function cmdDag(hippoRoot, flags) {
|
|
3412
|
+
requireInit(hippoRoot);
|
|
3413
|
+
const entries = loadAllEntries(hippoRoot);
|
|
3414
|
+
const isStats = flags['stats'] === true;
|
|
3415
|
+
const byLevel = new Map();
|
|
3416
|
+
let unlinked = 0;
|
|
3417
|
+
for (const entry of entries) {
|
|
3418
|
+
const level = entry.dag_level ?? 0;
|
|
3419
|
+
byLevel.set(level, (byLevel.get(level) ?? 0) + 1);
|
|
3420
|
+
if (level === 1 && !entry.dag_parent_id)
|
|
3421
|
+
unlinked++;
|
|
3422
|
+
}
|
|
3423
|
+
if (isStats) {
|
|
3424
|
+
console.log('DAG Structure:');
|
|
3425
|
+
console.log(` Level 3 (entity profiles): ${byLevel.get(3) ?? 0}`);
|
|
3426
|
+
console.log(` Level 2 (topic summaries): ${byLevel.get(2) ?? 0}`);
|
|
3427
|
+
console.log(` Level 1 (extracted facts): ${byLevel.get(1) ?? 0}`);
|
|
3428
|
+
console.log(` Level 0 (raw memories): ${byLevel.get(0) ?? 0}`);
|
|
3429
|
+
console.log(` Unlinked facts: ${unlinked}`);
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
// Tree view: show summaries and their children
|
|
3433
|
+
const summaries = entries.filter((e) => e.dag_level === 2);
|
|
3434
|
+
if (summaries.length === 0) {
|
|
3435
|
+
console.log('No DAG summaries yet. Run `hippo sleep` with ANTHROPIC_API_KEY set.');
|
|
3436
|
+
return;
|
|
3437
|
+
}
|
|
3438
|
+
for (const summary of summaries) {
|
|
3439
|
+
const summaryTags = summary.tags.filter((t) => t !== 'dag-summary').join(', ');
|
|
3440
|
+
console.log(`\nš ${summary.content.slice(0, 80)}`);
|
|
3441
|
+
if (summaryTags)
|
|
3442
|
+
console.log(` [${summaryTags}]`);
|
|
3443
|
+
const children = entries.filter((e) => e.dag_parent_id === summary.id);
|
|
3444
|
+
for (const child of children) {
|
|
3445
|
+
console.log(` āā ${child.content.slice(0, 70)}`);
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3377
3449
|
function printUsage() {
|
|
3378
3450
|
console.log(`
|
|
3379
3451
|
Hippo - biologically-inspired memory system for AI agents
|
|
@@ -3638,7 +3710,7 @@ async function main() {
|
|
|
3638
3710
|
console.error('Memory content too short (minimum 3 characters).');
|
|
3639
3711
|
process.exit(1);
|
|
3640
3712
|
}
|
|
3641
|
-
cmdRemember(hippoRoot, text, flags);
|
|
3713
|
+
await cmdRemember(hippoRoot, text, flags);
|
|
3642
3714
|
break;
|
|
3643
3715
|
}
|
|
3644
3716
|
case 'recall': {
|
|
@@ -3691,7 +3763,7 @@ async function main() {
|
|
|
3691
3763
|
await cmdRefine(hippoRoot, flags);
|
|
3692
3764
|
break;
|
|
3693
3765
|
case 'sleep':
|
|
3694
|
-
cmdSleep(hippoRoot, flags);
|
|
3766
|
+
await cmdSleep(hippoRoot, flags);
|
|
3695
3767
|
break;
|
|
3696
3768
|
case 'last-sleep':
|
|
3697
3769
|
cmdLastSleep(flags);
|
|
@@ -3711,6 +3783,9 @@ async function main() {
|
|
|
3711
3783
|
case 'dedup':
|
|
3712
3784
|
cmdDedup(hippoRoot, flags);
|
|
3713
3785
|
break;
|
|
3786
|
+
case 'dag':
|
|
3787
|
+
cmdDag(hippoRoot, flags);
|
|
3788
|
+
break;
|
|
3714
3789
|
case 'audit': {
|
|
3715
3790
|
requireInit(hippoRoot);
|
|
3716
3791
|
const entries = loadAllEntries(hippoRoot);
|