@amemhq/core 2.0.0 → 2.1.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.
@@ -15,7 +15,6 @@ var cachedDim = null;
15
15
  var DEFAULT_EMBEDDING_MODEL = "Xenova/bge-m3";
16
16
  var LEGACY_DEFAULT_EMBEDDING_MODEL = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
17
17
  var LEGACY_DEFAULT_DIM = 384;
18
- var DEFAULT_MODEL_DTYPE = "fp16";
19
18
  var pinnedModel = null;
20
19
  function pinEmbeddingModel(model) {
21
20
  if (pinnedModel === model) return;
@@ -53,9 +52,28 @@ function getEmbeddingDevice() {
53
52
  return process.env.AMEM_EMBED_DEVICE?.trim() || void 0;
54
53
  }
55
54
  function getEmbeddingDtype() {
56
- const explicit = process.env.AMEM_EMBED_DTYPE?.trim();
57
- if (explicit) return explicit;
58
- return getEmbeddingModel() === DEFAULT_EMBEDDING_MODEL ? DEFAULT_MODEL_DTYPE : void 0;
55
+ return process.env.AMEM_EMBED_DTYPE?.trim() || void 0;
56
+ }
57
+ function applyModelPaths(env) {
58
+ const cache = process.env.AMEM_MODEL_CACHE?.trim();
59
+ if (cache) env.cacheDir = cache;
60
+ const local = process.env.AMEM_MODEL_DIR?.trim();
61
+ if (local) {
62
+ env.localModelPath = local;
63
+ env.allowLocalModels = true;
64
+ }
65
+ }
66
+ function makeProgressReporter() {
67
+ const lastPct = /* @__PURE__ */ new Map();
68
+ return (e) => {
69
+ if (e.status !== "progress" || !e.file || typeof e.progress !== "number") return;
70
+ if (!e.file.endsWith(".onnx") && !e.file.endsWith(".onnx_data")) return;
71
+ const pct = Math.floor(e.progress / 10) * 10;
72
+ if (lastPct.get(e.file) === pct) return;
73
+ lastPct.set(e.file, pct);
74
+ const size = e.total ? ` of ${(e.total / 1e9).toFixed(2)} GB` : "";
75
+ console.log(`[amem] downloading ${e.file}: ${pct}%${size}`);
76
+ };
59
77
  }
60
78
  function extractorKey() {
61
79
  return `${getEmbeddingModel()}|${getEmbeddingDevice() ?? ""}|${getEmbeddingDtype() ?? ""}`;
@@ -66,11 +84,13 @@ async function getExtractor() {
66
84
  if (!pipeline) {
67
85
  const mod = await import("@huggingface/transformers");
68
86
  pipeline = mod.pipeline;
87
+ applyModelPaths(mod.env);
69
88
  }
70
89
  const device = getEmbeddingDevice();
71
90
  const dtype = getEmbeddingDtype();
72
91
  extractor = await pipeline("feature-extraction", getEmbeddingModel(), {
73
92
  revision: "main",
93
+ progress_callback: makeProgressReporter(),
74
94
  // Omitted entirely when unset, so an unconfigured install gets exactly the
75
95
  // library defaults it got before these existed.
76
96
  ...device ? { device } : {},
@@ -366,6 +386,10 @@ async function scrollIdsRaw(collection, limit = 1e4) {
366
386
  async function deleteCollectionRaw(collection) {
367
387
  await qdrant("DELETE", `/collections/${collection}`);
368
388
  }
389
+ async function snapshotCollectionRaw(collection) {
390
+ const r = await qdrant("POST", `/collections/${collection}/snapshots`);
391
+ return { name: r.name, size: r.size ?? 0 };
392
+ }
369
393
  async function resolveAliasRaw(alias) {
370
394
  try {
371
395
  const res = await qdrant("GET", `/aliases`);
@@ -1847,7 +1871,12 @@ async function searchMemory(query, topK = 5, agentId = "main", opts) {
1847
1871
  keywords: note.keywords,
1848
1872
  links: note.links,
1849
1873
  timestamp: note.timestamp,
1850
- similarity: embSimMap.get(id) ?? bfsSimMap.get(id) ?? 0,
1874
+ // Neither map covers a note that got here on BM25 alone: it was never in
1875
+ // the dense results, and it was not expanded into. That is a real cosine
1876
+ // nobody had measured, not a zero — and reporting 0 made a lexical match
1877
+ // look like the least relevant row in the list. Both vectors are already
1878
+ // in hand, so measuring it is one dot product.
1879
+ similarity: embSimMap.get(id) ?? bfsSimMap.get(id) ?? cosineSimilarity(queryEmbedding, note.embedding),
1851
1880
  rrf: rrfMap.get(id) ?? 0,
1852
1881
  via,
1853
1882
  topics: note.topics ?? [],
@@ -2278,6 +2307,7 @@ async function switchToMigrated(opts) {
2278
2307
  const { name, to } = opts;
2279
2308
  const log = opts.logger?.info ?? ((m) => console.log(m));
2280
2309
  if (name === to) throw new Error(`switch: "${name}" and "${to}" are the same collection`);
2310
+ let snap;
2281
2311
  const already = await resolveAliasRaw(name);
2282
2312
  if (already === to) {
2283
2313
  log(`[switch] "${name}" already points at "${to}" \u2014 nothing to do`);
@@ -2293,6 +2323,10 @@ async function switchToMigrated(opts) {
2293
2323
  );
2294
2324
  }
2295
2325
  log(`[switch] verified ${targetCount} in "${to}" against ${sourceCount} in "${name}"`);
2326
+ if (opts.snapshot !== false) {
2327
+ snap = await snapshotCollectionRaw(name);
2328
+ log(`[switch] snapshotted "${name}" \u2192 ${snap.name} (${(snap.size / 1e6).toFixed(0)} MB)`);
2329
+ }
2296
2330
  await deleteCollectionRaw(name);
2297
2331
  log(`[switch] dropped "${name}"`);
2298
2332
  await createAliasRaw(name, to);
@@ -2300,7 +2334,7 @@ async function switchToMigrated(opts) {
2300
2334
  await setAliasRaw(name, to);
2301
2335
  }
2302
2336
  log(`[switch] "${name}" now resolves to "${to}"`);
2303
- return { name, to, moved: targetCount };
2337
+ return { name, to, moved: targetCount, snapshot: snap };
2304
2338
  }
2305
2339
 
2306
2340
  export {
@@ -2350,4 +2384,4 @@ export {
2350
2384
  migrateCollection,
2351
2385
  switchToMigrated
2352
2386
  };
2353
- //# sourceMappingURL=chunk-K6WZTDM7.js.map
2387
+ //# sourceMappingURL=chunk-3HJV3LLV.js.map