mr-memory 3.3.0 → 3.4.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 (2) hide show
  1. package/index.ts +36 -8
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -271,6 +271,7 @@ type MemoryRouterConfig = {
271
271
  mode?: "relay" | "proxy";
272
272
  logging?: boolean;
273
273
  embeddings?: string;
274
+ agentKeys?: Record<string, string>;
274
275
  };
275
276
 
276
277
  // ──────────────────────────────────────────────────────
@@ -380,10 +381,28 @@ const memoryRouterPlugin = {
380
381
  const mode = cfg?.mode || "relay";
381
382
  const logging = cfg?.logging ?? false;
382
383
  const embeddings = cfg?.embeddings; // undefined = bge (default), "qwen" = qwen3-8b
384
+ const agentKeys = cfg?.agentKeys;
383
385
  const log = (msg: string) => { if (logging) api.logger.info?.(msg); };
384
386
 
385
- if (memoryKey) {
386
- api.logger.info?.(`memoryrouter: active (key: ${memoryKey.slice(0, 6)}...)`);
387
+ // Resolve the correct memory key for a given agent context.
388
+ // Multi-agent gateways: each agent gets its own key via agentKeys map.
389
+ // Single-agent: falls back to the global key.
390
+ function resolveKey(ctx: any): string | undefined {
391
+ if (agentKeys && ctx?.workspaceDir) {
392
+ // Derive agentId from workspace path: ~/.openclaw/workspace-rex → "rex"
393
+ // Default workspace (~/.openclaw/workspace) → "main"
394
+ const dirName = ctx.workspaceDir.split("/").pop() || "";
395
+ const agentId = dirName === "workspace" ? "main" : dirName.replace(/^workspace-/, "");
396
+ if (agentId && agentKeys[agentId]) return agentKeys[agentId];
397
+ }
398
+ return memoryKey;
399
+ }
400
+
401
+ const hasAnyKey = !!(memoryKey || (agentKeys && Object.keys(agentKeys).length > 0));
402
+
403
+ if (hasAnyKey) {
404
+ if (memoryKey) api.logger.info?.(`memoryrouter: active (key: ${memoryKey.slice(0, 6)}...)`);
405
+ if (agentKeys) api.logger.info?.(`memoryrouter: ${Object.keys(agentKeys).length} agent key(s) configured`);
387
406
  } else {
388
407
  api.logger.info?.("memoryrouter: no key configured — run: openclaw mr <key>");
389
408
  api.logger.info?.("memoryrouter: get your free API key at https://memoryrouter.ai");
@@ -393,7 +412,7 @@ const memoryRouterPlugin = {
393
412
  // Core: before_agent_start — search memories, inject context
394
413
  // ==================================================================
395
414
 
396
- if (memoryKey) {
415
+ if (hasAnyKey) {
397
416
  // Track whether we've already fired for this prompt (dedup double-fire)
398
417
  let lastPreparedPrompt = "";
399
418
  // Track whether before_prompt_build already handled the first call in this run
@@ -411,6 +430,9 @@ const memoryRouterPlugin = {
411
430
  return;
412
431
  }
413
432
 
433
+ const activeKey = resolveKey(ctx);
434
+ if (!activeKey) return; // No key for this agent
435
+
414
436
  try {
415
437
  const startMs = Date.now();
416
438
  const prompt = event.prompt;
@@ -451,7 +473,7 @@ const memoryRouterPlugin = {
451
473
  method: "POST",
452
474
  headers: {
453
475
  "Content-Type": "application/json",
454
- Authorization: `Bearer ${memoryKey}`,
476
+ Authorization: `Bearer ${activeKey}`,
455
477
  },
456
478
  body: JSON.stringify({
457
479
  messages: contextPayload,
@@ -491,6 +513,8 @@ const memoryRouterPlugin = {
491
513
  // ── before_prompt_build: fires once per run (primary, includes full billing context)
492
514
  api.on("before_prompt_build", async (event, ctx) => {
493
515
  promptBuildFiredThisRun = true;
516
+ const activeKey = resolveKey(ctx);
517
+ if (!activeKey) return; // No key for this agent
494
518
  try {
495
519
  const startMs = Date.now();
496
520
  const prompt = event.prompt;
@@ -561,7 +585,7 @@ const memoryRouterPlugin = {
561
585
  method: "POST",
562
586
  headers: {
563
587
  "Content-Type": "application/json",
564
- Authorization: `Bearer ${memoryKey}`,
588
+ Authorization: `Bearer ${activeKey}`,
565
589
  },
566
590
  body: JSON.stringify({
567
591
  messages: contextPayload,
@@ -605,6 +629,8 @@ const memoryRouterPlugin = {
605
629
  // ==================================================================
606
630
 
607
631
  api.on("agent_end", async (event, ctx) => {
632
+ const activeKey = resolveKey(ctx);
633
+ if (!activeKey) return; // No key for this agent
608
634
  try {
609
635
  const msgs = event.messages;
610
636
  if (!msgs || !Array.isArray(msgs) || msgs.length === 0) return;
@@ -677,7 +703,7 @@ const memoryRouterPlugin = {
677
703
  method: "POST",
678
704
  headers: {
679
705
  "Content-Type": "application/json",
680
- Authorization: `Bearer ${memoryKey}`,
706
+ Authorization: `Bearer ${activeKey}`,
681
707
  },
682
708
  body: JSON.stringify({
683
709
  messages: toStore,
@@ -711,6 +737,7 @@ const memoryRouterPlugin = {
711
737
 
712
738
  // memory_search — calls MR /v1/memory/search
713
739
  api.registerTool((ctx) => {
740
+ const toolKey = resolveKey(ctx);
714
741
  return {
715
742
  label: "Memory Search",
716
743
  name: "memory_search",
@@ -725,6 +752,7 @@ const memoryRouterPlugin = {
725
752
  required: ["query"],
726
753
  } as any,
727
754
  execute: async (_toolCallId: string, params: Record<string, unknown>) => {
755
+ if (!toolKey) return jsonToolResult({ results: [], error: "No memory key configured for this agent" });
728
756
  const query = typeof params.query === "string" ? params.query.trim() : "";
729
757
  if (!query) return jsonToolResult({ results: [], error: "query required" });
730
758
  const limit = typeof params.maxResults === "number" ? params.maxResults : 50;
@@ -732,7 +760,7 @@ const memoryRouterPlugin = {
732
760
  const res = await fetch(`${endpoint}/v1/memory/search`, {
733
761
  method: "POST",
734
762
  headers: {
735
- Authorization: `Bearer ${memoryKey}`,
763
+ Authorization: `Bearer ${toolKey}`,
736
764
  "Content-Type": "application/json",
737
765
  ...(embeddings && { "X-Embedding-Model": embeddings }),
738
766
  },
@@ -807,7 +835,7 @@ const memoryRouterPlugin = {
807
835
  },
808
836
  };
809
837
  });
810
- } // end if (memoryKey)
838
+ } // end if (hasAnyKey)
811
839
 
812
840
  // ==================================================================
813
841
  // CLI Commands
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mr-memory",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "MemoryRouter persistent memory plugin for OpenClaw — your AI remembers every conversation",
5
5
  "type": "module",
6
6
  "files": [