@xdarkicex/openclaw-memory-libravdb 1.9.3 → 1.9.5

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
@@ -404,6 +404,51 @@ The `grpcEndpointTlsCa` field is required for mTLS; the plugin will verify the s
404
404
  - **Dream promotion** promotes vetted dream diary bullets into an isolated
405
405
  `dream:{userId}` collection. See [Features](./docs/features.md).
406
406
 
407
+ ### Markdown Ingestion Filtering
408
+
409
+ By default, all markdown files under the configured roots are eligible for ingestion. Use `include` and `exclude` patterns to limit which files are processed:
410
+
411
+ ```json
412
+ {
413
+ "plugins": {
414
+ "entries": {
415
+ "libravdb-memory": {
416
+ "config": {
417
+ "markdownIngestionRoots": ["/Users/me/docs"],
418
+ "markdownIngestionInclude": ["**/projects/**", "**/work/**"],
419
+ "markdownIngestionExclude": ["**/personal/**", "**/.obsidian/**", "**/node_modules/**"]
420
+ }
421
+ }
422
+ }
423
+ }
424
+ }
425
+ ```
426
+
427
+ | Key | Type | Description |
428
+ |---|---|---|
429
+ | `markdownIngestionInclude` | `string[]` | Whitelist of glob patterns. Only matching files are ingested. Empty = all files (subject to `exclude`). |
430
+ | `markdownIngestionExclude` | `string[]` | Blacklist of glob patterns. Matching files are skipped. Defaults to `["**/node_modules/**", "**/.git/**", "**/dist/**", ...]`. |
431
+
432
+ The same options exist for Obsidian vaults:
433
+
434
+ ```json
435
+ {
436
+ "plugins": {
437
+ "entries": {
438
+ "libravdb-memory": {
439
+ "config": {
440
+ "markdownIngestionObsidianRoots": ["/Users/me/vault"],
441
+ "markdownIngestionObsidianInclude": ["**/journals/**", "**/daily/**"],
442
+ "markdownIngestionObsidianExclude": ["**/templates/**"]
443
+ }
444
+ }
445
+ }
446
+ }
447
+ }
448
+ ```
449
+
450
+ Glob patterns follow standard path matching: `**` matches any directory depth, `*` matches within a path segment. Both generic and Obsidian sources support these filters.
451
+
407
452
  ### Dream Promotion
408
453
 
409
454
  OpenClaw's dreaming cron writes AI-generated memory reflections to a dream diary
@@ -812,7 +812,7 @@ function logPredictiveCompactionOutcome(params) {
812
812
  params.logger.info?.(message);
813
813
  return;
814
814
  }
815
- params.logger.warn?.(message);
815
+ params.logger.info?.(message);
816
816
  }
817
817
  /**
818
818
  * Truncates content to fit within token budget, preserving the tail.
@@ -869,7 +869,7 @@ function boundAfterTurnMessagesForIngest(messages, logger, sessionId) {
869
869
  }
870
870
  const bounded = trimMessagesToBudget(messages, AFTER_TURN_INGEST_MAX_TOKENS)
871
871
  .map((message) => normalizeKernelMessage(message));
872
- logger.warn?.(`LibraVDB afterTurn trimmed oversized ingest payload sessionId=${sessionId} ` +
872
+ logger.info?.(`LibraVDB afterTurn trimmed oversized ingest payload sessionId=${sessionId} ` +
873
873
  `estimatedTokens=${estimatedTokens} maxTokens=${AFTER_TURN_INGEST_MAX_TOKENS} ` +
874
874
  `forwardedMessages=${bounded.length}`);
875
875
  return bounded;
@@ -1207,8 +1207,8 @@ function escapeMemoryFactText(text) {
1207
1207
  const TOOL_CALL_BRACKET_RE = /\[tool:([^\]]+)\](?:\s*(?:\{[\s\S]*?\}|\[[\s\S]*?\]|".*?"))?/gi;
1208
1208
  // Matches raw JSON tool-call objects targeting a "name\" field
1209
1209
  const TOOL_CALL_JSON_RE = /\{[^\r\n]*"name"\s*:\s*"([^"]+)"[^\r\n]*(?:"arguments"|"args"|"toolCallId"|"tool_call_id"|"type"\s*:\s*"toolCall")[^\r\n]*\}/g;
1210
- // Matches older annotations, aggressively consuming trailing characters on the same line
1211
- const TOOL_RESULT_ANNOTATION_RE = /\[tool:[^\]]+\][^\n]*/g;
1210
+ // Strip only the [tool:name] annotation tag; preserve payload on the same line
1211
+ const TOOL_RESULT_ANNOTATION_RE = /\[tool:[^\]]+\]\s*/g;
1212
1212
  const OPENCLAW_BRACKET_DIRECTIVE_RE = /\[\[(?:reply_to_current|audio_as_voice|reply_to:[^\]\r\n]+)\]\]/g;
