hippo-memory 1.32.0 → 1.32.1
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/dedupe.d.ts +8 -2
- package/dist/dedupe.d.ts.map +1 -1
- package/dist/dedupe.js +61 -39
- package/dist/dedupe.js.map +1 -1
- package/dist/src/dedupe.js +61 -39
- package/dist/src/dedupe.js.map +1 -1
- package/dist/src/version.js +1 -1
- 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/dedupe.d.ts
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* asc). Previously the strength/retrieval-count comparator could tie
|
|
15
15
|
* exactly with no terminal key, so the survivor fell to load order
|
|
16
16
|
* (arrival-order-dependent); see `strengthBucket` below for the bucket
|
|
17
|
-
* encoding.
|
|
17
|
+
* encoding. As of the tenant-partition fix
|
|
18
|
+
* (docs/plans/2026-08-15-dedupe-tenant-partition.md) the order is scoped
|
|
19
|
+
* WITHIN each tenant group; cross-tenant pairs are never compared.
|
|
18
20
|
*/
|
|
19
21
|
export interface DedupPair {
|
|
20
22
|
kept: string;
|
|
@@ -51,7 +53,11 @@ export interface DedupPair {
|
|
|
51
53
|
export declare function strengthBucket(strength: number | null | undefined): number;
|
|
52
54
|
/**
|
|
53
55
|
* Scan the store for near-duplicate memories and remove the weaker copy.
|
|
54
|
-
* Two memories are duplicates if their content has > threshold Jaccard
|
|
56
|
+
* Two memories are duplicates if their content has > threshold Jaccard
|
|
57
|
+
* overlap AND they belong to the same tenant: the scan is partitioned by
|
|
58
|
+
* tenantId, so byte-identical content in two tenants is never a duplicate
|
|
59
|
+
* pair (the tenant boundary is an isolation boundary; cross-tenant removal
|
|
60
|
+
* was the v1.32.0 known-issue data-loss bug).
|
|
55
61
|
* Keeps the one with higher strength (or more retrievals if tied).
|
|
56
62
|
*/
|
|
57
63
|
export declare function deduplicateStore(hippoRoot: string, options?: {
|
package/dist/dedupe.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedupe.d.ts","sourceRoot":"","sources":["../src/dedupe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dedupe.d.ts","sourceRoot":"","sources":["../src/dedupe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAG1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACrD;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,CA6EzC"}
|
package/dist/dedupe.js
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* asc). Previously the strength/retrieval-count comparator could tie
|
|
15
15
|
* exactly with no terminal key, so the survivor fell to load order
|
|
16
16
|
* (arrival-order-dependent); see `strengthBucket` below for the bucket
|
|
17
|
-
* encoding.
|
|
17
|
+
* encoding. As of the tenant-partition fix
|
|
18
|
+
* (docs/plans/2026-08-15-dedupe-tenant-partition.md) the order is scoped
|
|
19
|
+
* WITHIN each tenant group; cross-tenant pairs are never compared.
|
|
18
20
|
*/
|
|
19
21
|
import { textOverlap } from './search.js';
|
|
20
22
|
import { loadAllEntries, deleteEntry } from './store.js';
|
|
@@ -50,59 +52,79 @@ export function strengthBucket(strength) {
|
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Scan the store for near-duplicate memories and remove the weaker copy.
|
|
53
|
-
* Two memories are duplicates if their content has > threshold Jaccard
|
|
55
|
+
* Two memories are duplicates if their content has > threshold Jaccard
|
|
56
|
+
* overlap AND they belong to the same tenant: the scan is partitioned by
|
|
57
|
+
* tenantId, so byte-identical content in two tenants is never a duplicate
|
|
58
|
+
* pair (the tenant boundary is an isolation boundary; cross-tenant removal
|
|
59
|
+
* was the v1.32.0 known-issue data-loss bug).
|
|
54
60
|
* Keeps the one with higher strength (or more retrievals if tied).
|
|
55
61
|
*/
|
|
56
62
|
export function deduplicateStore(hippoRoot, options = {}) {
|
|
57
63
|
const threshold = options.threshold ?? 0.7;
|
|
58
64
|
const dryRun = options.dryRun ?? false;
|
|
59
65
|
const entries = loadAllEntries(hippoRoot);
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
// Tenant partition (mirrors consolidate.ts mergeCandidatesByTenant and
|
|
67
|
+
// dag.ts unparentedByTenant): group by tenantId BEFORE the sort so a
|
|
68
|
+
// duplicate pair can never form across tenants. Map preserves insertion
|
|
69
|
+
// order, so a single-tenant store (every row 'default') gets exactly one
|
|
70
|
+
// group and the sort plus pair loop below run byte-identical to the
|
|
71
|
+
// pre-fix global pass.
|
|
72
|
+
const entriesByTenant = new Map();
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
const bucket = entriesByTenant.get(entry.tenantId);
|
|
75
|
+
if (bucket)
|
|
76
|
+
bucket.push(entry);
|
|
77
|
+
else
|
|
78
|
+
entriesByTenant.set(entry.tenantId, [entry]);
|
|
79
|
+
}
|
|
68
80
|
// finiteCount mirrors strengthBucket's non-finite hardening on the
|
|
69
81
|
// retrieval leg: a NaN retrieval_count would make the comparator return
|
|
70
82
|
// NaN and break the total order the same way a NaN bucket would.
|
|
71
83
|
// Unreachable via the schema (non-nullable INTEGER column), so this is
|
|
72
84
|
// symmetry, not a live bug.
|
|
73
85
|
const finiteCount = (n) => Number.isFinite(n ?? 0) ? (n ?? 0) : 0;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const retrievalDiff = finiteCount(b.retrieval_count) - finiteCount(a.retrieval_count);
|
|
79
|
-
if (retrievalDiff !== 0)
|
|
80
|
-
return retrievalDiff;
|
|
81
|
-
return compareEntryIdentity(a, b);
|
|
82
|
-
});
|
|
86
|
+
// Shared across tenant groups: safe because memory ids are globally
|
|
87
|
+
// unique (crypto.randomUUID at creation), so an id in `removed` can never
|
|
88
|
+
// collide with another tenant's row, and deleteEntry below deletes by
|
|
89
|
+
// primary-key id alone.
|
|
83
90
|
const removed = new Set();
|
|
84
91
|
const pairs = [];
|
|
85
|
-
for (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
if (
|
|
92
|
+
for (const tenantEntries of entriesByTenant.values()) {
|
|
93
|
+
// The v1.26.3 survivor total order (see the file-level docstring:
|
|
94
|
+
// strength bucket desc -> retrieval_count desc -> compareEntryIdentity),
|
|
95
|
+
// scoped per tenant group: the total order holds within a tenant only,
|
|
96
|
+
// matching the partition above.
|
|
97
|
+
tenantEntries.sort((a, b) => {
|
|
98
|
+
const bucketDiff = strengthBucket(b.strength) - strengthBucket(a.strength);
|
|
99
|
+
if (bucketDiff !== 0)
|
|
100
|
+
return bucketDiff;
|
|
101
|
+
const retrievalDiff = finiteCount(b.retrieval_count) - finiteCount(a.retrieval_count);
|
|
102
|
+
if (retrievalDiff !== 0)
|
|
103
|
+
return retrievalDiff;
|
|
104
|
+
return compareEntryIdentity(a, b);
|
|
105
|
+
});
|
|
106
|
+
for (let i = 0; i < tenantEntries.length; i++) {
|
|
107
|
+
if (removed.has(tenantEntries[i].id))
|
|
93
108
|
continue;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
removed
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
for (let j = i + 1; j < tenantEntries.length; j++) {
|
|
110
|
+
if (removed.has(tenantEntries[j].id))
|
|
111
|
+
continue;
|
|
112
|
+
const similarity = textOverlap(tenantEntries[i].content, tenantEntries[j].content);
|
|
113
|
+
if (similarity <= threshold)
|
|
114
|
+
continue;
|
|
115
|
+
removed.add(tenantEntries[j].id);
|
|
116
|
+
pairs.push({
|
|
117
|
+
kept: tenantEntries[i].id,
|
|
118
|
+
keptContent: tenantEntries[i].content,
|
|
119
|
+
keptLayer: tenantEntries[i].layer,
|
|
120
|
+
keptStrength: tenantEntries[i].strength ?? 0,
|
|
121
|
+
removed: tenantEntries[j].id,
|
|
122
|
+
removedContent: tenantEntries[j].content,
|
|
123
|
+
removedLayer: tenantEntries[j].layer,
|
|
124
|
+
removedStrength: tenantEntries[j].strength ?? 0,
|
|
125
|
+
similarity,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
106
128
|
}
|
|
107
129
|
}
|
|
108
130
|
if (!dryRun) {
|
package/dist/dedupe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../src/dedupe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../src/dedupe.ts"],"names":[],"mappings":"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"}
|
package/dist/src/dedupe.js
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* asc). Previously the strength/retrieval-count comparator could tie
|
|
15
15
|
* exactly with no terminal key, so the survivor fell to load order
|
|
16
16
|
* (arrival-order-dependent); see `strengthBucket` below for the bucket
|
|
17
|
-
* encoding.
|
|
17
|
+
* encoding. As of the tenant-partition fix
|
|
18
|
+
* (docs/plans/2026-08-15-dedupe-tenant-partition.md) the order is scoped
|
|
19
|
+
* WITHIN each tenant group; cross-tenant pairs are never compared.
|
|
18
20
|
*/
|
|
19
21
|
import { textOverlap } from './search.js';
|
|
20
22
|
import { loadAllEntries, deleteEntry } from './store.js';
|
|
@@ -50,59 +52,79 @@ export function strengthBucket(strength) {
|
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Scan the store for near-duplicate memories and remove the weaker copy.
|
|
53
|
-
* Two memories are duplicates if their content has > threshold Jaccard
|
|
55
|
+
* Two memories are duplicates if their content has > threshold Jaccard
|
|
56
|
+
* overlap AND they belong to the same tenant: the scan is partitioned by
|
|
57
|
+
* tenantId, so byte-identical content in two tenants is never a duplicate
|
|
58
|
+
* pair (the tenant boundary is an isolation boundary; cross-tenant removal
|
|
59
|
+
* was the v1.32.0 known-issue data-loss bug).
|
|
54
60
|
* Keeps the one with higher strength (or more retrievals if tied).
|
|
55
61
|
*/
|
|
56
62
|
export function deduplicateStore(hippoRoot, options = {}) {
|
|
57
63
|
const threshold = options.threshold ?? 0.7;
|
|
58
64
|
const dryRun = options.dryRun ?? false;
|
|
59
65
|
const entries = loadAllEntries(hippoRoot);
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
// Tenant partition (mirrors consolidate.ts mergeCandidatesByTenant and
|
|
67
|
+
// dag.ts unparentedByTenant): group by tenantId BEFORE the sort so a
|
|
68
|
+
// duplicate pair can never form across tenants. Map preserves insertion
|
|
69
|
+
// order, so a single-tenant store (every row 'default') gets exactly one
|
|
70
|
+
// group and the sort plus pair loop below run byte-identical to the
|
|
71
|
+
// pre-fix global pass.
|
|
72
|
+
const entriesByTenant = new Map();
|
|
73
|
+
for (const entry of entries) {
|
|
74
|
+
const bucket = entriesByTenant.get(entry.tenantId);
|
|
75
|
+
if (bucket)
|
|
76
|
+
bucket.push(entry);
|
|
77
|
+
else
|
|
78
|
+
entriesByTenant.set(entry.tenantId, [entry]);
|
|
79
|
+
}
|
|
68
80
|
// finiteCount mirrors strengthBucket's non-finite hardening on the
|
|
69
81
|
// retrieval leg: a NaN retrieval_count would make the comparator return
|
|
70
82
|
// NaN and break the total order the same way a NaN bucket would.
|
|
71
83
|
// Unreachable via the schema (non-nullable INTEGER column), so this is
|
|
72
84
|
// symmetry, not a live bug.
|
|
73
85
|
const finiteCount = (n) => Number.isFinite(n ?? 0) ? (n ?? 0) : 0;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const retrievalDiff = finiteCount(b.retrieval_count) - finiteCount(a.retrieval_count);
|
|
79
|
-
if (retrievalDiff !== 0)
|
|
80
|
-
return retrievalDiff;
|
|
81
|
-
return compareEntryIdentity(a, b);
|
|
82
|
-
});
|
|
86
|
+
// Shared across tenant groups: safe because memory ids are globally
|
|
87
|
+
// unique (crypto.randomUUID at creation), so an id in `removed` can never
|
|
88
|
+
// collide with another tenant's row, and deleteEntry below deletes by
|
|
89
|
+
// primary-key id alone.
|
|
83
90
|
const removed = new Set();
|
|
84
91
|
const pairs = [];
|
|
85
|
-
for (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
if (
|
|
92
|
+
for (const tenantEntries of entriesByTenant.values()) {
|
|
93
|
+
// The v1.26.3 survivor total order (see the file-level docstring:
|
|
94
|
+
// strength bucket desc -> retrieval_count desc -> compareEntryIdentity),
|
|
95
|
+
// scoped per tenant group: the total order holds within a tenant only,
|
|
96
|
+
// matching the partition above.
|
|
97
|
+
tenantEntries.sort((a, b) => {
|
|
98
|
+
const bucketDiff = strengthBucket(b.strength) - strengthBucket(a.strength);
|
|
99
|
+
if (bucketDiff !== 0)
|
|
100
|
+
return bucketDiff;
|
|
101
|
+
const retrievalDiff = finiteCount(b.retrieval_count) - finiteCount(a.retrieval_count);
|
|
102
|
+
if (retrievalDiff !== 0)
|
|
103
|
+
return retrievalDiff;
|
|
104
|
+
return compareEntryIdentity(a, b);
|
|
105
|
+
});
|
|
106
|
+
for (let i = 0; i < tenantEntries.length; i++) {
|
|
107
|
+
if (removed.has(tenantEntries[i].id))
|
|
93
108
|
continue;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
removed
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
for (let j = i + 1; j < tenantEntries.length; j++) {
|
|
110
|
+
if (removed.has(tenantEntries[j].id))
|
|
111
|
+
continue;
|
|
112
|
+
const similarity = textOverlap(tenantEntries[i].content, tenantEntries[j].content);
|
|
113
|
+
if (similarity <= threshold)
|
|
114
|
+
continue;
|
|
115
|
+
removed.add(tenantEntries[j].id);
|
|
116
|
+
pairs.push({
|
|
117
|
+
kept: tenantEntries[i].id,
|
|
118
|
+
keptContent: tenantEntries[i].content,
|
|
119
|
+
keptLayer: tenantEntries[i].layer,
|
|
120
|
+
keptStrength: tenantEntries[i].strength ?? 0,
|
|
121
|
+
removed: tenantEntries[j].id,
|
|
122
|
+
removedContent: tenantEntries[j].content,
|
|
123
|
+
removedLayer: tenantEntries[j].layer,
|
|
124
|
+
removedStrength: tenantEntries[j].strength ?? 0,
|
|
125
|
+
similarity,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
106
128
|
}
|
|
107
129
|
}
|
|
108
130
|
if (!dryRun) {
|
package/dist/src/dedupe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../../src/dedupe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dedupe.js","sourceRoot":"","sources":["../../src/dedupe.ts"],"names":[],"mappings":"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"}
|
package/dist/src/version.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* an ESM `import` can resolve cleanly, and a hardcoded constant survives
|
|
19
19
|
* any packager that drops .json files.
|
|
20
20
|
*/
|
|
21
|
-
export const PACKAGE_VERSION = '1.32.
|
|
21
|
+
export const PACKAGE_VERSION = '1.32.1';
|
|
22
22
|
// Bump on every release alongside the 4 other manifests + lockfile.
|
|
23
23
|
/**
|
|
24
24
|
* Compare two semver strings. Returns positive if a > b, 0 if equal, negative
|
package/dist/version.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* an ESM `import` can resolve cleanly, and a hardcoded constant survives
|
|
19
19
|
* any packager that drops .json files.
|
|
20
20
|
*/
|
|
21
|
-
export declare const PACKAGE_VERSION = "1.32.
|
|
21
|
+
export declare const PACKAGE_VERSION = "1.32.1";
|
|
22
22
|
/**
|
|
23
23
|
* Compare two semver strings. Returns positive if a > b, 0 if equal, negative
|
|
24
24
|
* if a < b.
|
package/dist/version.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* an ESM `import` can resolve cleanly, and a hardcoded constant survives
|
|
19
19
|
* any packager that drops .json files.
|
|
20
20
|
*/
|
|
21
|
-
export const PACKAGE_VERSION = '1.32.
|
|
21
|
+
export const PACKAGE_VERSION = '1.32.1';
|
|
22
22
|
// Bump on every release alongside the 4 other manifests + lockfile.
|
|
23
23
|
/**
|
|
24
24
|
* Compare two semver strings. Returns positive if a > b, 0 if equal, negative
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "hippo-memory",
|
|
3
3
|
"name": "Hippo Memory",
|
|
4
4
|
"description": "Biologically-inspired memory for AI agents. Decay by default, retrieval strengthening, sleep consolidation.",
|
|
5
|
-
"version": "1.32.
|
|
5
|
+
"version": "1.32.1",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|