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 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`, 1.08 GB) and caches it. Later
93
- restarts are instant. Want something smaller? `AMEM_EMBED_MODEL=onnx-community/gte-multilingual-base`
94
- is about a third the size and reads text just as long — set it **before** you have
95
- memories, since changing it afterwards means a [migration](https://amem.owo.lc/reference/embedding-models#changing-the-model-on-a-store-you-already-have).
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
- const explicit = process.env.AMEM_EMBED_DTYPE?.trim();
80
- if (explicit) return explicit;
81
- return getEmbeddingModel() === DEFAULT_EMBEDDING_MODEL ? DEFAULT_MODEL_DTYPE : void 0;
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, DEFAULT_MODEL_DTYPE, pinnedModel, CLS_POOLED_MODELS;
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"() {
@@ -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.1",
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.1",
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",