@xdarkicex/openclaw-memory-libravdb 1.4.9 → 1.4.10

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.
@@ -1,6 +1,42 @@
1
1
  import type { PluginRuntime } from "./plugin-runtime.js";
2
2
  import type { LoggerLike, PluginConfig, RecallCache, SearchResult } from "./types.js";
3
3
  import { AssembleContextInternalResponse } from "./generated/libravdb/ipc/v1/rpc_pb.js";
4
+ type KernelCompatibleMessage = {
5
+ role: string;
6
+ content: string;
7
+ id?: string;
8
+ };
9
+ type OpenClawCompatibleMessage = {
10
+ role: string;
11
+ content: string;
12
+ id?: string;
13
+ };
14
+ type OpenClawCompatibleAssembleResult = {
15
+ messages: OpenClawCompatibleMessage[];
16
+ estimatedTokens: number;
17
+ systemPromptAddition: string;
18
+ debug?: AssembleContextInternalResponse["debug"];
19
+ };
20
+ export declare function normalizeKernelMessage(message: {
21
+ role: string;
22
+ content: unknown;
23
+ id?: string;
24
+ }): KernelCompatibleMessage;
25
+ export declare function normalizeKernelMessages(messages: Array<{
26
+ role: string;
27
+ content: unknown;
28
+ id?: string;
29
+ }>): KernelCompatibleMessage[];
30
+ export declare function normalizeAssembleResult(result: {
31
+ messages?: Array<{
32
+ role: string;
33
+ content?: unknown;
34
+ id?: string;
35
+ }>;
36
+ estimatedTokens?: number;
37
+ systemPromptAddition?: string;
38
+ debug?: AssembleContextInternalResponse["debug"];
39
+ }): OpenClawCompatibleAssembleResult;
4
40
  export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: PluginConfig, recallCache: RecallCache<SearchResult>, logger?: LoggerLike): {
5
41
  info: {
6
42
  id: string;
@@ -19,7 +55,7 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
19
55
  userId?: string;
20
56
  message: {
21
57
  role: string;
22
- content: string;
58
+ content: unknown;
23
59
  id?: string;
24
60
  };
25
61
  isHeartbeat?: boolean;
@@ -30,12 +66,12 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
30
66
  userId?: string;
31
67
  messages: Array<{
32
68
  role: string;
33
- content: string;
69
+ content: unknown;
34
70
  id?: string;
35
71
  }>;
36
72
  tokenBudget: number;
37
73
  prompt?: string;
38
- }): Promise<AssembleContextInternalResponse>;
74
+ }): Promise<OpenClawCompatibleAssembleResult>;
39
75
  compact(args: {
40
76
  sessionId: string;
41
77
  force?: boolean;
@@ -47,10 +83,11 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
47
83
  userId?: string;
48
84
  messages: Array<{
49
85
  role: string;
50
- content: string;
86
+ content: unknown;
51
87
  id?: string;
52
88
  }>;
53
89
  prePromptMessageCount?: number;
54
90
  isHeartbeat?: boolean;
55
91
  }): Promise<any>;
56
92
  };