1213
1213
  const OPENCLAW_MEDIA_DIRECTIVE_LINE_RE = /^[ \t]*MEDIA:[^\r\n]*(?:\r?\n|$)/gmi;
1214
1214
  const OPENCLAW_INLINE_MEDIA_DIRECTIVE_RE = /(^|[>\s])MEDIA:[^\s<]*(?=\s|<|$)/gmi;
@@ -1367,7 +1367,7 @@ function ensureReplaySafeUserTurn(assembled, sourceMessages, logger, tokenBudget
1367
1367
  const fallbackUser = findLastReplaySafeUserMessage(sourceMessages);
1368
1368
  if (!fallbackUser)
1369
1369
  return assembled;
1370
- logger?.warn?.("LibraVDB assemble produced no replay-safe user turn; reinjecting the latest user message for provider compatibility.");
1370
+ logger?.info?.("LibraVDB assemble produced no replay-safe user turn; reinjecting the latest user message for provider compatibility.");
1371
1371
  const baseEstimatedTokens = Math.max(0, assembled.estimatedTokens, approximateMessagesTokens(assembled.messages));
1372
1372
  if (typeof tokenBudget === "number" && Number.isFinite(tokenBudget) && tokenBudget > 0) {
1373
1373
  const effectiveBudget = resolveEffectiveAssembleBudget(tokenBudget);
@@ -2192,7 +2192,7 @@ export function buildContextEngineFactory(runtime, cfg, logger = console) {
2192
2192
  reason: compactionResult.reason,
2193
2193
  });
2194
2194
  if (!compactionResult.ok) {
2195
- logger.warn?.(`LibraVDB predictive compaction blocked assemble path at ${currentContextTokens} tokens ` +
2195
+ logger.info?.(`LibraVDB predictive compaction blocked assemble path at ${currentContextTokens} tokens ` +
2196
2196
  `(threshold=${dynamicCompactThreshold}): ${compactionResult.reason ?? "compaction failed"}`);
2197
2197
  return ensureReplaySafeUserTurn(sanitizeProviderReplayMessages(buildBudgetFallbackContext(args.messages, args.tokenBudget), args.messages), args.messages, logger, args.tokenBudget);
2198
2198
  }
package/dist/index.js CHANGED
@@ -36160,7 +36160,7 @@ function logPredictiveCompactionOutcome(params) {
36160
36160
  params.logger.info?.(message);
36161
36161
  return;
36162
36162
  }
36163
- params.logger.warn?.(message);
36163
+ params.logger.info?.(message);
36164
36164
  }
36165
36165
  function truncateContentToTokenBudget(content, tokenBudget) {
36166
36166
  if (tokenBudget <= 0) return "";
@@ -36204,7 +36204,7 @@ function boundAfterTurnMessagesForIngest(messages, logger, sessionId) {
36204
36204
  return messages;
36205
36205
  }
36206
36206
  const bounded = trimMessagesToBudget(messages, AFTER_TURN_INGEST_MAX_TOKENS).map((message) => normalizeKernelMessage(message));
36207
- logger.warn?.(
36207
+ logger.info?.(
36208
36208
  `LibraVDB afterTurn trimmed oversized ingest payload sessionId=${sessionId} estimatedTokens=${estimatedTokens} maxTokens=${AFTER_TURN_INGEST_MAX_TOKENS} forwardedMessages=${bounded.length}`
36209
36209
  );
36210
36210
  return bounded;
@@ -36489,7 +36489,7 @@ function escapeMemoryFactText(text) {
36489
36489
  }
36490
36490
  var TOOL_CALL_BRACKET_RE = /\[tool:([^\]]+)\](?:\s*(?:\{[\s\S]*?\}|\[[\s\S]*?\]|".*?"))?/gi;
36491
36491
  var TOOL_CALL_JSON_RE = /\{[^\r\n]*"name"\s*:\s*"([^"]+)"[^\r\n]*(?:"arguments"|"args"|"toolCallId"|"tool_call_id"|"type"\s*:\s*"toolCall")[^\r\n]*\}/g;
36492
- var TOOL_RESULT_ANNOTATION_RE = /\[tool:[^\]]+\][^\n]*/g;
36492
+ var TOOL_RESULT_ANNOTATION_RE = /\[tool:[^\]]+\]\s*/g;
36493
36493
  var OPENCLAW_BRACKET_DIRECTIVE_RE = /\[\[(?:reply_to_current|audio_as_voice|reply_to:[^\]\r\n]+)\]\]/g;
