hippo-memory 0.30.1 → 0.31.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 +6 -0
- package/dist/cli.js +36 -13
- package/dist/cli.js.map +1 -1
- package/dist/scope.d.ts +14 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +35 -0
- package/dist/scope.js.map +1 -0
- package/dist/search.d.ts +6 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +13 -0
- package/dist/search.js.map +1 -1
- package/dist/shared.d.ts +2 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +3 -3
- package/dist/shared.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,12 @@ hippo recall "data pipeline issues" --budget 2000
|
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
63
|
+
### What's new in v0.31.0
|
|
64
|
+
|
|
65
|
+
- **Scope-aware corrections.** Tag a memory with `hippo remember --scope plan-eng-review` and it only surfaces strongly when that scope is active again. Matching scope gets 1.5x boost, mismatching scope is suppressed 0.5x, unscoped memories stay neutral. Corrections said during one skill stop polluting unrelated contexts.
|
|
66
|
+
- **Auto-detect from env.** `HIPPO_SCOPE`, `GSTACK_SKILL`, `OPENCLAW_SKILL` populate the scope automatically. Explicit `--scope` on any command overrides.
|
|
67
|
+
- **`hippo explain --why`** now shows the `scope:` multiplier when it fires, so you can see why a memory got ranked up or down.
|
|
68
|
+
|
|
63
69
|
### What's new in v0.30.1
|
|
64
70
|
|
|
65
71
|
- **`hippo recall --layer <L>` is now a strict filter.** Previously the flag was accepted but silently dropped; other layers leaked into results. The RSI demo's `recall --layer trace` now does what it says.
|
package/dist/cli.js
CHANGED
|
@@ -44,6 +44,7 @@ import { openHippoDb, closeHippoDb } from './db.js';
|
|
|
44
44
|
import { captureError, extractLessons, deduplicateLesson, runWatched, fetchGitLog, isGitRepo, } from './autolearn.js';
|
|
45
45
|
import { extractInvalidationTarget, invalidateMatching } from './invalidation.js';
|
|
46
46
|
import { extractPathTags } from './path-context.js';
|
|
47
|
+
import { detectScope, scopeMatch } from './scope.js';
|
|
47
48
|
import { getGlobalRoot, initGlobal, promoteToGlobal, shareMemory, listPeers, autoShare, transferScore, searchBothHybrid, syncGlobalToLocal, } from './shared.js';
|
|
48
49
|
import { DAILY_TASK_NAME, buildDailyRunnerCommand, listRegisteredWorkspaces, registerWorkspace, runDailyMaintenance, } from './scheduler.js';
|
|
49
50
|
import { importChatGPT, importClaude, importCursor, importGenericFile, importMarkdown, } from './importers.js';
|
|
@@ -413,6 +414,14 @@ function cmdRemember(hippoRoot, text, flags) {
|
|
|
413
414
|
if (!entry.tags.includes(pt))
|
|
414
415
|
entry.tags.push(pt);
|
|
415
416
|
}
|
|
417
|
+
// Scope tagging: explicit --scope or auto-detected
|
|
418
|
+
const explicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
419
|
+
const activeScope = explicitScope || detectScope();
|
|
420
|
+
if (activeScope) {
|
|
421
|
+
const scopeTag = `scope:${activeScope}`;
|
|
422
|
+
if (!entry.tags.includes(scopeTag))
|
|
423
|
+
entry.tags.push(scopeTag);
|
|
424
|
+
}
|
|
416
425
|
writeEntry(targetRoot, entry);
|
|
417
426
|
updateStats(targetRoot, { remembered: 1 });
|
|
418
427
|
const prefix = useGlobal ? '[global] ' : '';
|
|
@@ -459,6 +468,8 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
459
468
|
const minResults = flags['min-results'] !== undefined
|
|
460
469
|
? parseInt(String(flags['min-results']), 10)
|
|
461
470
|
: undefined;
|
|
471
|
+
const recallExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
472
|
+
const recallActiveScope = recallExplicitScope || detectScope();
|
|
462
473
|
let results;
|
|
463
474
|
if (usePhysics && !hasGlobal) {
|
|
464
475
|
results = await physicsSearch(query, localEntries, {
|
|
@@ -466,17 +477,18 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
466
477
|
hippoRoot,
|
|
467
478
|
physicsConfig: config.physics,
|
|
468
479
|
minResults,
|
|
480
|
+
scope: recallActiveScope,
|
|
469
481
|
});
|
|
470
482
|
}
|
|
471
483
|
else if (hasGlobal) {
|
|
472
484
|
// Use searchBothHybrid for merged results with embedding support
|
|
473
485
|
results = await searchBothHybrid(query, hippoRoot, globalRoot, {
|
|
474
|
-
budget, mmr: mmrEnabled, mmrLambda, localBump, minResults,
|
|
486
|
+
budget, mmr: mmrEnabled, mmrLambda, localBump, minResults, scope: recallActiveScope,
|
|
475
487
|
});
|
|
476
488
|
}
|
|
477
489
|
else {
|
|
478
490
|
results = await hybridSearch(query, localEntries, {
|
|
479
|
-
budget, hippoRoot, mmr: mmrEnabled, mmrLambda, minResults,
|
|
491
|
+
budget, hippoRoot, mmr: mmrEnabled, mmrLambda, minResults, scope: recallActiveScope,
|
|
480
492
|
});
|
|
481
493
|
}
|
|
482
494
|
// --outcome filter: drop trace entries whose trace_outcome !== target.
|
|
@@ -602,6 +614,8 @@ async function cmdExplain(hippoRoot, query, flags) {
|
|
|
602
614
|
: flags['local-bump'] !== undefined
|
|
603
615
|
? parseFloat(String(flags['local-bump']))
|
|
604
616
|
: config.search.localBump;
|
|
617
|
+
const explainExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
618
|
+
const explainActiveScope = explainExplicitScope || detectScope();
|
|
605
619
|
let results;
|
|
606
620
|
let modeUsed;
|
|
607
621
|
if (usePhysics && !hasGlobal) {
|
|
@@ -610,18 +624,19 @@ async function cmdExplain(hippoRoot, query, flags) {
|
|
|
610
624
|
hippoRoot,
|
|
611
625
|
physicsConfig: config.physics,
|
|
612
626
|
explain: true,
|
|
627
|
+
scope: explainActiveScope,
|
|
613
628
|
});
|
|
614
629
|
modeUsed = 'physics';
|
|
615
630
|
}
|
|
616
631
|
else if (hasGlobal) {
|
|
617
632
|
results = await searchBothHybrid(query, hippoRoot, globalRoot, {
|
|
618
|
-
budget, explain: true, mmr: mmrEnabled, mmrLambda, localBump,
|
|
633
|
+
budget, explain: true, mmr: mmrEnabled, mmrLambda, localBump, scope: explainActiveScope,
|
|
619
634
|
});
|
|
620
635
|
modeUsed = 'searchBothHybrid';
|
|
621
636
|
}
|
|
622
637
|
else {
|
|
623
638
|
results = await hybridSearch(query, localEntries, {
|
|
624
|
-
budget, hippoRoot, explain: true, mmr: mmrEnabled, mmrLambda,
|
|
639
|
+
budget, hippoRoot, explain: true, mmr: mmrEnabled, mmrLambda, scope: explainActiveScope,
|
|
625
640
|
});
|
|
626
641
|
modeUsed = 'hybrid';
|
|
627
642
|
}
|
|
@@ -691,6 +706,8 @@ async function cmdExplain(hippoRoot, query, flags) {
|
|
|
691
706
|
console.log(` recency: x${fmt(b.recencyMultiplier, 3)} (age=${b.ageDays}d)`);
|
|
692
707
|
if (b.decisionBoost !== 1)
|
|
693
708
|
console.log(` decision: x${fmt(b.decisionBoost, 2)} (tagged 'decision')`);
|
|
709
|
+
if (b.scopeBoost !== 1)
|
|
710
|
+
console.log(` scope: x${fmt(b.scopeBoost, 2)} (scope tag ${b.scopeBoost > 1 ? 'match' : 'mismatch'})`);
|
|
694
711
|
if (b.pathBoost !== 1)
|
|
695
712
|
console.log(` path: x${fmt(b.pathBoost, 3)} (cwd path tag overlap)`);
|
|
696
713
|
if (b.sourceBump !== 1)
|
|
@@ -2190,6 +2207,8 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
2190
2207
|
}
|
|
2191
2208
|
const budget = parseInt(String(flags['budget'] ?? '1500'), 10);
|
|
2192
2209
|
const limit = parseLimitFlag(flags['limit']);
|
|
2210
|
+
const ctxExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
2211
|
+
const ctxActiveScope = ctxExplicitScope || detectScope();
|
|
2193
2212
|
// If budget is 0, skip entirely (zero token cost)
|
|
2194
2213
|
if (budget <= 0)
|
|
2195
2214
|
return;
|
|
@@ -2239,12 +2258,16 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
2239
2258
|
...pinnedLocal.map((e) => ({ entry: e, isGlobal: false })),
|
|
2240
2259
|
...pinnedGlobal.map((e) => ({ entry: e, isGlobal: true })),
|
|
2241
2260
|
]
|
|
2242
|
-
.map(({ entry, isGlobal }) =>
|
|
2243
|
-
entry,
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2261
|
+
.map(({ entry, isGlobal }) => {
|
|
2262
|
+
const scopeSig = scopeMatch(entry.tags, ctxActiveScope);
|
|
2263
|
+
const sBst = scopeSig === 1 ? 1.5 : scopeSig === -1 ? 0.5 : 1.0;
|
|
2264
|
+
return {
|
|
2265
|
+
entry,
|
|
2266
|
+
score: calculateStrength(entry, nowP) * (isGlobal ? 1 / 1.2 : 1) * sBst,
|
|
2267
|
+
tokens: estimateTokens(entry.content),
|
|
2268
|
+
isGlobal,
|
|
2269
|
+
};
|
|
2270
|
+
})
|
|
2248
2271
|
.sort((a, b) => b.score - a.score);
|
|
2249
2272
|
let usedP = 0;
|
|
2250
2273
|
for (const r of rankedPinned) {
|
|
@@ -2287,7 +2310,7 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
2287
2310
|
else {
|
|
2288
2311
|
let results;
|
|
2289
2312
|
if (hasGlobal) {
|
|
2290
|
-
const merged = await searchBothHybrid(query, hippoRoot, globalRoot, { budget });
|
|
2313
|
+
const merged = await searchBothHybrid(query, hippoRoot, globalRoot, { budget, scope: ctxActiveScope });
|
|
2291
2314
|
const localIndex = loadIndex(hippoRoot);
|
|
2292
2315
|
results = merged.map((r) => ({
|
|
2293
2316
|
entry: r.entry,
|
|
@@ -2300,8 +2323,8 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
2300
2323
|
const ctxConfig = loadConfig(hippoRoot);
|
|
2301
2324
|
const usePhysicsCtx = ctxConfig.physics?.enabled !== false;
|
|
2302
2325
|
const ctxResults = usePhysicsCtx
|
|
2303
|
-
? await physicsSearch(query, localEntries, { budget, hippoRoot, physicsConfig: ctxConfig.physics })
|
|
2304
|
-
: await hybridSearch(query, localEntries, { budget, hippoRoot });
|
|
2326
|
+
? await physicsSearch(query, localEntries, { budget, hippoRoot, physicsConfig: ctxConfig.physics, scope: ctxActiveScope })
|
|
2327
|
+
: await hybridSearch(query, localEntries, { budget, hippoRoot, scope: ctxActiveScope });
|
|
2305
2328
|
results = ctxResults.map((r) => ({
|
|
2306
2329
|
entry: r.entry,
|
|
2307
2330
|
score: r.score,
|