mr-memory 2.17.0 → 2.18.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/index.ts CHANGED
@@ -178,6 +178,7 @@ type MemoryRouterConfig = {
178
178
  density?: "low" | "high" | "xhigh";
179
179
  mode?: "relay" | "proxy";
180
180
  logging?: boolean;
181
+ embeddings?: string;
181
182
  };
182
183
 
183
184
  // ──────────────────────────────────────────────────────
@@ -286,10 +287,12 @@ const memoryRouterPlugin = {
286
287
  const density = cfg?.density || "high";
287
288
  const mode = cfg?.mode || "relay";
288
289
  const logging = cfg?.logging ?? false;
290
+ const embeddings = cfg?.embeddings; // undefined = bge (default), "qwen" = qwen3-8b
289
291
  const log = (msg: string) => { if (logging) api.logger.info?.(msg); };
290
292
 
291
293
  if (memoryKey) {
292
- api.logger.info?.(`memoryrouter: active (key: ${memoryKey.slice(0, 6)}..., mode: ${mode})`);
294
+ const modelLabel = embeddings ? `, embeddings: ${embeddings}` : "";
295
+ api.logger.info?.(`memoryrouter: active (key: ${memoryKey.slice(0, 6)}..., mode: ${mode}${modelLabel})`);
293
296
  } else {
294
297
  api.logger.info?.("memoryrouter: no key configured — run: openclaw mr <key>");
295
298
  api.logger.info?.("memoryrouter: get your free API key at https://memoryrouter.ai");
@@ -363,7 +366,7 @@ const memoryRouterPlugin = {
363
366
  messages: contextPayload,
364
367
  session_id: ctx.sessionKey,
365
368
  density,
366
-
369
+ ...(embeddings && { embeddings }),
367
370
  }),
368
371
  });
369
372
 
@@ -475,7 +478,7 @@ const memoryRouterPlugin = {
475
478
  messages: contextPayload,
476
479
  session_id: ctx.sessionKey,
477
480
  density,
478
-
481
+ ...(embeddings && { embeddings }),
479
482
  }),
480
483
  });
481
484
 
@@ -594,6 +597,7 @@ const memoryRouterPlugin = {
594
597
  messages: toStore,
595
598
  session_id: ctx.sessionKey,
596
599
  model: "unknown",
600
+ ...(embeddings && { embeddings }),
597
601
  }),
598
602
  });
599
603
  if (!res.ok) {
@@ -763,6 +767,48 @@ const memoryRouterPlugin = {
763
767
  });
764
768
  }
765
769
 
770
+ // Embedding model command
771
+ mr.command("embeddings")
772
+ .description("Get or set embedding model (bge, qwen)")
773
+ .argument("[model]", "Embedding model: bge (default, 1024d) or qwen (4096d)")
774
+ .action(async (model: string | undefined) => {
775
+ if (!model) {
776
+ console.log(`Current embedding model: ${embeddings || "bge (default)"}`);
777
+ console.log(`\nAvailable models:`);
778
+ console.log(` bge BGE-M3 1024 dims (Cloudflare Workers AI, ~18ms, free)`);
779
+ console.log(` qwen Qwen3-8B 4096 dims (HuggingFace, ~69ms, $0.80/hr)`);
780
+ console.log(`\nUsage: openclaw mr embeddings <model>`);
781
+ return;
782
+ }
783
+ const normalized = model.toLowerCase().trim();
784
+ const valid = ["bge", "bge-m3", "qwen", "qwen3", "qwen3-8b", "default"];
785
+ if (!valid.includes(normalized)) {
786
+ console.error(`Unknown model: "${model}". Valid options: bge, qwen`);
787
+ return;
788
+ }
789
+ if (!memoryKey) { console.error("Not configured. Run: openclaw mr <key>"); return; }
790
+ // "bge" / "default" → clear embeddings (use server default)
791
+ const newEmbeddings = (normalized === "bge" || normalized === "bge-m3" || normalized === "default")
792
+ ? undefined
793
+ : normalized.startsWith("qwen") ? "qwen" : normalized;
794
+ try {
795
+ await setPluginConfig(api, {
796
+ key: memoryKey,
797
+ endpoint: cfg?.endpoint,
798
+ density,
799
+ mode,
800
+ logging,
801
+ ...(newEmbeddings && { embeddings: newEmbeddings }),
802
+ });
803
+ const label = newEmbeddings || "bge (default)";
804
+ console.log(`✓ Embedding model set to ${label}`);
805
+ console.log(` All future prepare/ingest/search will use ${label}`);
806
+ console.log(`\n Restart gateway to apply: openclaw gateway restart`);
807
+ } catch (err) {
808
+ console.error(`Failed: ${err instanceof Error ? err.message : String(err)}`);
809
+ }
810
+ });
811
+
766
812
  mr.command("status")
767
813
  .description("Show MemoryRouter vault stats")
768
814
  .option("--json", "JSON output")
@@ -780,12 +826,15 @@ const memoryRouterPlugin = {
780
826
  return;
781
827
  }