93
+ export {};
@@ -1,3 +1,91 @@
1
+ function describeUnexpectedContent(value) {
2
+ try {
3
+ const serialized = JSON.stringify(value);
4
+ return serialized === undefined ? String(value) : serialized;
5
+ }
6
+ catch {
7
+ return String(value);
8
+ }
9
+ }
10
+ function stringifyKernelBlock(block) {
11
+ if (!block || typeof block !== "object") {
12
+ return "";
13
+ }
14
+ const record = block;
15
+ switch (record.type) {
16
+ case "text":
17
+ return typeof record.text === "string" ? record.text : "";
18
+ case "thinking":
19
+ return typeof record.thinking === "string" ? record.thinking : "";
20
+ case "toolCall": {
21
+ const name = typeof record.name === "string" ? record.name : "tool";
22
+ const args = record.arguments;
23
+ let renderedArgs = "";
24
+ if (typeof args === "string") {
25
+ renderedArgs = args;
26
+ }
27
+ else if (args !== undefined) {
28
+ try {
29
+ renderedArgs = JSON.stringify(args);
30
+ }
31
+ catch {
32
+ renderedArgs = String(args);
33
+ }
34
+ }
35
+ return renderedArgs ? `[tool:${name}] ${renderedArgs}` : `[tool:${name}]`;
36
+ }
37
+ case "image":
38
+ return "[image omitted]";
39
+ default:
40
+ console.warn("[libravdb] unsupported kernel content block", {
41
+ type: record.type,
42
+ block: describeUnexpectedContent(record),
43
+ });
44
+ return typeof record.text === "string" ? record.text : "";
45
+ }
46
+ }
47
+ function normalizeKernelContent(content) {
48
+ if (typeof content === "string") {
49
+ return content;
50
+ }
51
+ if (!Array.isArray(content)) {
52
+ console.warn("[libravdb] unexpected kernel content shape", {
53
+ kind: typeof content,
54
+ value: describeUnexpectedContent(content),
55
+ });
56
+ return "";
57
+ }
58
+ return content.map(stringifyKernelBlock).filter((part) => part.length > 0).join("\n");
59
+ }
60
+ export function normalizeKernelMessage(message) {
61
+ return {
62
+ role: message.role,
63
+ content: normalizeKernelContent(message.content),
64
+ ...(typeof message.id === "string" ? { id: message.id } : {}),
65
+ };
66
+ }
67
+ export function normalizeKernelMessages(messages) {
68
+ return messages.map((message) => normalizeKernelMessage(message));
69
+ }
70
+ export function normalizeAssembleResult(result) {
71
+ const messages = Array.isArray(result.messages)
72
+ ? result.messages.map((message) => ({
73
+ // OpenClaw replay only expects conversational turns here, so assemble output
74
+ // is collapsed to user/assistant even though normalizeKernelMessage preserves
75
+ // richer inbound roles. If kernel.assembleContext starts emitting other roles,
76
+ // this coercion point is where that contract needs to be revisited.
77
+ role: message.role === "user" ? "user" : "assistant",
78
+ content: normalizeKernelContent(message.content),
79
+ ...(typeof message.id === "string" ? { id: message.id } : {}),
80
+ }))
81
+ : [];
82
+ return {
83
+ messages,
84
+ estimatedTokens: typeof result.estimatedTokens === "number" ? result.estimatedTokens : 0,
85
+ systemPromptAddition: typeof result.systemPromptAddition === "string" ? result.systemPromptAddition : "",
86
+ ...(result.debug != null ? { debug: result.debug } : {}),
87
+ };
88
+ }
1
89
  export function buildContextEngineFactory(runtime, cfg, recallCache, logger = console) {
2
90
  return {
3
91
  info: { id: "libravdb-memory", name: "LibraVDB Memory", ownsCompaction: true },
@@ -24,39 +112,44 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
24
112
  return await rpc.call("bootstrap_session_kernel", args);
25
113
  },
26
114
  async ingest(args) {
115
+ const message = normalizeKernelMessage(args.message);
27
116
  const kernel = runtime.getKernel();
28
117
  if (kernel) {
29
118
  return await kernel.ingestMessage({
30
119
  sessionId: args.sessionId,
31
120
  sessionKey: args.sessionKey,
32
121
  userId: args.userId,
33
- message: args.message,
122
+ message,
34
123
  isHeartbeat: args.isHeartbeat,
35
124
  });
36
125
  }
37
126
  const rpc = await runtime.getRpc();
38
- return await rpc.call("ingest_message_kernel", args);
127
+ return await rpc.call("ingest_message_kernel", {
128
+ ...args,
129
+ message,
130
+ });
39
131
  },
40
132
  async assemble(args) {
133
+ const messages = normalizeKernelMessages(args.messages);
41
134
  const kernel = runtime.getKernel();
42
135
  if (kernel) {
43
- return await kernel.assembleContext({
136
+ return normalizeAssembleResult(await kernel.assembleContext({
44
137
  sessionId: args.sessionId,
45
138
  sessionKey: args.sessionKey,
46
139
  userId: args.userId,
47
140
  queryText: args.prompt ?? "",
48
- visibleMessages: args.messages,
141
+ visibleMessages: messages,
49
142
  tokenBudget: args.tokenBudget,
50
143
  config: {},
51
144
  emitDebug: true
52
- });
145
+ }));
53
146
  }
54
147
  const rpc = await runtime.getRpc();
55
148
  const resp = await rpc.call("assemble_context_internal", {
56
149
  sessionId: args.sessionId,
57
150
  sessionKey: args.sessionKey,
58
151
  userId: args.userId,
59
- messages: args.messages,
152
+ messages,
60
153
  tokenBudget: args.tokenBudget,
61
154
  prompt: args.prompt,
62
155
  emitDebug: true,
@@ -92,7 +185,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
92
185
  ingestionGateThreshold: cfg.ingestionGateThreshold,
93
186
  },
94
187
  });
95
- return resp;
188
+ return normalizeAssembleResult(resp);
96
189
  },