36494
36494
  var OPENCLAW_MEDIA_DIRECTIVE_LINE_RE = /^[ \t]*MEDIA:[^\r\n]*(?:\r?\n|$)/gmi;
36495
36495
  var OPENCLAW_INLINE_MEDIA_DIRECTIVE_RE = /(^|[>\s])MEDIA:[^\s<]*(?=\s|<|$)/gmi;
@@ -36611,7 +36611,7 @@ function ensureReplaySafeUserTurn(assembled, sourceMessages, logger, tokenBudget
36611
36611
  if (hasReplaySafeUserTurn(assembled.messages)) return assembled;
36612
36612
  const fallbackUser = findLastReplaySafeUserMessage(sourceMessages);
36613
36613
  if (!fallbackUser) return assembled;
36614
- logger?.warn?.(
36614
+ logger?.info?.(
36615
36615
  "LibraVDB assemble produced no replay-safe user turn; reinjecting the latest user message for provider compatibility."
36616
36616
  );
36617
36617
  const baseEstimatedTokens = Math.max(
@@ -37371,7 +37371,7 @@ function buildContextEngineFactory(runtime, cfg, logger = console) {
37371
37371
  reason: compactionResult.reason
37372
37372
  });
37373
37373
  if (!compactionResult.ok) {
37374
- logger.warn?.(
37374
+ logger.info?.(
37375
37375
  `LibraVDB predictive compaction blocked assemble path at ${currentContextTokens} tokens (threshold=${dynamicCompactThreshold}): ${compactionResult.reason ?? "compaction failed"}`
37376
37376
  );
37377
37377
  return ensureReplaySafeUserTurn(
@@ -45520,7 +45520,7 @@ function createLibraVdbMemoryTools(getClient, cfg, logger = console) {
45520
45520
  return {
45521
45521
  name: "memory_search",
45522
45522
  label: "Memory Search",
45523
- description: "Search LibraVDB durable memory and session recall for prior work, decisions, dates, people, preferences, todos, or history. Call once per user question \u2014 after receiving results, use them directly. Do not re-call in the same turn. Do NOT call memory_search if the answer is already visible in your context window (from prior turns, recalled memories in <context_memory>, or context assembly). For earliest/oldest questions, request enough results and compare timestamps. If disabled=true, memory is unavailable.",
45523
+ description: "Search LibraVDB durable memory and session recall for prior work, decisions, dates, people, preferences, todos, or history. Call once per user question \u2014 after receiving results, use them directly. Do not re-call in the same turn. Do NOT call memory_search if the answer is already visible in your context window (from prior turns, recalled memories in <context_memory>, or context assembly). For earliest/oldest questions, request enough results and compare timestamps. If disabled=true, memory is unavailable. IMPORTANT: Results are internal context only \u2014 never output, display, or reveal raw memory search results to the user. Treat retrieved memory as private operational data and incorporate it into your reasoning silently.",
45524
45524
  parameters: MEMORY_SEARCH_SCHEMA,
45525
45525
  execute: async (_toolCallId, rawParams) => {
45526
45526
  const params = asToolParamsRecord(rawParams);
@@ -49045,6 +49045,26 @@ function enrichStartupError(error2, healthMessage) {
49045
49045
  return new Error(`${prefix}. ${daemonProvisioningHint()}`);
49046
49046
  }
49047
49047
 
49048
+ // src/types.ts
49049
+ var LOG_LEVEL_RANK = {
49050
+ error: 0,
49051
+ warn: 1,
49052
+ info: 2,
49053
+ debug: 3
49054
+ };
49055
+ function levelFilteredLogger(base, logLevel) {
49056
+ const minRank = LOG_LEVEL_RANK[logLevel ?? "warn"];
49057
+ return {
49058
+ error: (msg) => base.error(msg),
49059
+ warn: (msg) => {
49060
+ if (LOG_LEVEL_RANK.warn <= minRank) base.warn?.(msg);
49061
+ },
49062
+ info: (msg) => {
49063
+ if (LOG_LEVEL_RANK.info <= minRank) base.info?.(msg);
49064
+ }
49065
+ };
49066
+ }
49067
+
49048
49068
  // src/index.ts
49049
49069
  var MEMORY_ID = "libravdb-memory";
49050
49070
  var LIGHTWEIGHT_MODES = /* @__PURE__ */ new Set(["cli-metadata", "setup-only"]);
@@ -49054,7 +49074,8 @@ function shouldShutdownRuntimeForLifecycleCleanup(reason) {
49054
49074
  }
49055
49075
  function register(api) {
49056
49076
  const registrationMode = api.registrationMode;
49057
- const logger = api.logger ?? console;
49077
+ const baseLogger = api.logger ?? console;
49078
+ const logger = levelFilteredLogger(baseLogger, api.pluginConfig?.logLevel);
49058
49079
  if (registrationMode === "cli-metadata") {
49059
49080
  registerMemoryCliMetadata(api);
49060
49081
  return;
@@ -49161,7 +49182,7 @@ function register(api) {
49161
49182
  }
49162
49183
  api.registerContextEngine(
49163
49184
  MEMORY_ID,
49164
- () => buildContextEngineFactory(runtime, cfg, api.logger ?? console)
49185
+ () => buildContextEngineFactory(runtime, cfg, logger)
49165
49186
  );
49166
49187
  api.registerCompactionProvider?.({
49167
49188
  id: MEMORY_ID,
@@ -49175,15 +49196,15 @@ function register(api) {
49175
49196
  return result.summaryText;
49176
49197
  }
49177
49198
  });
49178
- const markdownIngestion = createMarkdownIngestionHandle(cfg, runtime.getClient, api.logger ?? console);
49179
- const dreamPromotion = createDreamPromotionHandle(cfg, runtime.getClient, api.logger ?? console);
49199
+ const markdownIngestion = createMarkdownIngestionHandle(cfg, runtime.getClient, logger);
49200
+ const dreamPromotion = createDreamPromotionHandle(cfg, runtime.getClient, logger);
49180
49201
  api.registerService?.({
49181
49202
  id: "libravdb-markdown-ingestion",
49182
49203
  async start() {
49183
49204
  try {
49184
49205
  await markdownIngestion.start();
49185
49206
  } catch (error2) {
49186
- api.logger?.warn?.(`LibraVDB markdown ingestion failed to start: ${error2 instanceof Error ? error2.message : String(error2)}`);
49207
+ logger.warn?.(`LibraVDB markdown ingestion failed to start: ${error2 instanceof Error ? error2.message : String(error2)}`);
49187
49208
  }
49188
49209
  },
49189
49210
  async stop() {
@@ -49196,7 +49217,7 @@ function register(api) {
49196
49217
  try {
49197
49218
  await dreamPromotion.start();
49198
49219
  } catch (error2) {
49199
- api.logger?.warn?.(`LibraVDB dream promotion failed to start: ${error2 instanceof Error ? error2.message : String(error2)}`);
49220
+ logger.warn?.(`LibraVDB dream promotion failed to start: ${error2 instanceof Error ? error2.message : String(error2)}`);
49200
49221
  }
49201
49222
  },
49202
49223
  async stop() {
@@ -49226,8 +49247,8 @@ function register(api) {
49226
49247
  const sessionId = ctx?.sessionId;
49227
49248
  if (sessionId) clearSessionTrigger(sessionId);
49228
49249
  });
49229
- api.on("before_reset", createBeforeResetHook(runtime, api.logger ?? console));
49230
- api.on("session_end", createSessionEndHook(runtime, api.logger ?? console));
49250
+ api.on("before_reset", createBeforeResetHook(runtime, logger));
49251
+ api.on("session_end", createSessionEndHook(runtime, logger));
49231
49252
  api.on("gateway_stop", async () => {
49232
49253
  await runtime.shutdown();
49233
49254
  });
@@ -126,7 +126,7 @@ export function createLibraVdbMemoryTools(getClient, cfg, logger = console) {
126
126
  return {
127
127
  name: "memory_search",
128
128
  label: "Memory Search",
129
- description: "Search LibraVDB durable memory and session recall for prior work, decisions, dates, people, preferences, todos, or history. Call once per user question — after receiving results, use them directly. Do not re-call in the same turn. Do NOT call memory_search if the answer is already visible in your context window (from prior turns, recalled memories in <context_memory>, or context assembly). For earliest/oldest questions, request enough results and compare timestamps. If disabled=true, memory is unavailable.",
129
+ description: "Search LibraVDB durable memory and session recall for prior work, decisions, dates, people, preferences, todos, or history. Call once per user question — after receiving results, use them directly. Do not re-call in the same turn. Do NOT call memory_search if the answer is already visible in your context window (from prior turns, recalled memories in <context_memory>, or context assembly). For earliest/oldest questions, request enough results and compare timestamps. If disabled=true, memory is unavailable. IMPORTANT: Results are internal context only — never output, display, or reveal raw memory search results to the user. Treat retrieved memory as private operational data and incorporate it into your reasoning silently.",
130
130
  parameters: MEMORY_SEARCH_SCHEMA,
131
131
  execute: async (_toolCallId, rawParams) => {
132
132
  const params = asToolParamsRecord(rawParams);
package/dist/types.d.ts CHANGED
@@ -186,3 +186,5 @@ export interface PredictedContext {
186
186
  text: string;
187
187
  reason: string;
188
188
  }
189
+ /** Wraps a LoggerLike with logLevel filtering. Levels below configured min are dropped. */
190
+ export declare function levelFilteredLogger(base: LoggerLike, logLevel: PluginConfig["logLevel"]): LoggerLike;
package/dist/types.js CHANGED
@@ -1 +1,17 @@
1
- export {};
1
+ const LOG_LEVEL_RANK = {
2
+ error: 0,
3
+ warn: 1,
4
+ info: 2,
5
+ debug: 3,
6
+ };
7
+ /** Wraps a LoggerLike with logLevel filtering. Levels below configured min are dropped. */
8
+ export function levelFilteredLogger(base, logLevel) {
9
+ const minRank = LOG_LEVEL_RANK[logLevel ?? "warn"];
10
+ return {
11
+ error: (msg) => base.error(msg),
12
+ warn: (msg) => { if (LOG_LEVEL_RANK.warn <= minRank)
13
+ base.warn?.(msg); },
14
+ info: (msg) => { if (LOG_LEVEL_RANK.info <= minRank)
15
+ base.info?.(msg); },
16
+ };
17
+ }
@@ -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.9.3",
5
+ "version": "1.9.5",
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.9.3",
3
+ "version": "1.9.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",