@openclaw/memory-lancedb 2026.5.27 → 2026.5.28-beta.2

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/dist/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
+ import { parseFiniteNumber } from "openclaw/plugin-sdk/number-runtime";
4
5
  //#region extensions/memory-lancedb/config.ts
5
6
  const MEMORY_CATEGORIES = [
6
7
  "preference",
@@ -56,11 +57,27 @@ function resolveEnvVars(value) {
56
57
  return envValue;
57
58
  });
58
59
  }
59
- function resolveEmbeddingModel(embedding) {
60
+ function resolveEmbeddingModel(embedding, dimensions) {
60
61
  const model = typeof embedding.model === "string" ? embedding.model : DEFAULT_MODEL;
61
- if (typeof embedding.dimensions !== "number") vectorDimsForModel(model);
62
+ if (dimensions === void 0) vectorDimsForModel(model);
62
63
  return model;
63
64
  }
65
+ function resolveFiniteIntegerConfig(value) {
66
+ if (typeof value !== "number") return;
67
+ const parsed = parseFiniteNumber(value);
68
+ return parsed === void 0 ? void 0 : Math.floor(parsed);
69
+ }
70
+ function resolveBoundedIntegerConfig(params) {
71
+ const resolved = resolveFiniteIntegerConfig(params.value) ?? params.fallback;
72
+ if (resolved < params.min || resolved > params.max) throw new Error(`${params.label} must be between ${params.min} and ${params.max}`);
73
+ return resolved;
74
+ }
75
+ function resolveEmbeddingDimensions(embedding) {
76
+ if (embedding.dimensions === void 0) return;
77
+ const dimensions = typeof embedding.dimensions === "number" ? parseFiniteNumber(embedding.dimensions) : void 0;
78
+ if (dimensions === void 0 || !Number.isInteger(dimensions) || dimensions < 1) throw new Error("embedding.dimensions must be a positive integer");
79
+ return dimensions;
80
+ }
64
81
  const memoryConfigSchema = {
65
82
  parse(value) {
66
83
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("memory config required");
@@ -80,13 +97,24 @@ const memoryConfigSchema = {
80
97
  if (!embedding || typeof embedding !== "object" || Array.isArray(embedding)) throw new Error("embedding config required");
81
98
  assertAllowedKeys(embedding, [...EMBEDDING_CONFIG_KEYS], "embedding config");
82
99
  if (Object.keys(embedding).length === 0) throw new Error("embedding config must include at least one setting");
83
- const model = resolveEmbeddingModel(embedding);
100
+ const dimensions = resolveEmbeddingDimensions(embedding);
101
+ const model = resolveEmbeddingModel(embedding, dimensions);
84
102
  const provider = typeof embedding.provider === "string" ? embedding.provider.trim() : "openai";
85
103
  if (!provider) throw new Error("embedding.provider must not be empty");
86
- const captureMaxChars = typeof cfg.captureMaxChars === "number" ? Math.floor(cfg.captureMaxChars) : void 0;
87
- const recallMaxChars = typeof cfg.recallMaxChars === "number" ? Math.floor(cfg.recallMaxChars) : void 0;
88
- if (typeof captureMaxChars === "number" && (captureMaxChars < 100 || captureMaxChars > 1e4)) throw new Error("captureMaxChars must be between 100 and 10000");
89
- if (typeof recallMaxChars === "number" && (recallMaxChars < 100 || recallMaxChars > 1e4)) throw new Error("recallMaxChars must be between 100 and 10000");
104
+ const captureMaxChars = resolveBoundedIntegerConfig({
105
+ value: cfg.captureMaxChars,
106
+ fallback: 500,
107
+ min: 100,
108
+ max: 1e4,
109
+ label: "captureMaxChars"
110
+ });
111
+ const recallMaxChars = resolveBoundedIntegerConfig({
112
+ value: cfg.recallMaxChars,
113
+ fallback: DEFAULT_RECALL_MAX_CHARS,
114
+ min: 100,
115
+ max: 1e4,
116
+ label: "recallMaxChars"
117
+ });
90
118
  let customTriggers;
91
119
  if (cfg.customTriggers !== void 0) {
92
120
  if (!Array.isArray(cfg.customTriggers)) throw new Error("customTriggers must be an array of strings");
@@ -118,15 +146,15 @@ const memoryConfigSchema = {
118
146
  model,
119
147
  apiKey: typeof embedding.apiKey === "string" ? resolveEnvVars(embedding.apiKey) : void 0,
120
148
  baseUrl: typeof embedding.baseUrl === "string" ? resolveEnvVars(embedding.baseUrl) : void 0,
121
- dimensions: typeof embedding.dimensions === "number" ? embedding.dimensions : void 0
149
+ dimensions
122
150
  },
123
151
  dreaming,
124
152
  dbPath: typeof cfg.dbPath === "string" ? cfg.dbPath : DEFAULT_DB_PATH,
125
153
  autoCapture: cfg.autoCapture === true,
126
154
  autoRecall: cfg.autoRecall !== false,
127
- captureMaxChars: captureMaxChars ?? 500,
155
+ captureMaxChars,
128
156
  ...customTriggers ? { customTriggers } : {},
129
- recallMaxChars: recallMaxChars ?? 1e3,
157
+ recallMaxChars,
130
158
  ...storageOptions ? { storageOptions } : {}
131
159
  };
132
160
  },
package/dist/index.js CHANGED
@@ -3,6 +3,8 @@ import { DEFAULT_RECALL_MAX_CHARS, MEMORY_CATEGORIES, memoryConfigSchema, vector
3
3
  import { loadLanceDbModule } from "./lancedb-runtime.js";
4
4
  import { Buffer } from "node:buffer";
5
5
  import { randomUUID } from "node:crypto";
6
+ import { optionalFiniteNumberSchema, optionalPositiveIntegerSchema } from "openclaw/plugin-sdk/channel-actions";
7
+ import { readFiniteNumberParam, readPositiveIntegerParam } from "openclaw/plugin-sdk/param-readers";
6
8
  import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
7
9
  import { ensureGlobalUndiciEnvProxyDispatcher } from "openclaw/plugin-sdk/runtime-env";
8
10
  import { asOptionalRecord, normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -52,9 +54,12 @@ function extractLatestUserText(messages) {
52
54
  }
53
55
  function normalizeRecallQuery(text, maxChars = DEFAULT_RECALL_MAX_CHARS) {
54
56
  const normalized = text.replace(/\s+/g, " ").trim();
55
- const limit = Math.max(0, Math.floor(maxChars));
57
+ const limit = normalizeMaxChars(maxChars, DEFAULT_RECALL_MAX_CHARS);
56
58
  return normalized.length > limit ? truncateUtf16Safe(normalized, limit).trimEnd() : normalized;
57
59
  }
60
+ function normalizeMaxChars(value, fallback) {
61
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
62
+ }
58
63
  function messageFingerprint(message) {
59
64
  const msgObj = asOptionalRecord(message);
60
65
  if (!msgObj) return `${typeof message}:${String(message)}`;
@@ -334,7 +339,7 @@ function matchesCustomTrigger(text, customTriggers) {
334
339
  return customTriggers.some((trigger) => lower.includes(trigger.toLocaleLowerCase()));
335
340
  }
336
341
  function shouldCapture(text, options) {
337
- const maxChars = options?.maxChars ?? 500;
342
+ const maxChars = normalizeMaxChars(options?.maxChars, 500);
338
343
  if (text.length > maxChars) return false;
339
344
  if (text.includes("<relevant-memories>")) return false;
340
345
  if (text.startsWith("<") && text.includes("</")) return false;
@@ -417,10 +422,12 @@ var memory_lancedb_default = definePluginEntry({
417
422
  description: "Search through long-term memories. Use when you need context about user preferences, past decisions, or previously discussed topics.",
418
423
  parameters: Type.Object({
419
424
  query: Type.String({ description: "Search query" }),
420
- limit: Type.Optional(Type.Number({ description: "Max results (default: 5)" }))
425
+ limit: optionalPositiveIntegerSchema({ description: "Max results (default: 5)" })
421
426
  }),
422
427
  async execute(_toolCallId, params) {
423
- const { query, limit = 5 } = params;
428
+ const rawParams = params;
429
+ const query = rawParams.query;
430
+ const limit = readPositiveIntegerParam(rawParams, "limit") ?? 5;
424
431
  const currentCfg = resolveCurrentHookConfig();
425
432
  const vector = await embeddings.embed(normalizeRecallQuery(query, currentCfg.recallMaxChars));
426
433
  const results = await db.search(vector, limit, .1);
@@ -457,14 +464,22 @@ var memory_lancedb_default = definePluginEntry({
457
464
  description: "Save important information in long-term memory. Use for preferences, facts, decisions.",
458
465
  parameters: Type.Object({
459
466
  text: Type.String({ description: "Information to remember" }),
460
- importance: Type.Optional(Type.Number({ description: "Importance 0-1 (default: 0.7)" })),
467
+ importance: optionalFiniteNumberSchema({
468
+ description: "Importance 0-1 (default: 0.7)",
469
+ minimum: 0,
470
+ maximum: 1
471
+ }),
461
472
  category: Type.Optional(Type.Unsafe({
462
473
  type: "string",
463
474
  enum: [...MEMORY_CATEGORIES]
464
475
  }))
465
476
  }),
466
477
  async execute(_toolCallId, params) {
467
- const { text, importance = .7, category = "other" } = params;
478
+ const { text, category = "other" } = params;
479
+ const importance = readFiniteNumberParam(params, "importance", {
480
+ min: 0,
481
+ max: 1
482
+ }) ?? .7;
468
483
  if (looksLikePromptInjection(text)) return {
469
484
  content: [{
470
485
  type: "text",
@@ -589,7 +604,8 @@ var memory_lancedb_default = definePluginEntry({
589
604
  });
590
605
  memory.command("search").description("Search memories").argument("<query>", "Search query").option("--limit <n>", "Max results", "5").action(async (query, opts) => {
591
606
  const vector = await embeddings.embed(normalizeRecallQuery(query, cfg.recallMaxChars));
592
- const output = (await db.search(vector, Number.parseInt(opts.limit, 10), .3)).map((r) => ({
607
+ const limit = parsePositiveIntegerOption(opts.limit, "--limit");
608
+ const output = (await db.search(vector, limit, .3)).map((r) => ({
593
609
  id: r.entry.id,
594
610
  text: r.entry.text,
595
611
  category: r.entry.category,
@@ -626,8 +642,7 @@ var memory_lancedb_default = definePluginEntry({
626
642
  if (!/^[a-zA-Z0-9_\-\s='"><!.,()%*]+$/.test(filterCondition)) throw new Error("Filter condition contains invalid characters");
627
643
  query = query.where(filterCondition);
628
644
  }
629
- const limit = Number.parseInt(opts.limit, 10);
630
- if (Number.isNaN(limit) || limit <= 0) throw new Error("Invalid limit: must be a positive integer");
645
+ const limit = parsePositiveIntegerOption(opts.limit, "--limit") ?? 10;
631
646
  if (!opts.orderBy) query = query.limit(limit);
632
647
  let rows = await query.toArray();
633
648
  if (opts.orderBy) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/memory-lancedb",
3
- "version": "2026.5.27",
3
+ "version": "2026.5.28-beta.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/memory-lancedb",
9
- "version": "2026.5.27",
9
+ "version": "2026.5.28-beta.2",
10
10
  "dependencies": {
11
11
  "@lancedb/lancedb": "0.29.0",
12
12
  "apache-arrow": "18.1.0",
@@ -103,7 +103,8 @@
103
103
  "type": "string"
104
104
  },
105
105
  "dimensions": {
106
- "type": "number"
106
+ "type": "integer",
107
+ "minimum": 1
107
108
  }
108
109
  }
109
110
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/memory-lancedb",
3
- "version": "2026.5.27",
3
+ "version": "2026.5.28-beta.2",
4
4
  "description": "OpenClaw LanceDB-backed long-term memory plugin with auto-recall, auto-capture, and vector search.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,10 +26,10 @@
26
26
  "minHostVersion": ">=2026.4.10"
27
27
  },
28
28
  "compat": {
29
- "pluginApi": ">=2026.5.27"
29
+ "pluginApi": ">=2026.5.28-beta.2"
30
30
  },
31
31
  "build": {
32
- "openclawVersion": "2026.5.27"
32
+ "openclawVersion": "2026.5.28-beta.2"
33
33
  },
34
34
  "release": {
35
35
  "bundleRuntimeDependencies": false,
@@ -46,7 +46,7 @@
46
46
  "npm-shrinkwrap.json"
47
47
  ],
48
48
  "peerDependencies": {
49
- "openclaw": ">=2026.5.27"
49
+ "openclaw": ">=2026.5.28-beta.2"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "openclaw": {