hippo-memory 0.29.3 → 0.30.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 +7 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +102 -7
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/consolidate.d.ts +1 -0
- package/dist/consolidate.d.ts.map +1 -1
- package/dist/consolidate.js +59 -1
- package/dist/consolidate.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +16 -1
- package/dist/db.js.map +1 -1
- package/dist/memory.d.ts +7 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +7 -0
- package/dist/memory.js.map +1 -1
- package/dist/store.d.ts +12 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +54 -6
- package/dist/store.js.map +1 -1
- package/dist/trace.d.ts +34 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/trace.js +64 -0
- package/dist/trace.js.map +1 -0
- 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,13 @@ hippo recall "data pipeline issues" --budget 2000
|
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
63
|
+
### What's new in v0.30.0
|
|
64
|
+
|
|
65
|
+
- **Sequence binding for recursive-self-improvement agents.** New `Layer.Trace` memories store ordered `A → B → C → outcome` traces. Agents can `hippo trace record` explicitly, or just call `hippo session complete --outcome success` and let `hippo sleep` auto-promote completed sessions into queryable traces.
|
|
66
|
+
- **`hippo recall --outcome success`** — retrieve only successful prior strategies. The missing RSI primitive: "what worked last time I tried this?"
|
|
67
|
+
- **`examples/rsi-demo/`** — a minimal self-improving agent, deterministic and CI-runnable. Uses traces to learn. Current seed: 20% success on tasks 1-10 rising to 100% on tasks 41-50. Non-zero exit if the learning curve collapses — the demo is also the integration test.
|
|
68
|
+
- **Schema v3 migration, with a regression test that preserves existing data.** Idempotent auto-promotion via indexed `source_session_id`. Four inheritance smoke tests lock the claim that traces get decay / search / replay / physics "for free."
|
|
69
|
+
|
|
63
70
|
### What's new in v0.29.3
|
|
64
71
|
|
|
65
72
|
- **Post-install banner for Claude Code users.** After `npm install -g hippo-memory`, if Claude Code is detected but the Hippo hook isn't wired yet, a three-line message points the user at `hippo init`. Silent on reinstalls or machines without Claude Code. Opt out via `HIPPO_SKIP_POSTINSTALL=1`.
|
package/dist/cli.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* hippo outcome --good | --bad [--id <id>]
|
|
12
12
|
* hippo conflicts [--status <status>] [--json]
|
|
13
13
|
* hippo snapshot <save|show|clear>
|
|
14
|
-
* hippo session <log|show|latest|resume>
|
|
14
|
+
* hippo session <log|show|latest|resume|complete>
|
|
15
15
|
* hippo handoff <create|latest|show>
|
|
16
16
|
* hippo current <show>
|
|
17
17
|
* hippo forget <id>
|
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* hippo outcome --good | --bad [--id <id>]
|
|
12
12
|
* hippo conflicts [--status <status>] [--json]
|
|
13
13
|
* hippo snapshot <save|show|clear>
|
|
14
|
-
* hippo session <log|show|latest|resume>
|
|
14
|
+
* hippo session <log|show|latest|resume|complete>
|
|
15
15
|
* hippo handoff <create|latest|show>
|
|
16
16
|
* hippo current <show>
|
|
17
17
|
* hippo forget <id>
|
|
@@ -33,6 +33,7 @@ import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInsta
|
|
|
33
33
|
import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, applyOutcome, computeSchemaFit, Layer, DECISION_HALF_LIFE_DAYS, } from './memory.js';
|
|
34
34
|
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, } from './store.js';
|
|
35
35
|
import { markRetrieved, estimateTokens, hybridSearch, physicsSearch, explainMatch, textOverlap } from './search.js';
|
|
36
|
+
import { renderTraceContent, parseSteps } from './trace.js';
|
|
36
37
|
import { consolidate } from './consolidate.js';
|
|
37
38
|
import { isEmbeddingAvailable, embedAll, embedMemory, loadEmbeddingIndex, resolveEmbeddingModel, } from './embeddings.js';
|
|
38
39
|
import { loadPhysicsState, resetAllPhysicsState } from './physics-state.js';
|
|
@@ -477,6 +478,22 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
477
478
|
budget, hippoRoot, mmr: mmrEnabled, mmrLambda, minResults,
|
|
478
479
|
});
|
|
479
480
|
}
|
|
481
|
+
// --outcome filter: drop trace entries whose trace_outcome !== target.
|
|
482
|
+
// Non-trace entries pass through unaffected (traces are the only layer with
|
|
483
|
+
// a meaningful outcome; filtering non-traces by outcome would be incoherent).
|
|
484
|
+
const outcomeFilter = flags['outcome'] !== undefined ? String(flags['outcome']).trim() : '';
|
|
485
|
+
if (outcomeFilter) {
|
|
486
|
+
const validOutcomes = ['success', 'failure', 'partial'];
|
|
487
|
+
if (!validOutcomes.includes(outcomeFilter)) {
|
|
488
|
+
console.error(`Invalid --outcome: "${outcomeFilter}". Must be one of: ${validOutcomes.join(', ')}.`);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
results = results.filter((r) => {
|
|
492
|
+
if (r.entry.layer !== Layer.Trace)
|
|
493
|
+
return true;
|
|
494
|
+
return r.entry.trace_outcome === outcomeFilter;
|
|
495
|
+
});
|
|
496
|
+
}
|
|
480
497
|
if (limit < results.length) {
|
|
481
498
|
results = results.slice(0, limit);
|
|
482
499
|
}
|
|
@@ -510,10 +527,13 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
510
527
|
tokens: r.tokens,
|
|
511
528
|
tags: r.entry.tags,
|
|
512
529
|
content: r.entry.content,
|
|
530
|
+
layer: r.entry.layer,
|
|
513
531
|
};
|
|
532
|
+
if (r.entry.layer === Layer.Trace) {
|
|
533
|
+
base.trace_outcome = r.entry.trace_outcome;
|
|
534
|
+
}
|
|
514
535
|
if (showWhy) {
|
|
515
536
|
const explanation = explainMatch(query, r);
|
|
516
|
-
base.layer = r.entry.layer;
|
|
517
537
|
base.confidence = resolveConfidence(r.entry);
|
|
518
538
|
base.source = isGlobal ? 'global' : 'local';
|
|
519
539
|
base.reason = explanation.reason;
|
|
@@ -826,6 +846,50 @@ async function cmdEval(hippoRoot, corpusPath, flags) {
|
|
|
826
846
|
}
|
|
827
847
|
}
|
|
828
848
|
}
|
|
849
|
+
function cmdTraceRecord(hippoRoot, flags) {
|
|
850
|
+
requireInit(hippoRoot);
|
|
851
|
+
const task = String(flags['task'] ?? '').trim();
|
|
852
|
+
const stepsJson = String(flags['steps'] ?? '').trim();
|
|
853
|
+
const outcome = String(flags['outcome'] ?? '').trim();
|
|
854
|
+
const validOutcomes = ['success', 'failure', 'partial'];
|
|
855
|
+
if (!task || !stepsJson || !outcome) {
|
|
856
|
+
console.error('Usage: hippo trace record --task <t> --steps <json> --outcome <success|failure|partial> [--session <id>] [--tag <t>]');
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
859
|
+
if (!validOutcomes.includes(outcome)) {
|
|
860
|
+
console.error(`Invalid outcome: "${outcome}". Must be one of: ${validOutcomes.join(', ')}.`);
|
|
861
|
+
process.exit(1);
|
|
862
|
+
}
|
|
863
|
+
let steps;
|
|
864
|
+
try {
|
|
865
|
+
steps = parseSteps(stepsJson);
|
|
866
|
+
}
|
|
867
|
+
catch (err) {
|
|
868
|
+
console.error(String(err instanceof Error ? err.message : err));
|
|
869
|
+
process.exit(1);
|
|
870
|
+
}
|
|
871
|
+
const sessionId = String(flags['session'] ?? '').trim() || null;
|
|
872
|
+
const rawTags = flags['tag'];
|
|
873
|
+
const tags = Array.isArray(rawTags)
|
|
874
|
+
? rawTags.map((t) => String(t))
|
|
875
|
+
: rawTags !== undefined
|
|
876
|
+
? [String(rawTags)]
|
|
877
|
+
: [];
|
|
878
|
+
const content = renderTraceContent({
|
|
879
|
+
task,
|
|
880
|
+
steps,
|
|
881
|
+
outcome: outcome,
|
|
882
|
+
});
|
|
883
|
+
const entry = createMemory(content, {
|
|
884
|
+
layer: Layer.Trace,
|
|
885
|
+
tags,
|
|
886
|
+
source: String(flags['source'] ?? 'cli'),
|
|
887
|
+
trace_outcome: outcome,
|
|
888
|
+
source_session_id: sessionId,
|
|
889
|
+
});
|
|
890
|
+
writeEntry(hippoRoot, entry);
|
|
891
|
+
console.log(`Recorded trace ${entry.id} (outcome=${outcome}, ${steps.length} steps)`);
|
|
892
|
+
}
|
|
829
893
|
function cmdTrace(hippoRoot, id, flags) {
|
|
830
894
|
requireInit(hippoRoot);
|
|
831
895
|
const asJson = Boolean(flags['json']);
|
|
@@ -1493,6 +1557,7 @@ function cmdStatus(hippoRoot) {
|
|
|
1493
1557
|
[Layer.Buffer]: 0,
|
|
1494
1558
|
[Layer.Episodic]: 0,
|
|
1495
1559
|
[Layer.Semantic]: 0,
|
|
1560
|
+
[Layer.Trace]: 0,
|
|
1496
1561
|
};
|
|
1497
1562
|
const byConfidence = {
|
|
1498
1563
|
verified: 0,
|
|
@@ -1880,6 +1945,32 @@ function cmdSession(hippoRoot, args, flags) {
|
|
|
1880
1945
|
printSessionEvents(events);
|
|
1881
1946
|
return;
|
|
1882
1947
|
}
|
|
1948
|
+
if (subcommand === 'complete') {
|
|
1949
|
+
const outcome = String(flags['outcome'] ?? '').trim();
|
|
1950
|
+
const summary = String(flags['summary'] ?? '').trim();
|
|
1951
|
+
const validOutcomes = ['success', 'failure', 'partial'];
|
|
1952
|
+
if (!sessionId) {
|
|
1953
|
+
console.error('Usage: hippo session complete --session <session-id> --outcome <success|failure|partial> [--summary "..."]');
|
|
1954
|
+
process.exit(1);
|
|
1955
|
+
}
|
|
1956
|
+
if (!validOutcomes.includes(outcome)) {
|
|
1957
|
+
console.error(`Invalid outcome: "${outcome}". Must be one of: ${validOutcomes.join(', ')}.`);
|
|
1958
|
+
process.exit(1);
|
|
1959
|
+
}
|
|
1960
|
+
const metadata = { ended_at: new Date().toISOString() };
|
|
1961
|
+
if (summary)
|
|
1962
|
+
metadata.summary = summary;
|
|
1963
|
+
const event = appendSessionEvent(hippoRoot, {
|
|
1964
|
+
session_id: sessionId,
|
|
1965
|
+
task: task || null,
|
|
1966
|
+
event_type: 'session_complete',
|
|
1967
|
+
content: outcome,
|
|
1968
|
+
source: String(flags['source'] ?? 'cli'),
|
|
1969
|
+
metadata,
|
|
1970
|
+
});
|
|
1971
|
+
console.log(`Completed session ${event.session_id} with outcome=${outcome} (event #${event.id})`);
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1883
1974
|
if (subcommand === 'resume') {
|
|
1884
1975
|
const handoff = loadLatestHandoff(hippoRoot, sessionId || undefined);
|
|
1885
1976
|
if (!handoff) {
|
|
@@ -1910,7 +2001,7 @@ function cmdSession(hippoRoot, args, flags) {
|
|
|
1910
2001
|
console.log(lines.join('\n'));
|
|
1911
2002
|
return;
|
|
1912
2003
|
}
|
|
1913
|
-
console.error('Usage: hippo session <log|show|latest|resume>');
|
|
2004
|
+
console.error('Usage: hippo session <log|show|latest|resume|complete>');
|
|
1914
2005
|
process.exit(1);
|
|
1915
2006
|
}
|
|
1916
2007
|
function printHandoff(handoff) {
|
|
@@ -3415,12 +3506,16 @@ async function main() {
|
|
|
3415
3506
|
break;
|
|
3416
3507
|
}
|
|
3417
3508
|
case 'trace': {
|
|
3418
|
-
const
|
|
3419
|
-
if (
|
|
3420
|
-
|
|
3509
|
+
const sub = args[0] ? String(args[0]) : '';
|
|
3510
|
+
if (sub === 'record') {
|
|
3511
|
+
cmdTraceRecord(hippoRoot, flags);
|
|
3512
|
+
break;
|
|
3513
|
+
}
|
|
3514
|
+
if (!sub) {
|
|
3515
|
+
console.error('Usage: hippo trace <memory-id> | hippo trace record --task <t> --steps <json> --outcome <o>');
|
|
3421
3516
|
process.exit(1);
|
|
3422
3517
|
}
|
|
3423
|
-
cmdTrace(hippoRoot,
|
|
3518
|
+
cmdTrace(hippoRoot, sub, flags);
|
|
3424
3519
|
break;
|
|
3425
3520
|
}
|
|
3426
3521
|
case 'refine':
|