hippo-memory 1.61.0 → 1.62.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 +28 -53
- package/dist/agent-memories/apply.d.ts +1 -1
- package/dist/agent-memories/claude-code.d.ts +3 -1
- package/dist/agent-memories/claude-code.js +53 -9
- package/dist/agent-memories/sync.d.ts +3 -3
- package/dist/agent-memories/sync.js +14 -6
- package/dist/agent-memories/types.d.ts +0 -2
- package/dist/api/assemble.js +55 -54
- package/dist/api/context-select.d.ts +49 -0
- package/dist/api/context-select.js +344 -0
- package/dist/api/context.d.ts +2 -2
- package/dist/api/context.js +195 -522
- package/dist/api/drill-down.js +36 -33
- package/dist/api/promote.js +55 -66
- package/dist/api/recall.js +303 -438
- package/dist/api/sleep.js +203 -218
- package/dist/capture/compact.d.ts +1 -1
- package/dist/capture/compact.js +2 -2
- package/dist/cli/briefs.js +324 -306
- package/dist/cli/context.js +44 -34
- package/dist/cli/continuity.js +283 -271
- package/dist/cli/curate.js +35 -34
- package/dist/cli/decisions.js +333 -333
- package/dist/cli/explain.js +66 -60
- package/dist/cli/maintenance.js +62 -51
- package/dist/cli/playbooks.js +387 -370
- package/dist/cli/projects.js +8 -5
- package/dist/cli/recall.js +28 -43
- package/dist/cli/remember.js +113 -70
- package/dist/cli/session-hooks.js +100 -90
- package/dist/cli/setup.js +267 -246
- package/dist/cli/status.js +73 -64
- package/dist/cli/transfer.js +85 -99
- package/dist/compaction-record.d.ts +0 -2
- package/dist/compaction-record.js +1 -1
- package/dist/customer-notes.js +77 -68
- package/dist/dag.js +222 -186
- package/dist/decisions.js +93 -76
- package/dist/doctor.js +11 -7
- package/dist/goals.js +99 -86
- package/dist/incidents.js +45 -38
- package/dist/policies.js +85 -68
- package/dist/processes.js +87 -71
- package/dist/project-briefs.js +135 -108
- package/dist/project-merge.d.ts +12 -4
- package/dist/project-merge.js +130 -45
- package/dist/shared.d.ts +9 -0
- package/dist/shared.js +10 -8
- package/dist/skills.js +81 -65
- package/dist/store/search-rows.d.ts +2 -2
- package/dist/store/search-rows.js +15 -9
- package/dist/version.d.ts +1 -1
- package/dist/version.js +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/dist/cli/explain.js
CHANGED
|
@@ -57,31 +57,39 @@ export async function cmdExplain(hippoRoot, query, flags) {
|
|
|
57
57
|
const results = dropHeldCopies(rank.results, (r) => r.entry);
|
|
58
58
|
const candidates = rank.localEntries.length + rank.globalEntries.length;
|
|
59
59
|
if (asJson) {
|
|
60
|
-
|
|
61
|
-
rank: rank + 1,
|
|
62
|
-
id: r.entry.id,
|
|
63
|
-
layer: r.entry.layer,
|
|
64
|
-
confidence: confidenceFacets(r.entry).tier,
|
|
65
|
-
aged_out: confidenceFacets(r.entry).agedOut,
|
|
66
|
-
score: r.score,
|
|
67
|
-
tokens: r.tokens,
|
|
68
|
-
tags: r.entry.tags,
|
|
69
|
-
content: r.entry.content,
|
|
70
|
-
breakdown: r.breakdown,
|
|
71
|
-
}));
|
|
72
|
-
console.log(JSON.stringify({
|
|
73
|
-
query,
|
|
74
|
-
mode: modeUsed,
|
|
75
|
-
candidates,
|
|
76
|
-
returned: output.length,
|
|
77
|
-
results: output,
|
|
78
|
-
}));
|
|
60
|
+
printExplainJson(results, query, modeUsed, candidates);
|
|
79
61
|
return;
|
|
80
62
|
}
|
|
81
63
|
if (results.length === 0) {
|
|
82
64
|
console.log(`No memories matched "${query}" (scanned ${candidates}).`);
|
|
83
65
|
return;
|
|
84
66
|
}
|
|
67
|
+
printExplainTable(results, query, modeUsed, candidates);
|
|
68
|
+
results.forEach((r, i) => printExplainBreakdown(r, i));
|
|
69
|
+
console.log('Note: explain does not mark memories as retrieved (read-only).');
|
|
70
|
+
}
|
|
71
|
+
function printExplainJson(results, query, modeUsed, candidates) {
|
|
72
|
+
const output = results.map((r, rank) => ({
|
|
73
|
+
rank: rank + 1,
|
|
74
|
+
id: r.entry.id,
|
|
75
|
+
layer: r.entry.layer,
|
|
76
|
+
confidence: confidenceFacets(r.entry).tier,
|
|
77
|
+
aged_out: confidenceFacets(r.entry).agedOut,
|
|
78
|
+
score: r.score,
|
|
79
|
+
tokens: r.tokens,
|
|
80
|
+
tags: r.entry.tags,
|
|
81
|
+
content: r.entry.content,
|
|
82
|
+
breakdown: r.breakdown,
|
|
83
|
+
}));
|
|
84
|
+
console.log(JSON.stringify({
|
|
85
|
+
query,
|
|
86
|
+
mode: modeUsed,
|
|
87
|
+
candidates,
|
|
88
|
+
returned: output.length,
|
|
89
|
+
results: output,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
function printExplainTable(results, query, modeUsed, candidates) {
|
|
85
93
|
console.log(`Query: "${query}"`);
|
|
86
94
|
console.log(`Mode: ${modeUsed} candidates: ${candidates} returned: ${results.length}`);
|
|
87
95
|
console.log();
|
|
@@ -95,49 +103,47 @@ export async function cmdExplain(hippoRoot, query, flags) {
|
|
|
95
103
|
console.log(`${String(i + 1).padEnd(5)} ${fmt(r.score, 3).padEnd(7)} ${fmt(r.entry.strength).padEnd(9)} ${ageStr.padEnd(6)} ${r.entry.layer.padEnd(10)} ${r.entry.id.padEnd(17)} ${preview}`);
|
|
96
104
|
}
|
|
97
105
|
console.log();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
console.log();
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
if (b.mode === 'physics') {
|
|
108
|
-
console.log(` mode: physics-gravity`);
|
|
109
|
-
console.log(` cosine: ${fmt(b.cosine, 3)} (pre-amp baseline)`);
|
|
110
|
-
console.log(` final: ${fmt(b.final, 4)} (post-amp, from physics scorer)`);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
const matched = b.matchedTerms.length > 0 ? b.matchedTerms.join(', ') : '(none)';
|
|
114
|
-
console.log(` mode: ${b.mode}${b.mode === 'hybrid-no-vec' ? ' (no cached doc vector — run `hippo embed`)' : ''}`);
|
|
115
|
-
console.log(` BM25: raw=${fmt(r.bm25, 3)} normalized=${fmt(b.normBm25, 3)} weight=${fmt(b.bm25Weight, 2)} matched=[${matched}]`);
|
|
116
|
-
console.log(` embedding: cosine=${fmt(b.cosine, 3)} weight=${fmt(b.embeddingWeight, 2)}`);
|
|
117
|
-
console.log(` base: ${fmt(b.bm25Weight, 2)}*${fmt(b.normBm25, 3)} + ${fmt(b.embeddingWeight, 2)}*${fmt(b.cosine, 3)} = ${fmt(b.base, 4)}`);
|
|
118
|
-
console.log(` strength: x${fmt(b.strengthMultiplier, 3)} (strength=${fmt(r.entry.strength, 3)})`);
|
|
119
|
-
console.log(` recency: x${fmt(b.recencyMultiplier, 3)} (age=${b.ageDays}d)`);
|
|
120
|
-
if (b.decisionBoost !== 1)
|
|
121
|
-
console.log(` decision: x${fmt(b.decisionBoost, 2)} (tagged 'decision')`);
|
|
122
|
-
if (b.scopeBoost !== 1)
|
|
123
|
-
console.log(` scope: x${fmt(b.scopeBoost, 2)} (scope tag ${b.scopeBoost > 1 ? 'match' : 'mismatch'})`);
|
|
124
|
-
if (b.pathBoost !== 1)
|
|
125
|
-
console.log(` path: x${fmt(b.pathBoost, 3)} (cwd path tag overlap)`);
|
|
126
|
-
if (b.sourceBump !== 1)
|
|
127
|
-
console.log(` source: x${fmt(b.sourceBump, 2)} (local priority bump over global)`);
|
|
128
|
-
if (b.outcomeBoost !== 1)
|
|
129
|
-
console.log(` outcome: x${fmt(b.outcomeBoost, 3)} (user feedback: pos-neg = ${(r.entry.outcome_positive ?? 0) - (r.entry.outcome_negative ?? 0)})`);
|
|
130
|
-
if (b.churnStaleMultiplier !== 1)
|
|
131
|
-
console.log(` churn: x${fmt(b.churnStaleMultiplier, 2)} (tagged 'churn-stale')`);
|
|
132
|
-
if (b.preMmrRank !== undefined && b.postMmrRank !== undefined && b.preMmrRank !== b.postMmrRank) {
|
|
133
|
-
const arrow = b.postMmrRank < b.preMmrRank ? 'up' : 'down';
|
|
134
|
-
console.log(` mmr: rank ${b.preMmrRank} -> ${b.postMmrRank} (diversity ${arrow})`);
|
|
135
|
-
}
|
|
136
|
-
console.log(` final: ${fmt(b.final, 4)}`);
|
|
137
|
-
}
|
|
106
|
+
}
|
|
107
|
+
function printExplainBreakdown(r, i) {
|
|
108
|
+
const b = r.breakdown;
|
|
109
|
+
console.log(`[${i + 1}] ${r.entry.id} composite=${fmt(r.score, 4)}`);
|
|
110
|
+
if (!b) {
|
|
111
|
+
console.log(' (no breakdown available)');
|
|
138
112
|
console.log();
|
|
113
|
+
return;
|
|
139
114
|
}
|
|
140
|
-
|
|
115
|
+
if (b.mode === 'physics') {
|
|
116
|
+
console.log(` mode: physics-gravity`);
|
|
117
|
+
console.log(` cosine: ${fmt(b.cosine, 3)} (pre-amp baseline)`);
|
|
118
|
+
console.log(` final: ${fmt(b.final, 4)} (post-amp, from physics scorer)`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const matched = b.matchedTerms.length > 0 ? b.matchedTerms.join(', ') : '(none)';
|
|
122
|
+
console.log(` mode: ${b.mode}${b.mode === 'hybrid-no-vec' ? ' (no cached doc vector — run `hippo embed`)' : ''}`);
|
|
123
|
+
console.log(` BM25: raw=${fmt(r.bm25, 3)} normalized=${fmt(b.normBm25, 3)} weight=${fmt(b.bm25Weight, 2)} matched=[${matched}]`);
|
|
124
|
+
console.log(` embedding: cosine=${fmt(b.cosine, 3)} weight=${fmt(b.embeddingWeight, 2)}`);
|
|
125
|
+
console.log(` base: ${fmt(b.bm25Weight, 2)}*${fmt(b.normBm25, 3)} + ${fmt(b.embeddingWeight, 2)}*${fmt(b.cosine, 3)} = ${fmt(b.base, 4)}`);
|
|
126
|
+
console.log(` strength: x${fmt(b.strengthMultiplier, 3)} (strength=${fmt(r.entry.strength, 3)})`);
|
|
127
|
+
console.log(` recency: x${fmt(b.recencyMultiplier, 3)} (age=${b.ageDays}d)`);
|
|
128
|
+
if (b.decisionBoost !== 1)
|
|
129
|
+
console.log(` decision: x${fmt(b.decisionBoost, 2)} (tagged 'decision')`);
|
|
130
|
+
if (b.scopeBoost !== 1)
|
|
131
|
+
console.log(` scope: x${fmt(b.scopeBoost, 2)} (scope tag ${b.scopeBoost > 1 ? 'match' : 'mismatch'})`);
|
|
132
|
+
if (b.pathBoost !== 1)
|
|
133
|
+
console.log(` path: x${fmt(b.pathBoost, 3)} (cwd path tag overlap)`);
|
|
134
|
+
if (b.sourceBump !== 1)
|
|
135
|
+
console.log(` source: x${fmt(b.sourceBump, 2)} (local priority bump over global)`);
|
|
136
|
+
if (b.outcomeBoost !== 1)
|
|
137
|
+
console.log(` outcome: x${fmt(b.outcomeBoost, 3)} (user feedback: pos-neg = ${(r.entry.outcome_positive ?? 0) - (r.entry.outcome_negative ?? 0)})`);
|
|
138
|
+
if (b.churnStaleMultiplier !== 1)
|
|
139
|
+
console.log(` churn: x${fmt(b.churnStaleMultiplier, 2)} (tagged 'churn-stale')`);
|
|
140
|
+
if (b.preMmrRank !== undefined && b.postMmrRank !== undefined && b.preMmrRank !== b.postMmrRank) {
|
|
141
|
+
const arrow = b.postMmrRank < b.preMmrRank ? 'up' : 'down';
|
|
142
|
+
console.log(` mmr: rank ${b.preMmrRank} -> ${b.postMmrRank} (diversity ${arrow})`);
|
|
143
|
+
}
|
|
144
|
+
console.log(` final: ${fmt(b.final, 4)}`);
|
|
145
|
+
}
|
|
146
|
+
console.log();
|
|
141
147
|
}
|
|
142
148
|
export async function handleExplain({ hippoRoot, args, flags }) {
|
|
143
149
|
const query = args.join(' ').trim();
|
package/dist/cli/maintenance.js
CHANGED
|
@@ -102,34 +102,60 @@ export async function cmdEmbed(hippoRoot, flags) {
|
|
|
102
102
|
// when no provider key is present (e.g. embedded earlier with a key that was
|
|
103
103
|
// later removed). The provider-availability gate is deferred to the embed path.
|
|
104
104
|
if (flags['reset-physics']) {
|
|
105
|
-
|
|
106
|
-
const embIndex = loadEmbeddingIndex(root);
|
|
107
|
-
const db = openHippoDb(root);
|
|
108
|
-
try {
|
|
109
|
-
const count = resetAllPhysicsState(db, entries, embIndex);
|
|
110
|
-
console.log(`Reset physics state: ${count} particles re-initialized from embeddings.`);
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
closeHippoDb(db);
|
|
114
|
-
}
|
|
105
|
+
resetPhysics(root);
|
|
115
106
|
return;
|
|
116
107
|
}
|
|
117
108
|
if (flags['status']) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const orphaned = Object.keys(embIndex).length - activeEmbedded;
|
|
123
|
-
console.log(`Embedding status: ${activeEmbedded}/${entries.length} memories embedded`);
|
|
124
|
-
if (orphaned > 0) {
|
|
125
|
-
console.log(` ${orphaned} orphaned embeddings (run \`hippo embed\` to prune)`);
|
|
126
|
-
}
|
|
127
|
-
const missing = entries.filter((e) => !embIndex[e.id]);
|
|
128
|
-
if (missing.length > 0) {
|
|
129
|
-
console.log(` ${missing.length} memories need embedding (run \`hippo embed\` to embed them)`);
|
|
130
|
-
}
|
|
109
|
+
printEmbedStatus(root);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!embedProviderReady(root))
|
|
131
113
|
return;
|
|
114
|
+
console.log('Embedding all memories (this may take a moment on first run to download model)...');
|
|
115
|
+
let count;
|
|
116
|
+
try {
|
|
117
|
+
count = await embedAll(root, resolveEmbeddingModel(root));
|
|
132
118
|
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
printError(`Embedding failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
121
|
+
const partial = loadEmbeddingIndex(root);
|
|
122
|
+
printError(`Partial progress saved: ${Object.keys(partial).length} embeddings on disk. Re-run \`hippo embed\` to resume.`);
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const entriesAfter = loadAllEntries(root);
|
|
127
|
+
const embIndexAfter = loadEmbeddingIndex(root);
|
|
128
|
+
console.log(`Done. ${count} new embeddings created. ${Object.keys(embIndexAfter).length}/${entriesAfter.length} total.`);
|
|
129
|
+
}
|
|
130
|
+
function resetPhysics(root) {
|
|
131
|
+
const entries = loadAllEntries(root);
|
|
132
|
+
const embIndex = loadEmbeddingIndex(root);
|
|
133
|
+
const db = openHippoDb(root);
|
|
134
|
+
try {
|
|
135
|
+
const count = resetAllPhysicsState(db, entries, embIndex);
|
|
136
|
+
console.log(`Reset physics state: ${count} particles re-initialized from embeddings.`);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
closeHippoDb(db);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function printEmbedStatus(root) {
|
|
143
|
+
const entries = loadAllEntries(root);
|
|
144
|
+
const embIndex = loadEmbeddingIndex(root);
|
|
145
|
+
const activeIds = new Set(entries.map((e) => e.id));
|
|
146
|
+
const activeEmbedded = Object.keys(embIndex).filter((id) => activeIds.has(id)).length;
|
|
147
|
+
const orphaned = Object.keys(embIndex).length - activeEmbedded;
|
|
148
|
+
console.log(`Embedding status: ${activeEmbedded}/${entries.length} memories embedded`);
|
|
149
|
+
if (orphaned > 0) {
|
|
150
|
+
console.log(` ${orphaned} orphaned embeddings (run \`hippo embed\` to prune)`);
|
|
151
|
+
}
|
|
152
|
+
const missing = entries.filter((e) => !embIndex[e.id]);
|
|
153
|
+
if (missing.length > 0) {
|
|
154
|
+
console.log(` ${missing.length} memories need embedding (run \`hippo embed\` to embed them)`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** False, after saying why, when no usable provider exists. */
|
|
158
|
+
function embedProviderReady(root) {
|
|
133
159
|
// Embedding (unlike status/reset) needs an available provider.
|
|
134
160
|
const embedProvider = (() => {
|
|
135
161
|
try {
|
|
@@ -142,38 +168,23 @@ export async function cmdEmbed(hippoRoot, flags) {
|
|
|
142
168
|
})();
|
|
143
169
|
if (!embedProvider) {
|
|
144
170
|
process.exitCode = 1;
|
|
145
|
-
return;
|
|
171
|
+
return false;
|
|
146
172
|
}
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (embedProvider.kind === 'local') {
|
|
153
|
-
console.log('Embeddings not available. Install @huggingface/transformers to enable:');
|
|
154
|
-
console.log(' npm install @huggingface/transformers');
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
printError(`Embedding provider '${embedProvider.kind}' is configured but ${embedProvider.keyEnv} is not set.`);
|
|
158
|
-
printError(`Export ${embedProvider.keyEnv}, or set config.embeddings.provider back to 'local'.`);
|
|
159
|
-
process.exitCode = 1;
|
|
160
|
-
}
|
|
161
|
-
return;
|
|
173
|
+
if (embedProvider.isAvailable())
|
|
174
|
+
return true;
|
|
175
|
+
if (loadConfig(root).embeddings.enabled === false) {
|
|
176
|
+
console.log('Embeddings are disabled in config (embeddings.enabled = false). Set it to true or "auto" to enable.');
|
|
177
|
+
return false;
|
|
162
178
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
count = await embedAll(root, resolveEmbeddingModel(root));
|
|
179
|
+
if (embedProvider.kind === 'local') {
|
|
180
|
+
console.log('Embeddings not available. Install @huggingface/transformers to enable:');
|
|
181
|
+
console.log(' npm install @huggingface/transformers');
|
|
167
182
|
}
|
|
168
|
-
|
|
169
|
-
printError(`Embedding
|
|
170
|
-
|
|
171
|
-
printError(`Partial progress saved: ${Object.keys(partial).length} embeddings on disk. Re-run \`hippo embed\` to resume.`);
|
|
183
|
+
else {
|
|
184
|
+
printError(`Embedding provider '${embedProvider.kind}' is configured but ${embedProvider.keyEnv} is not set.`);
|
|
185
|
+
printError(`Export ${embedProvider.keyEnv}, or set config.embeddings.provider back to 'local'.`);
|
|
172
186
|
process.exitCode = 1;
|
|
173
|
-
return;
|
|
174
187
|
}
|
|
175
|
-
|
|
176
|
-
const embIndexAfter = loadEmbeddingIndex(root);
|
|
177
|
-
console.log(`Done. ${count} new embeddings created. ${Object.keys(embIndexAfter).length}/${entriesAfter.length} total.`);
|
|
188
|
+
return false;
|
|
178
189
|
}
|
|
179
190
|
//# sourceMappingURL=maintenance.js.map
|