mr-memory 2.16.0 → 2.18.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.
Files changed (3) hide show
  1. package/index.ts +66 -8
  2. package/package.json +1 -1
  3. package/upload.ts +3 -1
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");
@@ -329,6 +332,8 @@ const memoryRouterPlugin = {
329
332
  for (const msg of event.historyMessages) {
330
333
  const m = msg as { role?: string; content?: unknown };
331
334
  if (!m.role) continue;
335
+ // Skip tool result/use messages — contains file reads, exec output, etc.
336
+ if (m.role !== "user" && m.role !== "assistant" && m.role !== "system") continue;
332
337
  let text = "";
333
338
  if (typeof m.content === "string") text = m.content;
334
339
  else if (Array.isArray(m.content)) {
@@ -361,7 +366,7 @@ const memoryRouterPlugin = {
361
366
  messages: contextPayload,
362
367
  session_id: ctx.sessionKey,
363
368
  density,
364
-
369
+ ...(embeddings && { embeddings }),
365
370
  }),
366
371
  });
367
372
 
@@ -432,6 +437,8 @@ const memoryRouterPlugin = {
432
437
  for (const msg of event.messages) {
433
438
  const m = msg as { role?: string; content?: unknown };
434
439
  if (!m.role) continue;
440
+ // Skip tool result/use messages — contains file reads, exec output, etc.
441
+ if (m.role !== "user" && m.role !== "assistant" && m.role !== "system") continue;
435
442
 
436
443
  let text = "";
437
444
  if (typeof m.content === "string") {
@@ -471,7 +478,7 @@ const memoryRouterPlugin = {
471
478
  messages: contextPayload,
472
479
  session_id: ctx.sessionKey,
473
480
  density,
474
-
481
+ ...(embeddings && { embeddings }),
475
482
  }),
476
483
  });
477
484
 
@@ -590,6 +597,7 @@ const memoryRouterPlugin = {
590
597
  messages: toStore,
591
598
  session_id: ctx.sessionKey,
592
599
  model: "unknown",
600
+ ...(embeddings && { embeddings }),
593
601
  }),
594
602
  });
595
603
  if (!res.ok) {
@@ -759,6 +767,48 @@ const memoryRouterPlugin = {
759
767
  });
760
768
  }
761
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
+
762
812
  mr.command("status")
763
813
  .description("Show MemoryRouter vault stats")
764
814
  .option("--json", "JSON output")
@@ -776,12 +826,15 @@ const memoryRouterPlugin = {
776
826
  return;
777
827
  }
778
828
  try {
779
- 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, {
780
833
  headers: { Authorization: `Bearer ${memoryKey}` },
781
834
  });
782
835
  const data = (await res.json()) as { totalVectors?: number; totalTokens?: number };
783
836
  if (opts.json) {
784
- 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));
785
838
  } else {
786
839
  console.log("MemoryRouter Status");
787
840
  console.log("───────────────────────────");
@@ -789,6 +842,7 @@ const memoryRouterPlugin = {
789
842
  console.log(`Key: ${memoryKey.slice(0, 6)}...${memoryKey.slice(-3)}`);
790
843
  console.log(`Mode: ${mode}`);
791
844
  console.log(`Density: ${density}`);
845
+ console.log(`Embeddings: ${embeddings || "bge (default)"}`);
792
846
  console.log(`Endpoint: ${endpoint}`);
793
847
  console.log(`Memories: ${data.totalVectors ?? 0}`);
794
848
  console.log(`Tokens: ${data.totalTokens ?? 0}`);
@@ -815,7 +869,7 @@ const memoryRouterPlugin = {
815
869
  ? path.resolve(configWorkspace.replace(/^~/, os.homedir()))
816
870
  : path.join(os.homedir(), ".openclaw", "workspace");
817
871
  const { runUpload } = await import("./upload.js");
818
- 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 });
819
873
  });
820
874
 
821
875
  mr.command("delete")
@@ -823,12 +877,16 @@ const memoryRouterPlugin = {
823
877
  .action(async () => {
824
878
  if (!memoryKey) { console.error("Not configured. Run: openclaw mr <key>"); return; }
825
879
  try {
826
- 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, {
827
884
  method: "DELETE",
828
885
  headers: { Authorization: `Bearer ${memoryKey}` },
829
886
  });
830
887
  const data = (await res.json()) as { message?: string };
831
- console.log(`✓ ${data.message || "Vault cleared"}`);
888
+ const modelLabel = embeddings ? ` (${embeddings})` : "";
889
+ console.log(`✓ ${data.message || `Vault cleared${modelLabel}`}`);
832
890
  } catch (err) {
833
891
  console.error(`Failed: ${err instanceof Error ? err.message : String(err)}`);
834
892
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mr-memory",
3
- "version": "2.16.0",
3
+ "version": "2.18.0",
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
  },