@xdarkicex/openclaw-memory-libravdb 1.4.23 → 1.4.25

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
@@ -20,7 +20,7 @@ assembly; durable recall; and sidecar-owned compaction.
20
20
 
21
21
  New install? Start here: [Install guide](./docs/install.md). Preferred setup on
22
22
  macOS: install `libravdbd` with Homebrew, install the OpenClaw plugin, then
23
- assign the plugin to both required slots.
23
+ assign the plugin to the OpenClaw memory slot.
24
24
 
25
25
  ## Install
26
26
 
@@ -31,18 +31,20 @@ brew services start libravdbd
31
31
  openclaw plugins install @xdarkicex/openclaw-memory-libravdb
32
32
  ```
33
33
 
34
- Then activate both plugin slots in `~/.openclaw/openclaw.json`:
34
+ Then activate the plugin in `~/.openclaw/openclaw.json`:
35
35
 
36
36
  ```json
37
37
  {
38
38
  "plugins": {
39
39
  "slots": {
40
- "memory": "libravdb-memory",
41
- "contextEngine": "libravdb-memory"
40
+ "memory": "libravdb-memory"
42
41
  },
43
- "configs": {
42
+ "entries": {
44
43
  "libravdb-memory": {
45
- "sidecarPath": "auto"
44
+ "enabled": true,
45
+ "config": {
46
+ "sidecarPath": "auto"
47
+ }
46
48
  }
47
49
  }
48
50
  }
@@ -78,9 +80,12 @@ If your daemon runs elsewhere, set `sidecarPath`:
78
80
  ```json
79
81
  {
80
82
  "plugins": {
81
- "configs": {
83
+ "entries": {
82
84
  "libravdb-memory": {
83
- "sidecarPath": "tcp:127.0.0.1:37421"
85
+ "enabled": true,
86
+ "config": {
87
+ "sidecarPath": "tcp:127.0.0.1:37421"
88
+ }
84
89
  }
85
90
  }
86
91
  }
@@ -89,7 +94,8 @@ If your daemon runs elsewhere, set `sidecarPath`:
89
94
 
90
95
  ## Highlights
91
96
 
92
- - **Dual slot ownership** - owns both OpenClaw `memory` and `contextEngine`.
97
+ - **Memory capability ownership** - owns the OpenClaw `memory` slot and
98
+ registers the context engine capability at runtime.
93
99
  - **Memory runtime bridge** - routes built-in `memory_search` calls to the same
94
100
  libraVDB-backed sidecar on hosts that expose the runtime API.
95
101
  - **Three memory scopes** - keeps active session, durable user, and global memory
@@ -1,5 +1,5 @@
1
1
  import type { PluginRuntime } from "./plugin-runtime.js";
2
- import type { LoggerLike, PluginConfig, RecallCache, SearchResult } from "./types.js";
2
+ import type { LoggerLike, PluginConfig } from "./types.js";
3
3
  import { AssembleContextInternalResponse } from "@xdarkicex/libravdb-contracts";
4
4
  type KernelCompatibleMessage = {
5
5
  role: string;
@@ -49,7 +49,7 @@ export declare function normalizeAssembleResult(result: {
49
49
  systemPromptAddition?: string;
50
50
  debug?: AssembleContextInternalResponse["debug"];
51
51
  }): OpenClawCompatibleAssembleResult;
52
- export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: PluginConfig, recallCache: RecallCache<SearchResult>, logger?: LoggerLike): {
52
+ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: PluginConfig, logger?: LoggerLike): {
53
53
  info: {
54
54
  id: string;
55
55
  name: string;
@@ -332,7 +332,7 @@ export function normalizeAssembleResult(result) {
332
332
  ...(result.debug != null ? { debug: result.debug } : {}),
333
333
  };
334
334
  }
335
- export function buildContextEngineFactory(runtime, cfg, recallCache, logger = console) {
335
+ export function buildContextEngineFactory(runtime, cfg, logger = console) {
336
336
  let cachedIdentity = null;
337
337
  function resolveUserId(args) {
338
338
  // Framework-provided userId takes priority (channels, future SDK compat).
@@ -350,6 +350,16 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
350
350
  return cachedIdentity.userId;
351
351
  }
352
352
  const getDynamicCompactThreshold = (tokenBudget) => resolveDynamicCompactThreshold(tokenBudget, cfg.compactThreshold, cfg.compactionThresholdFraction);
353
+ async function getKernelOrNull(phase) {
354
+ try {
355
+ return await runtime.getKernel();
356
+ }
357
+ catch (error) {
358
+ logger.warn?.(`LibraVDB ${phase} kernel unavailable, falling back to sidecar: ` +
359
+ `${error instanceof Error ? error.message : String(error)}`);
360
+ return null;
361
+ }
362
+ }
353
363
  const buildAssemblyConfig = (tokenBudget) => ({
354
364
  useSessionRecallProjection: cfg.useSessionRecallProjection,
355
365
  useSessionSummarySearchExperiment: cfg.useSessionSummarySearchExperiment,
@@ -475,7 +485,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
475
485
  }
476
486
  async function runCompaction(args) {
477
487
  const request = buildCompactSessionRequest(args);
478
- const kernel = runtime.getKernel();
488
+ const kernel = await getKernelOrNull("compact");
479
489
  try {
480
490
  if (kernel) {
481
491
  return normalizeCompactResult(await kernel.compactSession(request), {
@@ -544,7 +554,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
544
554
  });
545
555
  logger.info?.(`LibraVDB bootstrap sessionId=${args.sessionId} userId=${userId} ` +
546
556
  `sessionKey=${args.sessionKey ?? "(none)"}`);
547
- const kernel = runtime.getKernel();
557
+ const kernel = await getKernelOrNull("bootstrap");
548
558
  if (kernel) {
549
559
  try {
550
560
  await kernel.initializeSession({
@@ -577,7 +587,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
577
587
  `role=${message.role} heartbeat=${args.isHeartbeat ?? false} ` +
578
588
  `contentLen=${message.content.length}`);
579
589
  try {
580
- const kernel = runtime.getKernel();
590
+ const kernel = await getKernelOrNull("ingest");
581
591
  if (kernel) {
582
592
  return await kernel.ingestMessage({
583
593
  sessionId: args.sessionId,
@@ -650,7 +660,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
650
660
  return buildBudgetFallbackContext(messages, args.tokenBudget);
651
661
  }
652
662
  }
653
- const kernel = runtime.getKernel();
663
+ const kernel = await getKernelOrNull("assemble");
654
664
  if (kernel) {
655
665
  try {
656
666
  const assembled = normalizeAssembleResult(await kernel.assembleContext({
@@ -713,7 +723,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
713
723
  logger.info?.(`LibraVDB afterTurn sessionId=${args.sessionId} userId=${userId} ` +
714
724
  `messageCount=${msgCount} heartbeat=${args.isHeartbeat ?? false}`);
715
725
  try {
716
- const kernel = runtime.getKernel();
726
+ const kernel = await getKernelOrNull("afterTurn");
717
727
  const currentTokenCount = normalizeCurrentTokenCount(typeof args.runtimeContext?.currentTokenCount === "number"
718
728
  ? args.runtimeContext.currentTokenCount
719
729
  : undefined);
package/dist/index.js CHANGED
@@ -7,7 +7,6 @@ import { createDreamPromotionHandle } from "./dream-promotion.js";
7
7
  import { createMarkdownIngestionHandle } from "./markdown-ingest.js";
8
8
  import { buildMemoryPromptSection } from "./memory-provider.js";
9
9
  import { buildMemoryRuntimeBridge } from "./memory-runtime.js";
10
- import { createRecallCache } from "./recall-cache.js";
11
10
  import { createPluginRuntime } from "./plugin-runtime.js";
12
11
  export const MEMORY_ID = "libravdb-memory";
13
12
  const LIGHTWEIGHT_MODES = new Set(["cli-metadata", "setup-only"]);
@@ -51,7 +50,6 @@ export function register(api) {
51
50
  const runtime = runtimeOrNull;
52
51
  if (!runtime)
53
52
  return; // unreachable but satisfies the type checker
54
- const recallCache = createRecallCache();
55
53
  // Exclusive slot check: refuse to register if another plugin owns the memory slot.
56
54
  // plugins.slots.memory is the only configurable slot; context engine exclusivity
57
55
  // is enforced by the registry at runtime (no config surface for it).
@@ -63,12 +61,18 @@ export function register(api) {
63
61
  }
64
62
  // Migrated from three legacy calls to a single registerMemoryCapability.
65
63
  api.registerMemoryCapability(MEMORY_ID, {
66
- promptBuilder: buildMemoryPromptSection(runtime.getRpc, cfg, recallCache),
64
+ promptBuilder: buildMemoryPromptSection(runtime.getRpc, cfg),
67
65
  runtime: buildMemoryRuntimeBridge(runtime.getRpc, cfg),
68
66
  });
69
- api.registerContextEngine(MEMORY_ID, () => buildContextEngineFactory(runtime, cfg, recallCache, api.logger ?? console));
67
+ api.registerContextEngine(MEMORY_ID, () => buildContextEngineFactory(runtime, cfg, api.logger ?? console));
70
68
  const markdownIngestion = createMarkdownIngestionHandle(cfg, runtime.getRpc, api.logger ?? console);
71
69
  const dreamPromotion = createDreamPromotionHandle(cfg, runtime.getRpc, api.logger ?? console);
70
+ runtime.onShutdown(async () => {
71
+ await markdownIngestion.stop();
72
+ });
73
+ runtime.onShutdown(async () => {
74
+ await dreamPromotion.stop();
75
+ });
72
76
  void markdownIngestion.start().catch((error) => {
73
77
  api.logger?.warn?.(`LibraVDB markdown ingestion failed to start: ${error instanceof Error ? error.message : String(error)}`);
74
78
  });
@@ -78,8 +82,6 @@ export function register(api) {
78
82
  api.on("before_reset", createBeforeResetHook(runtime, api.logger ?? console));
79
83
  api.on("session_end", createSessionEndHook(runtime, api.logger ?? console));
80
84
  api.on("gateway_stop", async () => {
81
- await dreamPromotion.stop();
82
- await markdownIngestion.stop();
83
85
  await runtime.shutdown();
84
86
  });
85
87
  }
@@ -73,9 +73,11 @@ class DirectoryMarkdownSourceAdapter {
73
73
  logger;
74
74
  states = new Map();
75
75
  fileStates = new Map();
76
+ activeScans = new Set();
76
77
  tokenizerId;
77
78
  coreDoc;
78
79
  started = false;
80
+ stopping = false;
79
81
  constructor(kind, config, getRpc, logger, fsApi) {
80
82
  this.kind = kind;
81
83
  this.roots = config.roots;
@@ -93,10 +95,11 @@ class DirectoryMarkdownSourceAdapter {
93
95
  return;
94
96
  }
95
97
  this.started = true;
98
+ this.stopping = false;
96
99
  await this.refresh();
97
100
  }
98
101
  async refresh() {
99
- if (!this.started) {
102
+ if (!this.started || this.stopping) {
100
103
  return;
101
104
  }
102
105
  for (const root of this.roots) {
@@ -104,6 +107,7 @@ class DirectoryMarkdownSourceAdapter {
104
107
  }
105
108
  }
106
109
  async stop() {
110
+ this.stopping = true;
107
111
  for (const state of this.states.values()) {
108
112
  if (state.scanState.timer) {
109
113
  clearTimeout(state.scanState.timer);
@@ -114,6 +118,9 @@ class DirectoryMarkdownSourceAdapter {
114
118
  }
115
119
  state.directoryWatchers.clear();
116
120
  }
121
+ if (this.activeScans.size > 0) {
122
+ await Promise.allSettled([...this.activeScans]);
123
+ }
117
124
  this.states.clear();
118
125
  this.fileStates.clear();
119
126
  this.started = false;
@@ -138,27 +145,46 @@ class DirectoryMarkdownSourceAdapter {
138
145
  return created;
139
146
  }
140
147
  async scanRoot(root) {
148
+ if (!this.started || this.stopping) {
149
+ return;
150
+ }
141
151
  const rootState = this.getRootState(root);
142
152
  if (rootState.scanState.scanning) {
143
153
  rootState.scanState.dirty = true;
144
154
  return;
145
155
  }
146
156
  rootState.scanState.scanning = true;
157
+ const scan = (async () => {
158
+ try {
159
+ const currentFiles = new Set();
160
+ await this.walkDirectory(rootState, rootState.root, currentFiles);
161
+ if (!this.stopping) {
162
+ await this.pruneDeletedFiles(rootState, currentFiles);
163
+ rootState.knownFiles = currentFiles;
164
+ }
165
+ }
166
+ finally {
167
+ rootState.scanState.scanning = false;
168
+ if (rootState.scanState.dirty) {
169
+ rootState.scanState.dirty = false;
170
+ if (!this.stopping) {
171
+ this.scheduleRootScan(rootState);
172
+ }
173
+ }
174
+ }
175
+ })();
176
+ this.activeScans.add(scan);
147
177
  try {
148
- const currentFiles = new Set();
149
- await this.walkDirectory(rootState, rootState.root, currentFiles);
150
- await this.pruneDeletedFiles(rootState, currentFiles);
151
- rootState.knownFiles = currentFiles;
178
+ await scan;
152
179
  }
153
180
  finally {
154
- rootState.scanState.scanning = false;
155
- if (rootState.scanState.dirty) {
156
- rootState.scanState.dirty = false;
157
- this.scheduleRootScan(rootState);
158
- }
181
+ this.activeScans.delete(scan);
159
182
  }
160
183
  }
161
184
  scheduleRootScan(rootState) {
185
+ if (!this.started || this.stopping) {
186
+ return;
187
+ }
162
188
  if (rootState.scanState.scanning) {
163
189
  rootState.scanState.dirty = true;
164
190
  return;
@@ -187,6 +213,9 @@ class DirectoryMarkdownSourceAdapter {
187
213
  return;
188
214
  }
189
215
  for (const entry of entries) {
216
+ if (this.stopping) {
217
+ return;
218
+ }
190
219
  const child = path.join(dir, entry.name);
191
220
  if (entry.isDirectory()) {
192
221
  await this.walkDirectory(rootState, child, currentFiles);
@@ -203,7 +232,9 @@ class DirectoryMarkdownSourceAdapter {
203
232
  await this.syncMarkdownFile(rootState, child);
204
233
  }
205
234
  catch (error) {
206
- this.logger.warn?.(`[markdown-ingest] sync failed for ${child}: ${formatError(error)}`);
235
+ if (!this.stopping) {
236
+ this.logger.warn?.(`[markdown-ingest] sync failed for ${child}: ${formatError(error)}`);
237
+ }
207
238
  }
208
239
  }
209
240
  }
@@ -213,7 +244,9 @@ class DirectoryMarkdownSourceAdapter {
213
244
  }
214
245
  try {
215
246
  const watcher = this.fsApi.watch(dir, () => {
216
- this.scheduleRootScan(rootState);
247
+ if (!this.stopping) {
248
+ this.scheduleRootScan(rootState);
249
+ }
217
250
  });
218
251
  watcher.on("error", (error) => {
219
252
  this.logger.warn?.(`[markdown-ingest] watch error for ${dir}: ${formatError(error)}`);
@@ -1,4 +1,4 @@
1
1
  import type { MemoryPromptSectionBuilder } from "openclaw/plugin-sdk/plugin-entry";
2
- import type { PluginConfig, RecallCache, SearchResult } from "./types.js";
2
+ import type { PluginConfig } from "./types.js";
3
3
  import type { RpcGetter } from "./plugin-runtime.js";
4
- export declare function buildMemoryPromptSection(_getRpc: RpcGetter, _cfg: PluginConfig, _recallCache: RecallCache<SearchResult>): MemoryPromptSectionBuilder;
4
+ export declare function buildMemoryPromptSection(_getRpc: RpcGetter, _cfg: PluginConfig): MemoryPromptSectionBuilder;
@@ -4,7 +4,7 @@ const MEMORY_PROMPT_HEADER = [
4
4
  "in context via the context-engine assembler when available and relevant.",
5
5
  "",
6
6
  ];
7
- export function buildMemoryPromptSection(_getRpc, _cfg, _recallCache) {
7
+ export function buildMemoryPromptSection(_getRpc, _cfg) {
8
8
  return function memoryPromptSection({ availableTools: _availableTools, citationsMode: _citationsMode, }) {
9
9
  // OpenClaw builds the memory prompt section synchronously for embedded runs.
10
10
  // Actual retrieval and ranking happen in the context engine during assemble().
@@ -19,10 +19,12 @@ export interface LifecycleHint {
19
19
  nextSessionId?: string;
20
20
  nextSessionKey?: string;
21
21
  }
22
+ export type RuntimeShutdownTask = () => Promise<void> | void;
22
23
  export interface PluginRuntime {
23
24
  getRpc: RpcGetter;
24
- getKernel(): GrpcKernelClient | null;
25
+ getKernel(): Promise<GrpcKernelClient | null>;
25
26
  emitLifecycleHint(hint: LifecycleHint): Promise<void>;
27
+ onShutdown(task: RuntimeShutdownTask): void;
26
28
  shutdown(): Promise<void>;
27
29
  }
28
30
  export declare function createPluginRuntime(cfg: PluginConfig, logger?: LoggerLike): PluginRuntime;
@@ -10,7 +10,8 @@ export function resolveStartupHealthTimeoutMs(cfg) {
10
10
  export function createPluginRuntime(cfg, logger = console) {
11
11
  let started = null;
12
12
  let stopped = false;
13
- let resolvedKernel = null;
13
+ let shuttingDown = false;
14
+ const shutdownTasks = [];
14
15
  const ensureStarted = async () => {
15
16
  if (stopped) {
16
17
  throw new Error("LibraVDB plugin runtime has been shut down");
@@ -47,7 +48,6 @@ export function createPluginRuntime(cfg, logger = console) {
47
48
  logger.warn?.(`LibraVDB: failed to initialize gRPC kernel client: ${formatError(error)}`);
48
49
  }
49
50
  }
50
- resolvedKernel = kernel;
51
51
  return { rpc, sidecar, kernel };
52
52
  })().catch((error) => {
53
53
  started = null;
@@ -60,10 +60,8 @@ export function createPluginRuntime(cfg, logger = console) {
60
60
  async getRpc() {
61
61
  return (await ensureStarted()).rpc;
62
62
  },
63
- getKernel() {
64
- if (!started)
65
- return null;
66
- return resolvedKernel;
63
+ async getKernel() {
64
+ return (await ensureStarted()).kernel;
67
65
  },
68
66
  async emitLifecycleHint(hint) {
69
67
  try {
@@ -74,7 +72,25 @@ export function createPluginRuntime(cfg, logger = console) {
74
72
  logger.warn?.(`LibraVDB lifecycle hint dropped: ${formatError(error)}`);
75
73
  }
76
74
  },
75
+ onShutdown(task) {
76
+ if (stopped || shuttingDown) {
77
+ return;
78
+ }
79
+ shutdownTasks.push(task);
80
+ },
77
81
  async shutdown() {
82
+ if (stopped || shuttingDown) {
83
+ return;
84
+ }
85
+ shuttingDown = true;
86
+ for (const task of shutdownTasks.splice(0).reverse()) {
87
+ try {
88
+ await task();
89
+ }
90
+ catch (error) {
91
+ logger.warn?.(`LibraVDB shutdown task failed: ${formatError(error)}`);
92
+ }
93
+ }
78
94
  stopped = true;
79
95
  if (!started) {
80
96
  return;
package/dist/types.d.ts CHANGED
@@ -163,17 +163,3 @@ export interface SidecarHandle {
163
163
  export interface RpcCallOptions {
164
164
  timeoutMs: number;
165
165
  }
166
- export interface RecallCacheEntry<T = unknown> {
167
- userId: string;
168
- queryText: string;
169
- durableVariantHits: T[];
170
- userHits?: T[];
171
- globalHits?: T[];
172
- authoredVariantHits?: T[];
173
- }
174
- export interface RecallCache<T = unknown> {
175
- put(entry: RecallCacheEntry<T>): void;
176
- get(key: Pick<RecallCacheEntry<T>, "userId" | "queryText">): RecallCacheEntry<T> | undefined;
177
- take(key: Pick<RecallCacheEntry<T>, "userId" | "queryText">): RecallCacheEntry<T> | undefined;
178
- clearUser(userId: string): void;
179
- }
@@ -8,8 +8,8 @@ internal sequencing.
8
8
 
9
9
  LibraVDB Memory is split into two cooperating pieces:
10
10
 
11
- - a TypeScript OpenClaw plugin that owns the `memory` and `contextEngine`
12
- slots
11
+ - a TypeScript OpenClaw plugin that owns the `memory` slot and registers
12
+ context-engine capability at runtime
13
13
  - a Go sidecar daemon that owns storage, retrieval, and compaction
14
14
 
15
15
  The plugin keeps the host integration light and stable. The daemon keeps the
package/docs/features.md CHANGED
@@ -27,16 +27,19 @@ Example:
27
27
  ```json
28
28
  {
29
29
  "plugins": {
30
- "configs": {
30
+ "entries": {
31
31
  "libravdb-memory": {
32
- "markdownIngestionEnabled": true,
33
- "markdownIngestionRoots": [
34
- "/Users/<you>/.openclaw/memory"
35
- ],
36
- "markdownIngestionObsidianEnabled": true,
37
- "markdownIngestionObsidianRoots": [
38
- "/Users/<you>/Documents/Obsidian/Main"
39
- ]
32
+ "enabled": true,
33
+ "config": {
34
+ "markdownIngestionEnabled": true,
35
+ "markdownIngestionRoots": [
36
+ "/Users/<you>/.openclaw/memory"
37
+ ],
38
+ "markdownIngestionObsidianEnabled": true,
39
+ "markdownIngestionObsidianRoots": [
40
+ "/Users/<you>/Documents/Obsidian/Main"
41
+ ]
42
+ }
40
43
  }
41
44
  }
42
45
  }
@@ -84,12 +87,15 @@ Automatic diary watching:
84
87
  ```json
85
88
  {
86
89
  "plugins": {
87
- "configs": {
90
+ "entries": {
88
91
  "libravdb-memory": {
89
- "dreamPromotionEnabled": true,
90
- "dreamPromotionDiaryPath": "/Users/<you>/DREAMS.md",
91
- "dreamPromotionUserId": "<userId>",
92
- "dreamPromotionDebounceMs": 150
92
+ "enabled": true,
93
+ "config": {
94
+ "dreamPromotionEnabled": true,
95
+ "dreamPromotionDiaryPath": "/Users/<you>/DREAMS.md",
96
+ "dreamPromotionUserId": "<userId>",
97
+ "dreamPromotionDebounceMs": 150
98
+ }
93
99
  }
94
100
  }
95
101
  }
package/docs/install.md CHANGED
@@ -37,8 +37,7 @@ openclaw plugins install @xdarkicex/openclaw-memory-libravdb
37
37
  ```
38
38
 
39
39
  If you use the OpenClaw.ai plugin UI instead of the CLI, install the same
40
- package and then assign the plugin id `libravdb-memory` to both the `memory`
41
- and `contextEngine` slots.
40
+ package and then assign the plugin id `libravdb-memory` to the `memory` slot.
42
41
 
43
42
  Activate the plugin in `~/.openclaw/openclaw.json`:
44
43
 
@@ -46,8 +45,7 @@ Activate the plugin in `~/.openclaw/openclaw.json`:
46
45
  {
47
46
  "plugins": {
48
47
  "slots": {
49
- "memory": "libravdb-memory",
50
- "contextEngine": "libravdb-memory"
48
+ "memory": "libravdb-memory"
51
49
  }
52
50
  }
53
51
  }
@@ -59,12 +57,14 @@ If you run the daemon on a non-default endpoint, add a plugin config:
59
57
  {
60
58
  "plugins": {
61
59
  "slots": {
62
- "memory": "libravdb-memory",
63
- "contextEngine": "libravdb-memory"
60
+ "memory": "libravdb-memory"
64
61
  },
65
- "configs": {
62
+ "entries": {
66
63
  "libravdb-memory": {
67
- "sidecarPath": "unix:/Users/<you>/.clawdb/run/libravdb.sock"
64
+ "enabled": true,
65
+ "config": {
66
+ "sidecarPath": "unix:/Users/<you>/.clawdb/run/libravdb.sock"
67
+ }
68
68
  }
69
69
  }
70
70
  }
@@ -158,7 +158,7 @@ you wrap it in `brew services`, `systemd`, or `launchd`.
158
158
  ### Plugin Lifecycle
159
159
 
160
160
  - Install the package with `openclaw plugins install`.
161
- - Activate it by assigning `libravdb-memory` to both `memory` and `contextEngine`.
161
+ - Activate it by assigning `libravdb-memory` to the `memory` slot.
162
162
  - Update it with your normal OpenClaw plugin update flow.
163
163
  - Disable it by removing the slot assignment from `~/.openclaw/openclaw.json`.
164
164
 
@@ -60,21 +60,20 @@ or run `libravdbd serve` in a terminal for validation.
60
60
 
61
61
  ## Activation
62
62
 
63
- Assign `libravdb-memory` to both OpenClaw slots:
63
+ Assign `libravdb-memory` to the OpenClaw memory slot:
64
64
 
65
65
  ```json
66
66
  {
67
67
  "plugins": {
68
68
  "slots": {
69
- "memory": "libravdb-memory",
70
- "contextEngine": "libravdb-memory"
69
+ "memory": "libravdb-memory"
71
70
  }
72
71
  }
73
72
  }
74
73
  ```
75
74
 
76
- Treat partial assignment as a misconfiguration. This plugin is designed to own
77
- memory prompt injection and the context-engine lifecycle together.
75
+ The plugin registers both memory and context-engine capabilities at runtime;
76
+ current OpenClaw config only needs the `memory` slot assignment.
78
77
 
79
78
  If the daemon uses a non-default endpoint, add `sidecarPath`:
80
79
 
@@ -82,12 +81,14 @@ If the daemon uses a non-default endpoint, add `sidecarPath`:
82
81
  {
83
82
  "plugins": {
84
83
  "slots": {
85
- "memory": "libravdb-memory",
86
- "contextEngine": "libravdb-memory"
84
+ "memory": "libravdb-memory"
87
85
  },
88
- "configs": {
86
+ "entries": {
89
87
  "libravdb-memory": {
90
- "sidecarPath": "unix:/Users/<you>/.clawdb/run/libravdb.sock"
88
+ "enabled": true,
89
+ "config": {
90
+ "sidecarPath": "unix:/Users/<you>/.clawdb/run/libravdb.sock"
91
+ }
91
92
  }
92
93
  }
93
94
  }
@@ -177,9 +178,9 @@ setup, or republish the release with corrected checksums.
177
178
 
178
179
  ### Default memory still appears active
179
180
 
180
- Confirm that `libravdb-memory` is assigned to both `memory` and
181
- `contextEngine`. Without both slot entries, OpenClaw's default memory path can
182
- continue to run in parallel.
181
+ Confirm that `libravdb-memory` is assigned to `plugins.slots.memory`.
182
+ Without that slot entry, OpenClaw's default memory path can continue to run in
183
+ parallel.
183
184
 
184
185
  ### Lifecycle journal looks empty
185
186
 
package/docs/uninstall.md CHANGED
@@ -18,9 +18,9 @@ Remove the plugin from the active OpenClaw slot in `~/.openclaw/openclaw.json`:
18
18
  }
19
19
  ```
20
20
 
21
- Treat that JSON as a minimal example only. If you assigned `libravdb-memory`
22
- under both `memory` and `contextEngine`, remove those two slot entries and
23
- leave any other plugin slots intact.
21
+ Treat that JSON as a minimal example only. If you assigned
22
+ `libravdb-memory` under `memory`, remove that slot entry and leave any other
23
+ plugin slots intact.
24
24
 
25
25
  If you installed the package through the OpenClaw.ai plugin UI, remove or
26
26
  disable the same package there as well. If you use the CLI, remove it through
@@ -2,7 +2,7 @@
2
2
  "id": "libravdb-memory",
3
3
  "name": "LibraVDB Memory",
4
4
  "description": "Persistent vector memory with three-tier hybrid scoring",
5
- "version": "1.4.23",
5
+ "version": "1.4.25",
6
6
  "kind": [
7
7
  "memory",
8
8
  "context-engine"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdarkicex/openclaw-memory-libravdb",
3
- "version": "1.4.23",
3
+ "version": "1.4.25",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -1,2 +0,0 @@
1
- import type { RecallCache } from "./types.js";
2
- export declare function createRecallCache<T = unknown>(): RecallCache<T>;
@@ -1,30 +0,0 @@
1
- export function createRecallCache() {
2
- const entries = new Map();
3
- return {
4
- put(entry) {
5
- entries.set(cacheKey(entry.userId, entry.queryText), entry);
6
- },
7
- get(key) {
8
- return entries.get(cacheKey(key.userId, key.queryText));
9
- },
10
- take(key) {
11
- const id = cacheKey(key.userId, key.queryText);
12
- const hit = entries.get(id);
13
- if (hit) {
14
- entries.delete(id);
15
- }
16
- return hit;
17
- },
18
- clearUser(userId) {
19
- const prefix = `${userId}\n`;
20
- for (const key of entries.keys()) {
21
- if (key.startsWith(prefix)) {
22
- entries.delete(key);
23
- }
24
- }
25
- },
26
- };
27
- }
28
- function cacheKey(userId, queryText) {
29
- return `${userId}\n${queryText}`;
30
- }