@memoryrelay/plugin-memoryrelay-ai 0.16.3 → 0.17.1

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
@@ -5,7 +5,7 @@
5
5
  Persistent memory, architectural decisions, reusable patterns, and project orchestration for AI agents.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@memoryrelay/plugin-memoryrelay-ai.svg)](https://www.npmjs.com/package/@memoryrelay/plugin-memoryrelay-ai)
8
- [![OpenClaw Compatible](https://img.shields.io/badge/OpenClaw-2026.2.0+-blue.svg)](https://openclaw.ai)
8
+ [![OpenClaw Compatible](https://img.shields.io/badge/OpenClaw-2026.3.28+-blue.svg)](https://openclaw.ai)
9
9
 
10
10
  ## Why MemoryRelay?
11
11
 
@@ -34,6 +34,18 @@ MemoryRelay is designed for engineering teams managing complex, long-running pro
34
34
  openclaw plugins install @memoryrelay/plugin-memoryrelay-ai
35
35
  ```
36
36
 
37
+ **1b. Install native dependencies (for local SQLite cache)**
38
+
39
+ The local cache requires `better-sqlite3`, which includes native bindings. After plugin installation, run:
40
+
41
+ ```bash
42
+ cd ~/.openclaw/extensions/plugin-memoryrelay-ai && npm install --omit=dev
43
+ ```
44
+
45
+ Or install globally: `npm install -g better-sqlite3`
46
+
47
+ > **Note:** If you skip this step, the plugin still works — it falls back to API-only mode (no local cache).
48
+
37
49
  **2. Set your API key**
38
50
 
39
51
  ```bash
@@ -226,6 +238,7 @@ openclaw config set plugins.entries.plugin-memoryrelay-ai.config '{
226
238
  | `excludeChannels` | string[] | `[]` | Channel IDs to skip auto-recall |
227
239
  | `sessionTimeoutMinutes` | number | `120` | Idle time before session auto-close (10-1440) |
228
240
  | `sessionCleanupIntervalMinutes` | number | `30` | Stale session check interval (5-360) |
241
+ | `localCache` | object | see below | Local SQLite cache configuration (v0.17.0+) |
229
242
  | `debug` | boolean | `false` | Enable debug logging of API calls |
230
243
  | `verbose` | boolean | `false` | Include request/response bodies in logs |
231
244
  | `maxLogEntries` | number | `100` | Circular buffer size for in-memory logs (10-10000) |
@@ -239,6 +252,33 @@ openclaw config set plugins.entries.plugin-memoryrelay-ai.config '{
239
252
  | `MEMORYRELAY_API_URL` | `apiUrl` |
240
253
  | `MEMORYRELAY_DEFAULT_PROJECT` | `defaultProject` |
241
254
 
255
+ ### Local Cache Configuration (v0.17.0+)
256
+
257
+ ```json
258
+ {
259
+ "localCache": {
260
+ "enabled": true,
261
+ "dbPath": "~/.openclaw/memoryrelay-cache.db",
262
+ "syncIntervalMinutes": 5,
263
+ "maxLocalMemories": 10000,
264
+ "vectorSearch": { "enabled": false, "provider": "sqlite-vec" },
265
+ "ttl": { "hot": 72, "warm": 168, "cold": 720 }
266
+ }
267
+ }
268
+ ```
269
+
270
+ | Key | Type | Default | Description |
271
+ |-----|------|---------|-------------|
272
+ | `localCache.enabled` | boolean | `true` | Enable local SQLite cache |
273
+ | `localCache.dbPath` | string | `~/.openclaw/memoryrelay-cache.db` | Path to SQLite database |
274
+ | `localCache.syncIntervalMinutes` | number | `5` | Background sync interval (1-60) |
275
+ | `localCache.maxLocalMemories` | number | `10000` | Max memories stored locally |
276
+ | `localCache.vectorSearch.enabled` | boolean | `false` | Enable sqlite-vec vector search |
277
+ | `localCache.vectorSearch.provider` | string | `sqlite-vec` | Vector extension provider |
278
+ | `localCache.ttl.hot` | number | `72` | Hot tier TTL in hours (3 days) |
279
+ | `localCache.ttl.warm` | number | `168` | Warm tier TTL in hours (7 days) |
280
+ | `localCache.ttl.cold` | number | `720` | Cold tier TTL in hours (30 days) |
281
+
242
282
  ### Auto-Capture Tiers
243
283
 
244
284
  | Tier | Behavior | Use When |
@@ -267,6 +307,22 @@ The `confirmFirst` setting (default: `5`) prompts for confirmation on the first
267
307
  }
268
308
  ```
269
309
 
310
+ ## Performance (v0.17.0+)
311
+
312
+ With local cache enabled (default in v0.17.0), most operations skip API round-trips entirely:
313
+
314
+ | Operation | API-only (v0.16) | Local cache (v0.17) | Improvement |
315
+ |-----------|------------------|---------------------|-------------|
316
+ | Recall | ~200–500ms | <5ms | 40–100× |
317
+ | Capture | ~150–300ms | <2ms | 75–150× |
318
+ | Status probe | ~100ms | <1ms | 100× |
319
+
320
+ The local cache uses SQLite (better-sqlite3) with FTS5 for full-text search. An optional sqlite-vec extension enables local vector similarity search without API round-trips.
321
+
322
+ SyncDaemon runs in the background, pushing buffered writes and pulling remote changes on a configurable interval (default: 5 minutes).
323
+
324
+ > **Note:** v0.17.0 also fixes the `· unavailable` status display in `openclaw status` — the plugin now returns real memory counts from the local cache.
325
+
270
326
  ## Architecture & Privacy
271
327
 
272
328
  ### Data Flow
@@ -383,6 +439,92 @@ Then inspect with `/memory-logs` or `/memory-metrics` to identify slow or failin
383
439
 
384
440
  - `memory_batch_store`: May return 500 errors on large batches (use individual `memory_store` as workaround)
385
441
 
442
+ ## VPS Setup
443
+
444
+ Complete guide for running Claude Code with MemoryRelay on a VPS (Ubuntu).
445
+
446
+ ### Prerequisites
447
+
448
+ - Node.js 20+
449
+ - [OpenClaw](https://openclaw.ai) installed and configured
450
+ - [Claude Code](https://claude.ai/code) CLI installed
451
+
452
+ ### 1. Install the MCP server
453
+
454
+ ```bash
455
+ npm install -g @memoryrelay/mcp-server
456
+ ```
457
+
458
+ ### 2. Configure Claude Code settings
459
+
460
+ Add the MemoryRelay MCP server to `~/.claude/settings.json`:
461
+
462
+ ```json
463
+ {
464
+ "mcpServers": {
465
+ "MemoryRelay": {
466
+ "command": "memoryrelay-mcp",
467
+ "args": ["--agent-id", "YOUR_AGENT_UUID"],
468
+ "env": {
469
+ "MEMORYRELAY_API_KEY": "mem_prod_your_key_here"
470
+ }
471
+ }
472
+ }
473
+ }
474
+ ```
475
+
476
+ > **Important:** `agentId` must be a UUID obtained from `GET /v1/agents` — not a name string. Using a name string will cause authentication failures.
477
+
478
+ ### 3. Install the OpenClaw plugin
479
+
480
+ ```bash
481
+ openclaw plugins install @memoryrelay/plugin-memoryrelay-ai
482
+ ```
483
+
484
+ ### 4. Add `.mcp.json` to each project
485
+
486
+ Create `.mcp.json` in each project worktree root. This is **required** for MCP tools to be available in Claude sessions (including `claude --print`):
487
+
488
+ ```json
489
+ {
490
+ "mcpServers": {
491
+ "MemoryRelay": {
492
+ "command": "memoryrelay-mcp",
493
+ "args": ["--agent-id", "YOUR_AGENT_UUID"],
494
+ "env": {
495
+ "MEMORYRELAY_API_KEY": "mem_prod_your_key_here"
496
+ }
497
+ }
498
+ }
499
+ }
500
+ ```
501
+
502
+ ### 5. Install Alteriom Claude Skills (optional)
503
+
504
+ ```bash
505
+ git clone git@github.com:Alteriom/alteriom-claude-skills.git ~/.alteriom-claude-skills
506
+ ```
507
+
508
+ These provide curated skill files for common workflows across projects.
509
+
510
+ ## Known Issues
511
+
512
+ | Issue | Status | Workaround |
513
+ |-------|--------|------------|
514
+ | `openclaw status` shows `· unavailable` on OpenClaw 2026.3.28 | Cosmetic — plugin is functional | Fix planned in v0.17.0 (local cache with MemorySearchManager-compatible schema) |
515
+ | `plugins update --all` doesn't reliably update extensions | OpenClaw CLI bug | `rm -rf ~/.openclaw/extensions/plugin-memoryrelay-ai && openclaw plugins install @memoryrelay/plugin-memoryrelay-ai` |
516
+ | `agentId` must be a UUID from `GET /v1/agents` | By design | Do not use agent name strings — retrieve the UUID from the API |
517
+
518
+ ## Roadmap
519
+
520
+ **v0.17.0** — Local SQLite cache layer ([Epic #62](https://github.com/memoryrelay/openclaw-plugin/issues/62))
521
+
522
+ - Local SQLite cache for offline-first memory access
523
+ - SyncDaemon for background API synchronization
524
+ - Local vector search via `sqlite-vec`
525
+ - `MemorySearchManager`-compatible schema (fixes `openclaw status` display)
526
+ - Issues [#63](https://github.com/memoryrelay/openclaw-plugin/issues/63)–[#72](https://github.com/memoryrelay/openclaw-plugin/issues/72)
527
+
386
528
  ## Development
387
529
 
388
530
  ```bash
package/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * OpenClaw Memory Plugin - MemoryRelay
3
- * Version: 0.16.3
3
+ * Version: 0.17.1
4
4
  *
5
5
  * Long-term memory with vector search using MemoryRelay API.
6
6
  * Provides auto-recall and auto-capture via lifecycle hooks.
@@ -14,7 +14,8 @@
14
14
  * Docs: https://memoryrelay.ai
15
15
  */
16
16
 
17
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
17
+ import { mkdirSync } from "node:fs";
18
+ import { homedir } from "node:os";
18
19
  import { join } from "node:path";
19
20
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
20
21
 
@@ -31,6 +32,10 @@ import {
31
32
  VALID_HEALTH_STATUSES,
32
33
  } from "./src/client/memoryrelay-client.js";
33
34
  import { SessionResolver } from "./src/context/session-resolver.js";
35
+ import { LocalCache } from "./src/cache/local-cache.js";
36
+ import { SyncDaemon } from "./src/cache/sync-daemon.js";
37
+ import { PluginMemoryManager } from "./src/cache/memory-manager.js";
38
+ import type { LocalCacheConfig } from "./src/cache/types.js";
34
39
 
35
40
  // --- Hooks ---
36
41
  import { registerBeforeAgentStart } from "./src/hooks/before-agent-start.js";
@@ -98,6 +103,7 @@ interface MemoryRelayConfig {
98
103
  maxLogEntries?: number;
99
104
  sessionTimeoutMinutes?: number;
100
105
  sessionCleanupIntervalMinutes?: number;
106
+ localCache?: Partial<LocalCacheConfig>;
101
107
  }
102
108
 
103
109
  // ============================================================================
@@ -352,23 +358,64 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
352
358
  api.logger.error(`memory-memoryrelay: health check failed: ${String(err)}`);
353
359
  }
354
360
 
355
- // --- Create stub store file so OpenClaw's existsSync checks pass ---
356
- // OpenClaw 2026.3.28 scanner proceeds for all memory plugins but then checks
357
- // existsSync(store.path) for a local SQLite file. Create a minimal empty file
358
- // at the expected path so the scanner doesn't bail with "unavailable".
359
- try {
360
- const openclawHome = process.env.OPENCLAW_HOME || join(process.env.HOME || "/tmp", ".openclaw");
361
- const storeDir = join(openclawHome, "memory");
362
- // OpenClaw resolves store path as: ~/.openclaw/memory/{agentId}.sqlite
363
- const resolvedAgentId = agentId || "main";
364
- const storePath = join(storeDir, `${resolvedAgentId}.sqlite`);
365
- if (!existsSync(storePath)) {
361
+ // --- Local Cache + SyncDaemon (v0.17.0+) ---
362
+ // Replaces the stub file hack from v0.16.x. LocalCache creates a real SQLite
363
+ // database at the expected path, satisfying OpenClaw's existsSync scanner and
364
+ // enabling local-first recall/capture pipelines.
365
+ const DEFAULT_CACHE_CONFIG: LocalCacheConfig = {
366
+ enabled: true,
367
+ dbPath: "",
368
+ syncIntervalMinutes: 5,
369
+ maxLocalMemories: 1000,
370
+ vectorSearch: { enabled: false, provider: "none" },
371
+ ttl: { hot: 72, warm: 168, cold: 720 },
372
+ };
373
+
374
+ const localCacheConfig: LocalCacheConfig = {
375
+ ...DEFAULT_CACHE_CONFIG,
376
+ ...cfg?.localCache,
377
+ vectorSearch: { ...DEFAULT_CACHE_CONFIG.vectorSearch, ...cfg?.localCache?.vectorSearch },
378
+ ttl: { ...DEFAULT_CACHE_CONFIG.ttl, ...cfg?.localCache?.ttl },
379
+ };
380
+
381
+ let localCache: LocalCache | null = null;
382
+ let syncDaemon: SyncDaemon | null = null;
383
+ let memoryManager: PluginMemoryManager | null = null;
384
+
385
+ if (localCacheConfig.enabled) {
386
+ try {
387
+ const openclawHome = process.env.OPENCLAW_HOME || join(homedir(), ".openclaw");
388
+ const resolvedAgentId = agentId || "main";
389
+ const storeDir = join(openclawHome, "memory");
366
390
  mkdirSync(storeDir, { recursive: true });
367
- writeFileSync(storePath, Buffer.alloc(0));
368
- api.logger.info?.(`memory-memoryrelay: created stub store file at ${storePath}`);
391
+ const dbPath = join(storeDir, `${resolvedAgentId}.sqlite`);
392
+ localCacheConfig.dbPath = dbPath;
393
+
394
+ localCache = new LocalCache(dbPath, localCacheConfig);
395
+ syncDaemon = new SyncDaemon(localCache, client, localCacheConfig);
396
+ syncDaemon.start();
397
+
398
+ const vectorAvailable = localCacheConfig.vectorSearch.enabled;
399
+ memoryManager = new PluginMemoryManager(
400
+ localCache,
401
+ syncDaemon,
402
+ localCacheConfig,
403
+ vectorAvailable,
404
+ agentId || "main",
405
+ );
406
+
407
+ // Initial pull on startup (non-blocking)
408
+ syncDaemon.pull().catch((err) =>
409
+ api.logger.warn?.(`memory-memoryrelay: initial sync failed: ${String(err)}`),
410
+ );
411
+
412
+ api.logger.info?.(`memory-memoryrelay: local cache initialized at ${dbPath}`);
413
+ } catch (err) {
414
+ api.logger.warn?.(`memory-memoryrelay: local cache init failed, falling back to API-only: ${String(err)}`);
415
+ localCache = null;
416
+ syncDaemon = null;
417
+ memoryManager = null;
369
418
  }
370
- } catch (err) {
371
- api.logger.warn?.(`memory-memoryrelay: failed to create stub store file: ${String(err)}`);
372
419
  }
373
420
 
374
421
  // --- Tool enablement filter ---
@@ -398,8 +445,8 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
398
445
  // ========================================================================
399
446
 
400
447
  registerBeforeAgentStart(api, pluginConfig, isToolEnabled, defaultProject);
401
- registerBeforePromptBuild(api, pluginConfig, client, sessionResolver);
402
- registerAgentEnd(api, pluginConfig, client, sessionResolver);
448
+ registerBeforePromptBuild(api, pluginConfig, client, sessionResolver, localCache, syncDaemon);
449
+ registerAgentEnd(api, pluginConfig, client, sessionResolver, localCache, syncDaemon);
403
450
  registerSessionLifecycle(api, pluginConfig, client, agentId, defaultProject, sessionResolver);
404
451
  registerSubagentHooks(api, pluginConfig, client, agentId, autoCaptureConfig, isBlocklisted);
405
452
  registerCompactionHooks(api, client, agentId, blocklist, extractRescueContent);
@@ -425,7 +472,7 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
425
472
  // ========================================================================
426
473
 
427
474
  api.logger.info?.(
428
- `memory-memoryrelay: plugin v0.16.3 loaded (${Object.values(TOOL_GROUPS).flat().length} tools, autoRecall: ${pluginConfig.autoRecall}, autoCapture: ${autoCaptureConfig.enabled ? autoCaptureConfig.tier : "off"}, debug: ${debugEnabled})`,
475
+ `memory-memoryrelay: plugin v0.17.1 loaded (${Object.values(TOOL_GROUPS).flat().length} tools, autoRecall: ${pluginConfig.autoRecall}, autoCapture: ${autoCaptureConfig.enabled ? autoCaptureConfig.tier : "off"}, debug: ${debugEnabled})`,
429
476
  );
430
477
 
431
478
  // ========================================================================
@@ -467,6 +514,29 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
467
514
  // `openclaw status` shows memory count, vector info, and provider details
468
515
  // instead of "unavailable". OpenClaw 2026.3.28+ calls this for all memory plugins.
469
516
  api.registerGatewayMethod?.("memory.probe", async ({ respond }) => {
517
+ // Use local PluginMemoryManager when available (v0.17.0+)
518
+ if (memoryManager) {
519
+ try {
520
+ const stats = memoryManager.cacheStats();
521
+ const daemonInfo = memoryManager.getSyncDaemonInfo();
522
+ respond(true, {
523
+ available: true,
524
+ provider: "memoryrelay",
525
+ memoryCount: stats.totalMemories,
526
+ tierBreakdown: stats.tierBreakdown,
527
+ bufferDepth: stats.bufferDepth,
528
+ syncActive: daemonInfo.running,
529
+ lastSync: stats.lastSync,
530
+ vector: { enabled: localCacheConfig.vectorSearch.enabled, dims: 768 },
531
+ fts: { enabled: true },
532
+ consecutiveErrors: daemonInfo.errors,
533
+ });
534
+ return;
535
+ } catch (err) {
536
+ api.logger.warn?.(`memory-memoryrelay: memory.probe local cache failed, falling back to API: ${String(err)}`);
537
+ }
538
+ }
539
+
470
540
  try {
471
541
  const health = await client.health() as { status: string; embedding_info?: { dimension?: number } };
472
542
  const healthStatus = String(health.status).toLowerCase();
@@ -509,6 +579,16 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
509
579
  }
510
580
  });
511
581
 
582
+ // getMemorySearchManager — exposes the PluginMemoryManager so OpenClaw's
583
+ // status scanner can call status(), probeVectorAvailability(), and close().
584
+ api.registerGatewayMethod?.("getMemorySearchManager", async ({ respond }) => {
585
+ if (memoryManager) {
586
+ respond(true, { manager: memoryManager });
587
+ } else {
588
+ respond(false, { error: "Local cache not initialized" });
589
+ }
590
+ });
591
+
512
592
  api.registerGatewayMethod?.("memory.status", async ({ respond }) => {
513
593
  try {
514
594
  const startTime = Date.now();
@@ -833,7 +913,43 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
833
913
 
834
914
  if (statusReporter) {
835
915
  const report = statusReporter.buildReport(connectionStatus, reportConfig, { total_memories: memoryCount }, TOOL_GROUPS);
836
- return { text: StatusReporter.formatReport(report) };
916
+ let text = StatusReporter.formatReport(report);
917
+
918
+ // Append local cache section when available
919
+ if (memoryManager) {
920
+ try {
921
+ const cacheStats = memoryManager.cacheStats();
922
+ const daemonInfo = memoryManager.getSyncDaemonInfo();
923
+ const cacheLines: string[] = [];
924
+ cacheLines.push("LOCAL CACHE");
925
+ const { hot, warm, cold } = cacheStats.tierBreakdown;
926
+ cacheLines.push(` Total: ${cacheStats.totalMemories} memories (hot: ${hot}, warm: ${warm}, cold: ${cold})`);
927
+ cacheLines.push(` Buffer: ${cacheStats.bufferDepth} entries pending sync`);
928
+ if (cacheStats.lastSync) {
929
+ const ago = StatusReporter.formatTimeAgo(new Date(cacheStats.lastSync));
930
+ cacheLines.push(` Last sync: ${ago}`);
931
+ } else {
932
+ cacheLines.push(" Last sync: never");
933
+ }
934
+ const vecLabel = localCacheConfig.vectorSearch.enabled ? "ready (sqlite-vec, 768 dims)" : "disabled";
935
+ cacheLines.push(` Vector: ${vecLabel}`);
936
+ cacheLines.push(" FTS: ready");
937
+ cacheLines.push("");
938
+ const daemonStatus = daemonInfo.running ? "running" : "stopped";
939
+ cacheLines.push(`SYNC DAEMON: ${daemonStatus}`);
940
+ cacheLines.push(` Interval: ${daemonInfo.intervalMinutes} minutes`);
941
+ cacheLines.push(` Errors: ${daemonInfo.errors} consecutive`);
942
+ if (daemonInfo.lastError) {
943
+ cacheLines.push(` Last error: ${daemonInfo.lastError}`);
944
+ }
945
+ cacheLines.push("");
946
+ text += cacheLines.join("\n");
947
+ } catch {
948
+ // cache stats unavailable — skip section
949
+ }
950
+ }
951
+
952
+ return { text };
837
953
  }
838
954
  return { text: `MemoryRelay: ${isConnected ? "connected" : "disconnected"} | Endpoint: ${apiUrl} | Memories: ${memoryCount} | Agent: ${agentId}` };
839
955
  } catch (err) {
@@ -1336,6 +1452,20 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
1336
1452
  },
1337
1453
  });
1338
1454
 
1455
+ // ========================================================================
1456
+ // Local Cache Cleanup Service
1457
+ // ========================================================================
1458
+
1459
+ if (localCache || syncDaemon) {
1460
+ api.registerService({
1461
+ id: "memoryrelay-cache-cleanup",
1462
+ stop: async () => {
1463
+ syncDaemon?.stop();
1464
+ localCache?.close();
1465
+ },
1466
+ });
1467
+ }
1468
+
1339
1469
  // ========================================================================
1340
1470
  // Stale Session Cleanup Service
1341
1471
  // ========================================================================
@@ -2,8 +2,8 @@
2
2
  "id": "plugin-memoryrelay-ai",
3
3
  "kind": "memory",
4
4
  "name": "MemoryRelay AI",
5
- "description": "MemoryRelay v0.16.3 - Long-term memory with pipeline architecture, 42 tools, 17 commands, V2 async, sessions, decisions, patterns & projects (api.memoryrelay.net)",
6
- "version": "0.16.3",
5
+ "description": "MemoryRelay v0.17.1 - Long-term memory with pipeline architecture, 42 tools, 17 commands, V2 async, sessions, decisions, patterns & projects (api.memoryrelay.net)",
6
+ "version": "0.17.1",
7
7
  "uiHints": {
8
8
  "apiKey": {
9
9
  "label": "MemoryRelay API Key",
@@ -225,6 +225,47 @@
225
225
  }
226
226
  }
227
227
  },
228
+ "localCache": {
229
+ "type": "object",
230
+ "description": "Local SQLite cache for fast, offline-capable memory access",
231
+ "properties": {
232
+ "enabled": {
233
+ "type": "boolean",
234
+ "default": true,
235
+ "description": "Enable local SQLite cache layer"
236
+ },
237
+ "syncIntervalMinutes": {
238
+ "type": "number",
239
+ "default": 5,
240
+ "minimum": 1,
241
+ "maximum": 60,
242
+ "description": "How often to sync with the API (minutes)"
243
+ },
244
+ "maxLocalMemories": {
245
+ "type": "number",
246
+ "default": 1000,
247
+ "minimum": 100,
248
+ "maximum": 10000,
249
+ "description": "Maximum number of memories to keep locally"
250
+ },
251
+ "vectorSearch": {
252
+ "type": "object",
253
+ "properties": {
254
+ "enabled": { "type": "boolean", "default": true },
255
+ "provider": { "type": "string", "default": "sqlite-vec" }
256
+ }
257
+ },
258
+ "ttl": {
259
+ "type": "object",
260
+ "description": "Time-to-live per tier (hours)",
261
+ "properties": {
262
+ "hot": { "type": "number", "default": 72 },
263
+ "warm": { "type": "number", "default": 168 },
264
+ "cold": { "type": "number", "default": 720 }
265
+ }
266
+ }
267
+ }
268
+ },
228
269
  "ranking": {
229
270
  "type": "object",
230
271
  "properties": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoryrelay/plugin-memoryrelay-ai",
3
- "version": "0.16.3",
3
+ "version": "0.17.1",
4
4
  "description": "OpenClaw memory plugin for MemoryRelay API - 42 tools, 17 commands, V2 async, sessions, decisions, patterns, projects & semantic search",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -33,6 +33,7 @@
33
33
  "openclaw": ">=2026.2.0"
34
34
  },
35
35
  "devDependencies": {
36
+ "@types/better-sqlite3": "^7.6.13",
36
37
  "@types/node": "^25.3.5",
37
38
  "@vitest/coverage-v8": "^1.2.0",
38
39
  "typescript": "^5.9.3",
@@ -51,7 +52,16 @@
51
52
  "src/",
52
53
  "skills/"
53
54
  ],
55
+ "bundledDependencies": [
56
+ "better-sqlite3"
57
+ ],
54
58
  "engines": {
55
59
  "node": ">=20.0.0"
60
+ },
61
+ "dependencies": {
62
+ "better-sqlite3": "^12.8.0"
63
+ },
64
+ "optionalDependencies": {
65
+ "sqlite-vec": "^0.1.0"
56
66
  }
57
67
  }