97
190
  async compact(args) {
98
191
  const kernel = runtime.getKernel();
@@ -107,19 +200,23 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
107
200
  return await rpc.call("compact_session", args);
108
201
  },
109
202
  async afterTurn(args) {
203
+ const messages = normalizeKernelMessages(args.messages);
110
204
  const kernel = runtime.getKernel();
111
205
  if (kernel) {
112
206
  return await kernel.afterTurn({
113
207
  sessionId: args.sessionId,
114
208
  sessionKey: args.sessionKey,
115
209
  userId: args.userId,
116
- messages: args.messages,
210
+ messages,
117
211
  prePromptMessageCount: args.prePromptMessageCount,
118
212
  isHeartbeat: args.isHeartbeat,
119
213
  });
120
214
  }
121
215
  const rpc = await runtime.getRpc();
122
- return await rpc.call("after_turn_kernel", args);
216
+ return await rpc.call("after_turn_kernel", {
217
+ ...args,
218
+ messages,
219
+ });
123
220
  }
124
221
  };
125
222
  }
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ export default definePluginEntry({
12
12
  id: "libravdb-memory",
13
13
  name: "LibraVDB Memory",
14
14
  description: "Persistent vector memory with three-tier hybrid scoring",
15
- kind: "context-engine",
15
+ kind: ["memory", "context-engine"],
16
16
  register(api) {
17
17
  const cfg = api.pluginConfig;
18
18
  const recallCache = createRecallCache();
@@ -4,6 +4,7 @@ import type { LoggerLike, PluginConfig } from "./types.js";
4
4
  export type RpcGetter = () => Promise<RpcClient>;
5
5
  export declare const DEFAULT_RPC_TIMEOUT_MS = 30000;
6
6
  export declare const STARTUP_HEALTH_TIMEOUT_MS = 2000;
7
+ export declare function resolveStartupHealthTimeoutMs(cfg: PluginConfig): number;
7
8
  export interface LifecycleHint {
8
9
  hook: "before_reset" | "session_end";
9
10
  reason?: string;
@@ -4,6 +4,9 @@ import { daemonProvisioningHint, startSidecar } from "./sidecar.js";
4
4
  import { readFileSync } from "node:fs";
5
5
  export const DEFAULT_RPC_TIMEOUT_MS = 30000;
6
6
  export const STARTUP_HEALTH_TIMEOUT_MS = 2000;
7
+ export function resolveStartupHealthTimeoutMs(cfg) {
8
+ return Math.max(STARTUP_HEALTH_TIMEOUT_MS, cfg.rpcTimeoutMs ?? DEFAULT_RPC_TIMEOUT_MS);
9
+ }
7
10
  export function createPluginRuntime(cfg, logger = console) {
8
11
  let started = null;
9
12
  let stopped = false;
@@ -19,7 +22,7 @@ export function createPluginRuntime(cfg, logger = console) {
19
22
  timeoutMs: cfg.rpcTimeoutMs ?? DEFAULT_RPC_TIMEOUT_MS,
20
23
  });
21
24
  const health = await rpc.call("health", {}, {
22
- timeoutMs: STARTUP_HEALTH_TIMEOUT_MS,
25
+ timeoutMs: resolveStartupHealthTimeoutMs(cfg),
23
26
  });
24
27
  if (!health.ok) {
25
28
  try {
@@ -23,6 +23,13 @@ function normalizeSearchTextResponse(bytes) {
23
23
  }
24
24
  return response;
25
25
  }
26
+ function normalizeAssembleContextInternalResponse(bytes) {
27
+ const response = decodeProtobufResult(AssembleContextInternalResponse, bytes);
28
+ if (!Array.isArray(response.messages)) {
29
+ response.messages = [];
30
+ }
31
+ return response;
32
+ }
26
33
  function normalizeExcludeByCollection(value) {
27
34
  const normalized = {};
28
35
  if (!value) {
@@ -68,7 +75,7 @@ export const rpcProtobufCodecs = {
68
75
  bootstrap_session_kernel: codec((params) => encodeMessage(BootstrapSessionKernelRequest, params), (bytes) => decodeProtobufResult(BootstrapSessionKernelResponse, bytes)),
69
76
  ingest_message_kernel: codec((params) => encodeMessage(IngestMessageKernelRequest, params), (bytes) => decodeProtobufResult(IngestMessageKernelResponse, bytes)),
70
77
  after_turn_kernel: codec((params) => encodeMessage(AfterTurnKernelRequest, params), (bytes) => decodeProtobufResult(AfterTurnKernelResponse, bytes)),
71
- assemble_context_internal: codec((params) => encodeMessage(AssembleContextInternalRequest, params), (bytes) => decodeProtobufResult(AssembleContextInternalResponse, bytes)),
78
+ assemble_context_internal: codec((params) => encodeMessage(AssembleContextInternalRequest, params), normalizeAssembleContextInternalResponse),
72
79
  compact_session: codec((params) => encodeMessage(CompactSessionRequest, params), (bytes) => decodeProtobufResult(CompactSessionResponse, bytes)),
73
80
  rank_candidates: codec((params) => encodeMessage(RankCandidatesRequest, params), (bytes) => decodeProtobufResult(RankCandidatesResponse, bytes)),
74
81
  };
package/dist/rpc.d.ts CHANGED
@@ -8,6 +8,7 @@ export declare class RpcClient {
8
8
  private sentMagic;
9
9
  constructor(socket: SidecarSocket, options: RpcCallOptions);
10
10
  call<T>(method: string, params: unknown, callOptions?: Partial<RpcCallOptions>): Promise<T>;
11
+ private waitForReconnect;
11
12
  private handleData;
12
13
  private dispatchMessage;
13
14
  private rejectAll;
package/dist/rpc.js CHANGED
@@ -26,12 +26,13 @@ export class RpcClient {
26
26
  return await new Promise((resolve, reject) => {
27
27
  const id = ++this.seq;
28
28
  const timeoutMs = callOptions.timeoutMs ?? this.options.timeoutMs;
29
+ const deadline = Date.now() + timeoutMs;
29
30
  const timer = setTimeout(() => {
30
31
  this.pending.delete(id);
31
32
  reject(new Error(`RPC timeout: ${method} (${timeoutMs}ms)`));
32
33
  }, timeoutMs);
33
34
  this.pending.set(id, { resolve, reject, timer, decodeResult: codec.decodeResult });
34
- try {
35
+ const buildFrame = () => {
35
36
  const envelope = new RpcRequest({
36
37
  id,
37
38
  method,
@@ -41,18 +42,93 @@ export class RpcClient {
41
42
  const header = Buffer.alloc(4);
42
43
  header.writeUInt32BE(payload.byteLength, 0);
43
44
  const chunks = [];
44
- if (!this.sentMagic) {
45
+ const includesMagic = !this.sentMagic;
46
+ if (includesMagic) {
45
47
  chunks.push(Buffer.from([0x02]));
46
- this.sentMagic = true;
47
48
  }
48
49
  chunks.push(header, payload);
49
- this.socket.write(Buffer.concat(chunks));
50
- }
51
- catch (error) {
50
+ return { frame: Buffer.concat(chunks), includesMagic };
51
+ };
52
+ const send = (allowReconnectRetry) => {
53
+ if (!this.pending.has(id)) {
54
+ return;
55
+ }
56
+ const { frame, includesMagic } = buildFrame();
57
+ try {
58
+ this.socket.write(frame);
59
+ if (includesMagic) {
60
+ this.sentMagic = true;
61
+ }
62
+ }
63
+ catch (error) {
64
+ if (allowReconnectRetry && isReconnectableSocketGap(error)) {
65
+ this.sentMagic = false;
66
+ const remainingMs = Math.max(0, deadline - Date.now());
67
+ if (remainingMs <= 0) {
68
+ if (!this.pending.has(id)) {
69
+ return;
70
+ }
71
+ clearTimeout(timer);
72
+ this.pending.delete(id);
73
+ reject(new Error(`RPC timeout: ${method} (${timeoutMs}ms)`));
74
+ return;
75
+ }
76
+ void this.waitForReconnect(remainingMs)
77
+ .then(() => {
78
+ if (!this.pending.has(id)) {
79
+ return;
80
+ }
81
+ send(false);
82
+ })
83
+ .catch((reconnectError) => {
84
+ if (!this.pending.has(id)) {
85
+ return;
86
+ }
87
+ clearTimeout(timer);
88
+ this.pending.delete(id);
89
+ reject(reconnectError instanceof Error
90
+ ? reconnectError
91
+ : new Error(String(reconnectError)));
92
+ });
93
+ return;
94
+ }
95
+ clearTimeout(timer);
96
+ this.pending.delete(id);
97
+ reject(error instanceof Error ? error : new Error(String(error)));
98
+ }
99
+ };
100
+ send(true);
101
+ });
102
+ }
103
+ async waitForReconnect(timeoutMs) {
104
+ await new Promise((resolve, reject) => {
105
+ let settled = false;
106
+ const onConnect = () => {
107
+ if (settled)
108
+ return;
109
+ settled = true;
52
110
  clearTimeout(timer);
53
- this.pending.delete(id);
54
- reject(error instanceof Error ? error : new Error(String(error)));
55
- }
111
+ this.socket.off("error", onError);
112
+ resolve();
113
+ };
114
+ const onError = (error) => {
115
+ if (settled)
116
+ return;
117
+ settled = true;
118
+ clearTimeout(timer);
119
+ this.socket.off("connect", onConnect);
120
+ reject(error);
121
+ };
122
+ const timer = setTimeout(() => {
123
+ if (settled)
124
+ return;
125
+ settled = true;
126
+ this.socket.off("connect", onConnect);
127
+ this.socket.off("error", onError);
128
+ reject(new Error(`Sidecar reconnect timed out (${timeoutMs}ms)`));
129
+ }, timeoutMs);
130
+ this.socket.once("connect", onConnect);
131
+ this.socket.once("error", onError);
56
132
  });
57
133
  }
58
134
  handleData(chunk) {
@@ -119,3 +195,6 @@ export class RpcClient {
119
195
  }
120
196
  }
121
197
  }
198
+ function isReconnectableSocketGap(error) {
199
+ return error instanceof Error && /Sidecar socket unavailable/i.test(error.message);
200
+ }
package/dist/sidecar.d.ts CHANGED
@@ -17,6 +17,7 @@ declare class PlaceholderSocket implements SidecarSocket {
17
17
  setEncoding(_encoding: string): void;
18
18
  on(event: "data" | "close" | "error", handler: DataHandler | CloseHandler | ErrorHandler): void;
19
19
  once(event: "connect" | "error", handler: CloseHandler | ErrorHandler): void;
20
+ off(event: "connect" | "error", handler: CloseHandler | ErrorHandler): void;
20
21
  write(chunk: Buffer | string): void;
21
22
  destroy(): void;
22
23
  private emitError;
@@ -28,7 +29,7 @@ export declare function isTcpEndpoint(endpoint: string): boolean;
28
29
  export declare function resolveEndpoint(cfg: PluginConfig): string;
29
30
  export declare function resolveConfiguredEndpoint(cfg: PluginConfig): string;
30
31
  export declare function daemonProvisioningHint(): string;
31
- export declare function defaultEndpoint(platform?: NodeJS.Platform, homeDir?: string): string;
32
+ export declare function defaultEndpoint(platform?: NodeJS.Platform, homeDir?: string, pathExists?: (path: string) => boolean): string;
32
33
  export declare function buildSidecarEnv(cfg: PluginConfig): Record<string, string>;
33
34
  export { PlaceholderSocket };
34
35
  export declare function probeSidecarEndpoint(cfg: PluginConfig): Promise<string | null>;
package/dist/sidecar.js CHANGED
@@ -38,6 +38,13 @@ class PlaceholderSocket {
38
38
  }
39
39
  this.errorOnce.add(handler);
40
40
  }
41
+ off(event, handler) {
42
+ if (event === "connect") {
43
+ this.connectOnce.delete(handler);
44
+ return;
45
+ }
46
+ this.errorOnce.delete(handler);
47
+ }
41
48
  write(chunk) {
42
49
  try {
43
50
  const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
@@ -95,13 +102,15 @@ class SupervisorSocket {
95
102
  connectOnce = new Set();
96
103
  errorOnce = new Set();
97
104
  current;
98
- encoding = "utf8";
105
+ encoding;
99
106
  generation = 0;
100
107
  bind(socket) {
101
108
  this.current = socket;
102
109
  this.generation += 1;
103
110
  const generation = this.generation;
104
- socket.setEncoding(this.encoding);
111
+ if (this.encoding) {
112
+ socket.setEncoding(this.encoding);
113
+ }
105
114
  socket.on("data", (chunk) => {
106
115
  if (generation !== this.generation) {
107
116
  return;
@@ -163,6 +172,13 @@ class SupervisorSocket {
163
172
  }
164
173
  this.errorOnce.add(handler);
165
174
  }
175
+ off(event, handler) {
176
+ if (event === "connect") {
177
+ this.connectOnce.delete(handler);
178
+ return;
179
+ }
180
+ this.errorOnce.delete(handler);
181
+ }
166
182
  write(chunk) {
167
183
  if (!this.current) {
168
184
  throw new Error("Sidecar socket unavailable");
@@ -314,7 +330,7 @@ export function resolveConfiguredEndpoint(cfg) {
314
330
  export function daemonProvisioningHint() {
315
331
  return "If you installed the npm package, install and start libravdbd separately; the package does not provision the daemon binary, ONNX Runtime, or model assets.";
316
332
  }
317
- export function defaultEndpoint(platform = process.platform, homeDir = os.homedir()) {
333
+ export function defaultEndpoint(platform = process.platform, homeDir = os.homedir(), pathExists = fs.existsSync) {
318
334
  // Honour the daemon's own env var first (set by Homebrew LaunchAgent / systemd unit).
319
335
  const envEndpoint = process.env.LIBRAVDB_RPC_ENDPOINT?.trim();
320
336
  if (envEndpoint && isConfiguredEndpoint(envEndpoint)) {
@@ -335,7 +351,7 @@ export function defaultEndpoint(platform = process.platform, homeDir = os.homedi
335
351
  for (const dir of candidateDirs) {
336
352
  const sockPath = path.join(dir, sockName);
337
353
  try {
338
- if (fs.existsSync(sockPath)) {
354
+ if (pathExists(sockPath)) {
339
355
  return `unix:${sockPath}`;
340
356
  }
341
357
  }
package/dist/types.d.ts CHANGED
@@ -131,6 +131,8 @@ export interface SidecarSocket {
131
131
  on(event: "error", handler: (error: Error) => void): void;
132
132
  once(event: "connect", handler: () => void): void;
133
133
  once(event: "error", handler: (error: Error) => void): void;
134
+ off(event: "connect", handler: () => void): void;
135
+ off(event: "error", handler: (error: Error) => void): void;
134
136
  write(chunk: Buffer | string): void;
135
137
  destroy(err?: Error): void;
136
138
  }
package/docs/install.md CHANGED
@@ -67,13 +67,22 @@ If you run the daemon on a non-default endpoint, add a plugin config:
67
67
  }
68
68
  ```
69
69
 
70
+ When `sidecarPath` is set to `"auto"`, the plugin resolves endpoints in this order on macOS/Linux:
71
+
72
+ 1. `LIBRAVDB_RPC_ENDPOINT` if it is set to a valid daemon endpoint
73
+ 2. `$HOME/.clawdb/run/libravdb.sock` if it exists
74
+ 3. `/opt/homebrew/var/clawdb/run/libravdb.sock` if it exists
75
+ 4. `/usr/local/var/clawdb/run/libravdb.sock` if it exists
76
+ 5. fallback to `$HOME/.clawdb/run/libravdb.sock`
77
+
70
78
  ## Sidecar Daemon Install
71
79
 
72
80
  The daemon owns the local database, embeddings, and JSON-RPC endpoint.
73
81
 
74
82
  Default endpoints:
75
83
 
76
- - macOS/Linux: `unix:$HOME/.clawdb/run/libravdb.sock`
84
+ - Homebrew on macOS: `unix:/opt/homebrew/var/clawdb/run/libravdb.sock`
85
+ - macOS/Linux user-local installs: `unix:$HOME/.clawdb/run/libravdb.sock`
77
86
  - Windows: `tcp:127.0.0.1:37421`
78
87
 
79
88
  Default data path:
@@ -142,7 +142,8 @@ Install and start `libravdbd` separately for the same user account that runs Ope
142
142
 
143
143
  Default endpoints:
144
144
 
145
- - macOS/Linux: `unix:$HOME/.clawdb/run/libravdb.sock`
145
+ - Homebrew on macOS: `unix:/opt/homebrew/var/clawdb/run/libravdb.sock`
146
+ - macOS/Linux user-local installs: `unix:$HOME/.clawdb/run/libravdb.sock`
146
147
  - Windows: `tcp:127.0.0.1:37421`
147
148
 
148
149
  If you run the daemon on a different endpoint, set `plugins.configs.libravdb-memory.sidecarPath` in `~/.openclaw/openclaw.json`.
@@ -176,6 +177,18 @@ brew install libravdbd
176
177
  brew services start libravdbd
177
178
  ```
178
179
 
180
+ With `sidecarPath: "auto"`, Homebrew installs on Apple Silicon should resolve to:
181
+
182
+ ```text
183
+ unix:/opt/homebrew/var/clawdb/run/libravdb.sock
184
+ ```
185
+
186
+ User-local installs still default to:
187
+
188
+ ```text
189
+ unix:$HOME/.clawdb/run/libravdb.sock
190
+ ```
191
+
179
192
  The daemon release pipeline generates a publish-ready `libravdbd.rb` formula asset for release assets named:
180
193
 
181
194
  - `libravdbd-darwin-arm64`
@@ -2,17 +2,35 @@
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.9",
6
- "kind": "context-engine",
5
+ "version": "1.4.10",
6
+ "kind": [
7
+ "memory",
8
+ "context-engine"
9
+ ],
7
10
  "configSchema": {
8
11
  "type": "object",
9
12
  "additionalProperties": false,
10
13
  "properties": {
11
- "dbPath": { "type": "string" },
12
- "sidecarPath": { "type": "string" },
13
- "useSessionSummarySearchExperiment": { "type": "boolean" },
14
- "embeddingRuntimePath": { "type": "string" },
15
- "embeddingBackend": { "type": "string", "enum": ["bundled", "onnx-local", "custom-local"] },
14
+ "dbPath": {
15
+ "type": "string"
16
+ },
17
+ "sidecarPath": {
18
+ "type": "string"
19
+ },
20
+ "useSessionSummarySearchExperiment": {
21
+ "type": "boolean"
22
+ },
23
+ "embeddingRuntimePath": {
24
+ "type": "string"
25
+ },
26
+ "embeddingBackend": {
27
+ "type": "string",
28
+ "enum": [
29
+ "bundled",
30
+ "onnx-local",
31
+ "custom-local"
32
+ ]
33
+ },
16
34
  "embeddingProfile": {
17
35
  "type": "string",
18
36
  "default": "all-minilm-l6-v2"
@@ -21,22 +39,60 @@
21
39
  "type": "string",
22
40
  "default": "all-minilm-l6-v2"
23
41
  },
24
- "embeddingModelPath": { "type": "string" },
25
- "embeddingTokenizerPath": { "type": "string" },
26
- "embeddingDimensions": { "type": "number" },
27
- "embeddingNormalize": { "type": "boolean" },
28
- "summarizerBackend": { "type": "string", "enum": ["bundled", "onnx-local", "ollama-local", "custom-local"] },
29
- "summarizerProfile": { "type": "string" },
30
- "summarizerRuntimePath": { "type": "string" },
31
- "summarizerModelPath": { "type": "string" },
32
- "summarizerTokenizerPath": { "type": "string" },
33
- "summarizerModel": { "type": "string" },
34
- "summarizerEndpoint": { "type": "string" },
35
- "sessionTTL": { "type": "number" },
36
- "topK": { "type": "number" },
37
- "alpha": { "type": "number" },
38
- "beta": { "type": "number" },
39
- "gamma": { "type": "number" },
42
+ "embeddingModelPath": {
43
+ "type": "string"
44
+ },
45
+ "embeddingTokenizerPath": {
46
+ "type": "string"
47
+ },
48
+ "embeddingDimensions": {
49
+ "type": "number"
50
+ },
51
+ "embeddingNormalize": {
52
+ "type": "boolean"
53
+ },
54
+ "summarizerBackend": {
55
+ "type": "string",
56
+ "enum": [
57
+ "bundled",
58
+ "onnx-local",
59
+ "ollama-local",
60
+ "custom-local"
61
+ ]
62
+ },
63
+ "summarizerProfile": {
64
+ "type": "string"
65
+ },
66
+ "summarizerRuntimePath": {
67
+ "type": "string"
68
+ },
69
+ "summarizerModelPath": {
70
+ "type": "string"
71
+ },
72
+ "summarizerTokenizerPath": {
73
+ "type": "string"
74
+ },
75
+ "summarizerModel": {
76
+ "type": "string"
77
+ },
78
+ "summarizerEndpoint": {
79
+ "type": "string"
80
+ },
81
+ "sessionTTL": {
82
+ "type": "number"
83
+ },
84
+ "topK": {
85
+ "type": "number"
86
+ },
87
+ "alpha": {
88
+ "type": "number"
89
+ },
90
+ "beta": {
91
+ "type": "number"
92
+ },
93
+ "gamma": {
94
+ "type": "number"
95
+ },
40
96
  "ingestionGateThreshold": {
41
97
  "type": "number",
42
98
  "default": 0.35
@@ -47,7 +103,9 @@
47
103
  },
48
104
  "markdownIngestionRoots": {
49
105
  "type": "array",
50
- "items": { "type": "string" }
106
+ "items": {
107
+ "type": "string"
108
+ }
51
109
  },
52
110
  "markdownIngestionObsidianEnabled": {
53
111
  "type": "boolean",
@@ -55,15 +113,21 @@
55
113
  },
56
114
  "markdownIngestionObsidianRoots": {
57
115
  "type": "array",
58
- "items": { "type": "string" }
116
+ "items": {
117
+ "type": "string"
118
+ }
59
119
  },
60
120
  "markdownIngestionObsidianInclude": {
61
121
  "type": "array",
62
- "items": { "type": "string" }
122
+ "items": {
123
+ "type": "string"
124
+ }
63
125
  },
64
126
  "markdownIngestionObsidianExclude": {
65
127
  "type": "array",
66
- "items": { "type": "string" }
128
+ "items": {
129
+ "type": "string"
130
+ }
67
131
  },
68
132
  "markdownIngestionObsidianDebounceMs": {
69
133
  "type": "number",
@@ -71,11 +135,15 @@
71
135
  },
72
136
  "markdownIngestionInclude": {
73
137
  "type": "array",
74
- "items": { "type": "string" }
138
+ "items": {
139
+ "type": "string"
140
+ }
75
141
  },
76
142
  "markdownIngestionExclude": {
77
143
  "type": "array",
78
- "items": { "type": "string" }
144
+ "items": {
145
+ "type": "string"
146
+ }
79
147
  },
80
148
  "markdownIngestionCollection": {
81
149
  "type": "string",
@@ -103,16 +171,38 @@
103
171
  "type": "object",
104
172
  "additionalProperties": false,
105
173
  "default": {
106
- "w1c": 0.35, "w2c": 0.40, "w3c": 0.25,
107
- "w1t": 0.40, "w2t": 0.35, "w3t": 0.25
174
+ "w1c": 0.35,
175
+ "w2c": 0.4,
176
+ "w3c": 0.25,
177
+ "w1t": 0.4,
178
+ "w2t": 0.35,
179
+ "w3t": 0.25
108
180
  },
109
181
  "properties": {
110
- "w1c": { "type": "number", "default": 0.35 },
111
- "w2c": { "type": "number", "default": 0.40 },
112
- "w3c": { "type": "number", "default": 0.25 },
113
- "w1t": { "type": "number", "default": 0.40 },
114
- "w2t": { "type": "number", "default": 0.35 },
115
- "w3t": { "type": "number", "default": 0.25 }
182
+ "w1c": {
183
+ "type": "number",
184
+ "default": 0.35
185
+ },
186
+ "w2c": {
187
+ "type": "number",
188
+ "default": 0.4
189
+ },
190
+ "w3c": {
191
+ "type": "number",
192
+ "default": 0.25
193
+ },
194
+ "w1t": {
195
+ "type": "number",
196
+ "default": 0.4
197
+ },
198
+ "w2t": {
199
+ "type": "number",
200
+ "default": 0.35
201
+ },
202
+ "w3t": {
203
+ "type": "number",
204
+ "default": 0.25
205
+ }
116
206
  }
117
207
  },
118
208
  "gatingTechNorm": {
@@ -132,21 +222,42 @@
132
222
  "default": 0.5,
133
223
  "description": "Controls how much summary confidence affects retrieval score. 0 ignores summary quality and 1 fully suppresses zero-confidence summaries."
134
224
  },
135
- "recencyLambdaSession": { "type": "number" },
136
- "recencyLambdaUser": { "type": "number" },
137
- "recencyLambdaGlobal": { "type": "number" },
138
- "tokenBudgetFraction": { "type": "number" },
139
- "compactThreshold": { "type": "number" },
225
+ "recencyLambdaSession": {
226
+ "type": "number"
227
+ },
228
+ "recencyLambdaUser": {
229
+ "type": "number"
230
+ },
231
+ "recencyLambdaGlobal": {
232
+ "type": "number"
233
+ },
234
+ "tokenBudgetFraction": {
235
+ "type": "number"
236
+ },
237
+ "compactThreshold": {
238
+ "type": "number"
239
+ },
140
240
  "compactSessionTokenBudget": {
141
241
  "type": "number",
142
242
  "default": 2000,
143
243
  "description": "Auto-trigger compaction when the session accumulates this many tokens since the last compaction. Set to 0 to disable auto-compaction."
144
244
  },
145
- "ollamaUrl": { "type": "string" },
146
- "compactModel": { "type": "string" },
147
- "rpcTimeoutMs": { "type": "number", "default": 30000 },
148
- "maxRetries": { "type": "number" },
149
- "logLevel": { "type": "string" }
245
+ "ollamaUrl": {
246
+ "type": "string"
247
+ },
248
+ "compactModel": {
249
+ "type": "string"
250
+ },
251
+ "rpcTimeoutMs": {
252
+ "type": "number",
253
+ "default": 30000
254
+ },
255
+ "maxRetries": {
256
+ "type": "number"
257
+ },
258
+ "logLevel": {
259
+ "type": "string"
260
+ }
150
261
  }
151
262
  }
152
263
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdarkicex/openclaw-memory-libravdb",
3
- "version": "1.4.9",
3
+ "version": "1.4.10",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",