782
828
  try {
783
- const res = await fetch(`${endpoint}/v1/memory/stats`, {
829
+ const statsUrl = embeddings
830
+ ? `${endpoint}/v1/memory/stats?embeddings=${encodeURIComponent(embeddings)}`
831
+ : `${endpoint}/v1/memory/stats`;
832
+ const res = await fetch(statsUrl, {
784
833
  headers: { Authorization: `Bearer ${memoryKey}` },
785
834
  });
786
835
  const data = (await res.json()) as { totalVectors?: number; totalTokens?: number };
787
836
  if (opts.json) {
788
- console.log(JSON.stringify({ enabled: true, key: memoryKey, density, mode, stats: data }, null, 2));
837
+ console.log(JSON.stringify({ enabled: true, key: memoryKey, density, mode, embeddings: embeddings || "bge", stats: data }, null, 2));
789
838
  } else {
790
839
  console.log("MemoryRouter Status");
791
840
  console.log("───────────────────────────");
@@ -793,6 +842,7 @@ const memoryRouterPlugin = {
793
842
  console.log(`Key: ${memoryKey.slice(0, 6)}...${memoryKey.slice(-3)}`);
794
843
  console.log(`Mode: ${mode}`);
795
844
  console.log(`Density: ${density}`);
845
+ console.log(`Embeddings: ${embeddings || "bge (default)"}`);
796
846
  console.log(`Endpoint: ${endpoint}`);
797
847
  console.log(`Memories: ${data.totalVectors ?? 0}`);
798
848
  console.log(`Tokens: ${data.totalTokens ?? 0}`);
@@ -819,7 +869,7 @@ const memoryRouterPlugin = {
819
869
  ? path.resolve(configWorkspace.replace(/^~/, os.homedir()))
820
870
  : path.join(os.homedir(), ".openclaw", "workspace");
821
871
  const { runUpload } = await import("./upload.js");
822
- await runUpload({ memoryKey, endpoint, targetPath, stateDir, workspacePath, hasWorkspaceFlag: !!opts.workspace, hasBrainFlag: !!opts.brain });
872
+ await runUpload({ memoryKey, endpoint, targetPath, stateDir, workspacePath, hasWorkspaceFlag: !!opts.workspace, hasBrainFlag: !!opts.brain, embeddings });
823
873
  });
824
874
 
825
875
  mr.command("delete")
@@ -827,12 +877,16 @@ const memoryRouterPlugin = {
827
877
  .action(async () => {
828
878
  if (!memoryKey) { console.error("Not configured. Run: openclaw mr <key>"); return; }
829
879
  try {
830
- const res = await fetch(`${endpoint}/v1/memory`, {
880
+ const deleteUrl = embeddings
881
+ ? `${endpoint}/v1/memory?embeddings=${encodeURIComponent(embeddings)}`
882
+ : `${endpoint}/v1/memory`;
883
+ const res = await fetch(deleteUrl, {
831
884
  method: "DELETE",
832
885
  headers: { Authorization: `Bearer ${memoryKey}` },
833
886
  });
834
887
  const data = (await res.json()) as { message?: string };
835
- console.log(`✓ ${data.message || "Vault cleared"}`);
888
+ const modelLabel = embeddings ? ` (${embeddings})` : "";
889
+ console.log(`✓ ${data.message || `Vault cleared${modelLabel}`}`);
836
890
  } catch (err) {
837
891
  console.error(`Failed: ${err instanceof Error ? err.message : String(err)}`);
838
892
  }
@@ -41,6 +41,11 @@
41
41
  "mode": {
42
42
  "type": "string",
43
43
  "enum": ["relay", "proxy"]
44
+ },
45
+ "embeddings": {
46
+ "type": "string",
47
+ "enum": ["bge", "qwen"],
48
+ "description": "Embedding model: bge (1024d, default) or qwen (4096d)"
44
49
  }
45
50
  },
46
51
  "required": []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mr-memory",
3
- "version": "2.17.0",
3
+ "version": "2.18.1",
4
4
  "description": "MemoryRouter persistent memory plugin for OpenClaw — your AI remembers every conversation",
5
5
  "type": "module",
6
6
  "files": [
package/upload.ts CHANGED
@@ -353,8 +353,9 @@ export async function runUpload(params: {
353
353
  workspacePath?: string;
354
354
  hasWorkspaceFlag?: boolean;
355
355
  hasBrainFlag?: boolean;
356
+ embeddings?: string;
356
357
  }): Promise<void> {
357
- const { memoryKey, endpoint, targetPath, stateDir } = params;
358
+ const { memoryKey, endpoint, targetPath, stateDir, embeddings } = params;
358
359
  const uploadUrl = `${endpoint}/v1/memory/upload`;
359
360
 
360
361
  // Validate API reachability
@@ -469,6 +470,7 @@ export async function runUpload(params: {
469
470
  headers: {
470
471
  Authorization: `Bearer ${memoryKey}`,
471
472
  "Content-Type": "text/plain",
473
+ ...(embeddings && { "X-Embedding-Model": embeddings }),
472
474
  },
473
475
  body: jsonlBody,
474
476
  },