diff --git a/extensions/memory-lancedb/config.ts b/extensions/memory-lancedb/config.ts index 4caa48cdce..339e5c8cd7 100644 --- a/extensions/memory-lancedb/config.ts +++ b/extensions/memory-lancedb/config.ts @@ -18,7 +18,7 @@ export const MEMORY_CATEGORIES = ["preference", "fact", "decision", "entity", "o export type MemoryCategory = (typeof MEMORY_CATEGORIES)[number]; const DEFAULT_MODEL = "text-embedding-3-small"; -const DEFAULT_CAPTURE_MAX_CHARS = 1500; +export const DEFAULT_CAPTURE_MAX_CHARS = 500; const LEGACY_STATE_DIRS: string[] = []; function resolveDefaultDbPath(): string { diff --git a/extensions/memory-lancedb/index.test.ts b/extensions/memory-lancedb/index.test.ts index b5261f848a..c2cb431e78 100644 --- a/extensions/memory-lancedb/index.test.ts +++ b/extensions/memory-lancedb/index.test.ts @@ -61,7 +61,7 @@ describe("memory plugin e2e", () => { expect(config).toBeDefined(); expect(config?.embedding?.apiKey).toBe(OPENAI_API_KEY); expect(config?.dbPath).toBe(dbPath); - expect(config?.captureMaxChars).toBe(1500); + expect(config?.captureMaxChars).toBe(500); }); test("config schema resolves env vars", async () => { @@ -105,6 +105,21 @@ describe("memory plugin e2e", () => { }).toThrow("captureMaxChars must be between 100 and 10000"); }); + test("config schema accepts captureMaxChars override", async () => { + const { default: memoryPlugin } = await import("./index.js"); + + const config = memoryPlugin.configSchema?.parse?.({ + embedding: { + apiKey: OPENAI_API_KEY, + model: "text-embedding-3-small", + }, + dbPath, + captureMaxChars: 1800, + }); + + expect(config?.captureMaxChars).toBe(1800); + }); + test("shouldCapture applies real capture rules", async () => { const { shouldCapture } = await import("./index.js"); @@ -117,10 +132,14 @@ describe("memory plugin e2e", () => { expect(shouldCapture("injected")).toBe(false); expect(shouldCapture("status")).toBe(false); expect(shouldCapture("Here is a short **summary**\n- bullet")).toBe(false); - const longButAllowed = `I always prefer this style. ${"x".repeat(1200)}`; - const tooLong = `I always prefer this style. ${"x".repeat(1600)}`; - expect(shouldCapture(longButAllowed, { maxChars: 1500 })).toBe(true); - expect(shouldCapture(tooLong, { maxChars: 1500 })).toBe(false); + const defaultAllowed = `I always prefer this style. ${"x".repeat(400)}`; + const defaultTooLong = `I always prefer this style. ${"x".repeat(600)}`; + expect(shouldCapture(defaultAllowed)).toBe(true); + expect(shouldCapture(defaultTooLong)).toBe(false); + const customAllowed = `I always prefer this style. ${"x".repeat(1200)}`; + const customTooLong = `I always prefer this style. ${"x".repeat(1600)}`; + expect(shouldCapture(customAllowed, { maxChars: 1500 })).toBe(true); + expect(shouldCapture(customTooLong, { maxChars: 1500 })).toBe(false); }); test("detectCategory classifies using production logic", async () => { diff --git a/extensions/memory-lancedb/index.ts b/extensions/memory-lancedb/index.ts index aa53d834dd..0778006c7b 100644 --- a/extensions/memory-lancedb/index.ts +++ b/extensions/memory-lancedb/index.ts @@ -12,6 +12,7 @@ import { Type } from "@sinclair/typebox"; import { randomUUID } from "node:crypto"; import OpenAI from "openai"; import { + DEFAULT_CAPTURE_MAX_CHARS, MEMORY_CATEGORIES, type MemoryCategory, memoryConfigSchema, @@ -195,7 +196,7 @@ const MEMORY_TRIGGERS = [ ]; export function shouldCapture(text: string, options?: { maxChars?: number }): boolean { - const maxChars = options?.maxChars ?? 1500; + const maxChars = options?.maxChars ?? DEFAULT_CAPTURE_MAX_CHARS; if (text.length < 10 || text.length > maxChars) { return false; } diff --git a/extensions/memory-lancedb/openclaw.plugin.json b/extensions/memory-lancedb/openclaw.plugin.json index 007ea3d63d..44ee0dcd04 100644 --- a/extensions/memory-lancedb/openclaw.plugin.json +++ b/extensions/memory-lancedb/openclaw.plugin.json @@ -30,7 +30,7 @@ "label": "Capture Max Chars", "help": "Maximum message length eligible for auto-capture", "advanced": true, - "placeholder": "1500" + "placeholder": "500" } }, "configSchema": {