openclaw-amem 2.0.1 → 2.1.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 +5 -4
- package/dist/index.js +35 -6
- package/openclaw.plugin.json +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,10 +89,11 @@ Add `openclaw-amem` to your allowed plugins and hook it into the `memory` slot:
|
|
|
89
89
|
openclaw gateway restart
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
First run downloads the embedding model (`bge-m3`,
|
|
93
|
-
restarts are instant.
|
|
94
|
-
|
|
95
|
-
memories, since changing it afterwards means
|
|
92
|
+
First run downloads the embedding model (`bge-m3`, 2.27 GB) and caches it. Later
|
|
93
|
+
restarts are instant. If that is too much, the only smaller model worth setting is
|
|
94
|
+
`AMEM_EMBED_MODEL=Xenova/bge-small-zh-v1.5` — 25 MB, Chinese only, and it caps at
|
|
95
|
+
512 tokens. Set it **before** you have memories, since changing it afterwards means
|
|
96
|
+
a [migration](https://amem.owo.lc/reference/embedding-models#changing-the-model-on-a-store-you-already-have).
|
|
96
97
|
|
|
97
98
|
Upgrading from 1.x downloads nothing. Your existing memories keep the model that
|
|
98
99
|
built them, and the plugin says so at startup along with the one command that
|
package/dist/index.js
CHANGED
|
@@ -76,9 +76,28 @@ function getEmbeddingDevice() {
|
|
|
76
76
|
return process.env.AMEM_EMBED_DEVICE?.trim() || void 0;
|
|
77
77
|
}
|
|
78
78
|
function getEmbeddingDtype() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
return process.env.AMEM_EMBED_DTYPE?.trim() || void 0;
|
|
80
|
+
}
|
|
81
|
+
function applyModelPaths(env) {
|
|
82
|
+
const cache = process.env.AMEM_MODEL_CACHE?.trim();
|
|
83
|
+
if (cache) env.cacheDir = cache;
|
|
84
|
+
const local = process.env.AMEM_MODEL_DIR?.trim();
|
|
85
|
+
if (local) {
|
|
86
|
+
env.localModelPath = local;
|
|
87
|
+
env.allowLocalModels = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function makeProgressReporter() {
|
|
91
|
+
const lastPct = /* @__PURE__ */ new Map();
|
|
92
|
+
return (e) => {
|
|
93
|
+
if (e.status !== "progress" || !e.file || typeof e.progress !== "number") return;
|
|
94
|
+
if (!e.file.endsWith(".onnx") && !e.file.endsWith(".onnx_data")) return;
|
|
95
|
+
const pct = Math.floor(e.progress / 10) * 10;
|
|
96
|
+
if (lastPct.get(e.file) === pct) return;
|
|
97
|
+
lastPct.set(e.file, pct);
|
|
98
|
+
const size = e.total ? ` of ${(e.total / 1e9).toFixed(2)} GB` : "";
|
|
99
|
+
console.log(`[amem] downloading ${e.file}: ${pct}%${size}`);
|
|
100
|
+
};
|
|
82
101
|
}
|
|
83
102
|
function extractorKey() {
|
|
84
103
|
return `${getEmbeddingModel()}|${getEmbeddingDevice() ?? ""}|${getEmbeddingDtype() ?? ""}`;
|
|
@@ -89,11 +108,13 @@ async function getExtractor() {
|
|
|
89
108
|
if (!pipeline) {
|
|
90
109
|
const mod = await import("@huggingface/transformers");
|
|
91
110
|
pipeline = mod.pipeline;
|
|
111
|
+
applyModelPaths(mod.env);
|
|
92
112
|
}
|
|
93
113
|
const device = getEmbeddingDevice();
|
|
94
114
|
const dtype = getEmbeddingDtype();
|
|
95
115
|
extractor = await pipeline("feature-extraction", getEmbeddingModel(), {
|
|
96
116
|
revision: "main",
|
|
117
|
+
progress_callback: makeProgressReporter(),
|
|
97
118
|
// Omitted entirely when unset, so an unconfigured install gets exactly the
|
|
98
119
|
// library defaults it got before these existed.
|
|
99
120
|
...device ? { device } : {},
|
|
@@ -167,7 +188,7 @@ function cosineSimilarity(a, b) {
|
|
|
167
188
|
for (let i = 0; i < a.length; i++) dot += a[i] * b[i];
|
|
168
189
|
return dot;
|
|
169
190
|
}
|
|
170
|
-
var pipeline, extractor, loadedKey, cachedDim, DEFAULT_EMBEDDING_MODEL, LEGACY_DEFAULT_EMBEDDING_MODEL, LEGACY_DEFAULT_DIM,
|
|
191
|
+
var pipeline, extractor, loadedKey, cachedDim, DEFAULT_EMBEDDING_MODEL, LEGACY_DEFAULT_EMBEDDING_MODEL, LEGACY_DEFAULT_DIM, pinnedModel, CLS_POOLED_MODELS;
|
|
171
192
|
var init_embedding = __esm({
|
|
172
193
|
"../amem-core/src/embedding.ts"() {
|
|
173
194
|
"use strict";
|
|
@@ -178,7 +199,6 @@ var init_embedding = __esm({
|
|
|
178
199
|
DEFAULT_EMBEDDING_MODEL = "Xenova/bge-m3";
|
|
179
200
|
LEGACY_DEFAULT_EMBEDDING_MODEL = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
|
|
180
201
|
LEGACY_DEFAULT_DIM = 384;
|
|
181
|
-
DEFAULT_MODEL_DTYPE = "fp16";
|
|
182
202
|
pinnedModel = null;
|
|
183
203
|
CLS_POOLED_MODELS = /* @__PURE__ */ new Set([
|
|
184
204
|
"bge-m3",
|
|
@@ -377,6 +397,10 @@ async function scrollIdsRaw(collection, limit = 1e4) {
|
|
|
377
397
|
async function deleteCollectionRaw(collection) {
|
|
378
398
|
await qdrant("DELETE", `/collections/${collection}`);
|
|
379
399
|
}
|
|
400
|
+
async function snapshotCollectionRaw(collection) {
|
|
401
|
+
const r = await qdrant("POST", `/collections/${collection}/snapshots`);
|
|
402
|
+
return { name: r.name, size: r.size ?? 0 };
|
|
403
|
+
}
|
|
380
404
|
async function resolveAliasRaw(alias) {
|
|
381
405
|
try {
|
|
382
406
|
const res = await qdrant("GET", `/aliases`);
|
|
@@ -2559,6 +2583,7 @@ async function switchToMigrated(opts) {
|
|
|
2559
2583
|
const { name, to } = opts;
|
|
2560
2584
|
const log = opts.logger?.info ?? ((m) => console.log(m));
|
|
2561
2585
|
if (name === to) throw new Error(`switch: "${name}" and "${to}" are the same collection`);
|
|
2586
|
+
let snap;
|
|
2562
2587
|
const already = await resolveAliasRaw(name);
|
|
2563
2588
|
if (already === to) {
|
|
2564
2589
|
log(`[switch] "${name}" already points at "${to}" \u2014 nothing to do`);
|
|
@@ -2574,6 +2599,10 @@ async function switchToMigrated(opts) {
|
|
|
2574
2599
|
);
|
|
2575
2600
|
}
|
|
2576
2601
|
log(`[switch] verified ${targetCount} in "${to}" against ${sourceCount} in "${name}"`);
|
|
2602
|
+
if (opts.snapshot !== false) {
|
|
2603
|
+
snap = await snapshotCollectionRaw(name);
|
|
2604
|
+
log(`[switch] snapshotted "${name}" \u2192 ${snap.name} (${(snap.size / 1e6).toFixed(0)} MB)`);
|
|
2605
|
+
}
|
|
2577
2606
|
await deleteCollectionRaw(name);
|
|
2578
2607
|
log(`[switch] dropped "${name}"`);
|
|
2579
2608
|
await createAliasRaw(name, to);
|
|
@@ -2581,7 +2610,7 @@ async function switchToMigrated(opts) {
|
|
|
2581
2610
|
await setAliasRaw(name, to);
|
|
2582
2611
|
}
|
|
2583
2612
|
log(`[switch] "${name}" now resolves to "${to}"`);
|
|
2584
|
-
return { name, to, moved: targetCount };
|
|
2613
|
+
return { name, to, moved: targetCount, snapshot: snap };
|
|
2585
2614
|
}
|
|
2586
2615
|
var init_migrate = __esm({
|
|
2587
2616
|
"../amem-core/src/migrate.ts"() {
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "amem",
|
|
4
4
|
"description": "Catches memories that contradict each other. Notes rewrite themselves as new ones arrive, link into a graph, and stay separated per agent and per person. Runs on a small model. Requires a local Qdrant. 中文走 jieba 分词,提示词有中文版。",
|
|
5
5
|
"icon": "https://amem.owo.lc/logo.png",
|
|
6
|
-
"version": "2.0
|
|
6
|
+
"version": "2.1.0",
|
|
7
7
|
"kind": "memory",
|
|
8
8
|
"contracts": {
|
|
9
9
|
"tools": [
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
"AMEM_EMBED_POOLING",
|
|
36
36
|
"AMEM_EMBED_DEVICE",
|
|
37
37
|
"AMEM_EMBED_DTYPE",
|
|
38
|
+
"AMEM_MODEL_CACHE",
|
|
39
|
+
"AMEM_MODEL_DIR",
|
|
38
40
|
"AMEM_COLLECTION",
|
|
39
41
|
"AMEM_DATA_DIR",
|
|
40
42
|
"AMEM_EVO_COUNTER_PATH",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-amem",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Catches memories that contradict each other. Notes rewrite themselves as new ones arrive, link into a graph, and stay separated per agent and per person. Runs on a small model. Requires a local Qdrant. 中文走 jieba 分词,提示词有中文版。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|