memory-lancedb-pro 1.0.24 → 1.1.0-beta.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.
@@ -0,0 +1,227 @@
1
+ # memory-lancedb-pro v1.1.0 — 智能记忆增强
2
+
3
+ > **日期**: 2026-03-03
4
+ > **作者**: CJY
5
+ > **概述**: 基于对 AI Agent 记忆系统的深入理解,对记忆的写入质量、生命周期管理和去重能力进行了全面改进与完善
6
+
7
+ ---
8
+
9
+ ## 一、改进动机
10
+
11
+ 原有记忆系统在**检索侧**表现优异(Vector+BM25 混合检索、cross-encoder 重排序、多维评分),但在以下方面存在提升空间:
12
+
13
+ - **记忆写入质量**:依赖正则表达式触发捕获,容易漏捕有价值信息或误捕噪声
14
+ - **记忆结构层次**:扁平文本存储,缺乏分层索引能力
15
+ - **记忆生命周期**:简单时间衰减,无法模拟人类记忆的遗忘与强化规律
16
+ - **去重能力**:仅基于向量相似度的粗粒度去重,缺乏语义级判断
17
+
18
+ 本次改进针对这三个维度进行了系统性增强。
19
+
20
+ ---
21
+
22
+ ## 二、变更摘要
23
+
24
+ | 改进维度 | 核心变更 | 效果 |
25
+ | ------------ | ----------------------------------------- | ---------------------------------- |
26
+ | 智能提取 | LLM 驱动的 6 类别提取 + L0/L1/L2 分层存储 | 记忆写入更精准、结构更丰富 |
27
+ | 生命周期管理 | Weibull 衰减模型 + 三层晋升/降级 | 重要记忆持久保留,过时记忆自然淡化 |
28
+ | 智能去重 | 向量预过滤 + LLM 语义决策 | 避免冗余记忆,支持信息演化合并 |
29
+
30
+ ---
31
+
32
+ ## 三、新增文件
33
+
34
+ ### 1. `src/memory-categories.ts` — 6 类别分类系统
35
+
36
+ 设计了语义明确的记忆分类体系,将记忆分为两大类六小类:
37
+
38
+ - **用户记忆**:`profile`(身份属性)、`preferences`(偏好习惯)、`entities`(持续存在的实体)、`events`(发生的事件)
39
+ - **Agent 记忆**:`cases`(问题-解决方案对)、`patterns`(可复用的处理流程)
40
+
41
+ 每个类别有不同的合并策略:
42
+
43
+ - `profile` → 始终合并(用户身份信息持续累积)
44
+ - `preferences` / `entities` / `patterns` → 支持智能合并
45
+ - `events` / `cases` → 仅新增或跳过(独立记录,保留历史完整性)
46
+
47
+ ---
48
+
49
+ ### 2. `src/llm-client.ts` — LLM 客户端
50
+
51
+ 封装了 LLM 调用接口,专注于结构化 JSON 输出:
52
+
53
+ - 复用现有 OpenAI SDK 依赖,零新增包
54
+ - 内置 JSON 容错解析:支持 markdown 代码块包裹和平衡大括号提取
55
+ - 低温度 (0.1) 保证输出一致性
56
+ - 30 秒超时保护,失败时优雅降级
57
+
58
+ ---
59
+
60
+ ### 3. `src/extraction-prompts.ts` — 记忆提取提示模板
61
+
62
+ 精心设计了 3 个提示模板:
63
+
64
+ | 函数 | 用途 |
65
+ | ------------------------- | --------------------------------------------------- |
66
+ | `buildExtractionPrompt()` | 从对话中提取 6 类别 L0/L1/L2 记忆,含 few-shot 示例 |
67
+ | `buildDedupPrompt()` | CREATE / MERGE / SKIP 去重决策 |
68
+ | `buildMergePrompt()` | 将新旧记忆合并为三层结构 |
69
+
70
+ 提取提示包含完整的记忆价值判断标准、类别决策逻辑表、常见混淆澄清规则和 6 个 few-shot 示例。
71
+
72
+ ---
73
+
74
+ ### 4. `src/smart-extractor.ts` — 智能提取管线
75
+
76
+ 实现了完整的 LLM 驱动提取流水线:
77
+
78
+ ```
79
+ 对话文本 → LLM 提取 → 候选记忆 → 向量去重 → LLM 决策 → 持久化
80
+ ```
81
+
82
+ 核心设计:
83
+
84
+ - **两阶段去重**:先用向量相似度(阈值 0.7)快速筛选候选,再用 LLM 进行语义级判断
85
+ - **类别感知合并**:不同类别应用不同合并策略
86
+ - **L0/L1/L2 三层存储**:L0 一句话索引用于检索注入,L1 结构化摘要用于精读,L2 完整叙述用于深度回顾
87
+ - **向后兼容**:新增的 6 类别自动映射到已有的 5 类别存储,L0/L1/L2 存储在 metadata JSON 中
88
+ - **按类别设定重要度**:profile (0.9) > patterns (0.85) > cases/preferences (0.8) > entities (0.7) > events (0.6)
89
+
90
+ ---
91
+
92
+ ### 5. `src/decay-engine.ts` — Weibull 衰减引擎
93
+
94
+ 基于认知心理学中的记忆遗忘曲线研究,实现了复合衰减模型:
95
+
96
+ **复合分数 = 时效权重 × 时效 + 频率权重 × 频率 + 内在权重 × 内在价值**
97
+
98
+ 三个分量:
99
+
100
+ | 分量 | 机制 | 含义 |
101
+ | ------------------------ | --------------------------------- | ---------------------- |
102
+ | **时效 (recency)** | Weibull 拉伸指数衰减 `exp(-λt^β)` | 越久远的记忆衰减越快 |
103
+ | **频率 (frequency)** | 对数饱和曲线 + 时间加权 | 越常被访问的记忆越活跃 |
104
+ | **内在价值 (intrinsic)** | `importance × confidence` | 高价值记忆天然抵抗遗忘 |
105
+
106
+ 层级特定的衰减形状 (β 参数):
107
+
108
+ - **Core** (β=0.8):亚指数衰减 → 遗忘极慢,衰减地板 0.9
109
+ - **Working** (β=1.0):标准指数衰减,衰减地板 0.7
110
+ - **Peripheral** (β=1.3):超指数衰减 → 遗忘加速,衰减地板 0.5
111
+
112
+ 关键特性:
113
+
114
+ - **重要性调制半衰期**:`effectiveHL = halfLife × exp(μ × importance)`,重要记忆持续更久
115
+ - **搜索结果加权**:检索时自动应用衰减加权,让活跃记忆排名更高
116
+ - **过期识别**:识别 composite < 0.3 的过期记忆
117
+
118
+ ---
119
+
120
+ ### 6. `src/tier-manager.ts` — 三层晋升/降级管理器
121
+
122
+ 模拟人类记忆的多级存储模型:
123
+
124
+ ```
125
+ Peripheral(外围) ⟷ Working(工作) ⟷ Core(核心)
126
+ ```
127
+
128
+ **晋升条件**:
129
+
130
+ | 方向 | 条件 |
131
+ | -------------------- | ----------------------------------------------- |
132
+ | Peripheral → Working | 访问次数 ≥ 3 且 衰减分数 ≥ 0.4 |
133
+ | Working → Core | 访问次数 ≥ 10 且 衰减分数 ≥ 0.7 且 重要度 ≥ 0.8 |
134
+
135
+ **降级条件**:
136
+
137
+ | 方向 | 条件 |
138
+ | -------------------- | ------------------------------------------------ |
139
+ | Working → Peripheral | 衰减分数 < 0.15 或(年龄 > 60 天且访问次数 < 3) |
140
+ | Core → Working | 衰减分数 < 0.15 且 访问次数 < 3(极少触发) |
141
+
142
+ ---
143
+
144
+ ## 四、修改文件
145
+
146
+ ### `index.ts` — 插件入口
147
+
148
+ #### 新增配置项
149
+
150
+ ```typescript
151
+ smartExtraction?: boolean; // 是否启用 LLM 智能提取(默认 true)
152
+ llm?: {
153
+ apiKey?: string; // LLM API Key(默认复用 embedding.apiKey)
154
+ model?: string; // LLM 模型(默认 gpt-4o-mini)
155
+ baseURL?: string; // LLM API 端点
156
+ };
157
+ extractMinMessages?: number; // 最少消息数才触发提取(默认 4)
158
+ extractMaxChars?: number; // 送入 LLM 的最大字符数(默认 8000)
159
+ ```
160
+
161
+ #### `agent_end` 钩子改进
162
+
163
+ - 当 `smartExtraction` 启用时,优先使用 SmartExtractor 进行 LLM 6 类别提取
164
+ - 当消息数不足或 SmartExtractor 未初始化时,降级回原有正则触发逻辑
165
+ - 提取完成后输出统计日志:`smart-extracted N created, M merged, K skipped`
166
+
167
+ #### `before_agent_start` 钩子改进
168
+
169
+ - 注入的记忆上下文现在显示 L0 摘要而非原始文本
170
+ - 新增 6 类别标签(如 `[preferences:global]`)
171
+ - 新增层级标记(`[C]`ore / `[W]`orking / `[P]`eripheral)
172
+
173
+ ---
174
+
175
+ ## 五、配置指南
176
+
177
+ ### 最简配置(复用已有 API Key)
178
+
179
+ ```json
180
+ {
181
+ "embedding": {
182
+ "apiKey": "${OPENAI_API_KEY}",
183
+ "model": "text-embedding-3-small"
184
+ },
185
+ "smartExtraction": true
186
+ }
187
+ ```
188
+
189
+ ### 完整配置
190
+
191
+ ```json
192
+ {
193
+ "embedding": {
194
+ "apiKey": "${OPENAI_API_KEY}",
195
+ "model": "text-embedding-3-small"
196
+ },
197
+ "smartExtraction": true,
198
+ "llm": {
199
+ "apiKey": "${OPENAI_API_KEY}",
200
+ "model": "gpt-4o-mini",
201
+ "baseURL": "https://api.openai.com/v1"
202
+ },
203
+ "extractMinMessages": 4,
204
+ "extractMaxChars": 8000
205
+ }
206
+ ```
207
+
208
+ ### 禁用智能提取
209
+
210
+ ```json
211
+ {
212
+ "smartExtraction": false
213
+ }
214
+ ```
215
+
216
+ ---
217
+
218
+ ## 六、向后兼容性
219
+
220
+ | 方面 | 兼容方式 |
221
+ | -------------- | ---------------------------------------------- |
222
+ | LanceDB Schema | 新字段存储在 `metadata` JSON 中,不修改表结构 |
223
+ | 记忆类别 | 新 6 类别自动映射到原有 5 类别 |
224
+ | 混合检索 | Vector+BM25 检索管线完全保留 |
225
+ | 去重逻辑 | 仅在 `smartExtraction: true` 时生效 |
226
+ | 已有数据 | 旧记忆正常读取,新记忆额外携带 L0/L1/L2 元数据 |
227
+ | 配置 | 全部新增配置项均有默认值,零配置即可使用 |
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0-beta.1 (Smart Memory Beta)
4
+
5
+ This is a **beta** release published under the npm dist-tag **`beta`** (it will not affect the stable `latest` channel).
6
+
7
+ Highlights:
8
+ - **Smart Extraction (LLM-powered)**: 6-category extraction with L0/L1/L2 metadata (falls back to regex capture when disabled or init fails)
9
+ - **Lifecycle scoring integrated into retrieval**: decay-based score adjustment + tier floors
10
+ - **Tier transitions (best-effort)**: records access stats for top results and can promote/demote tiers via metadata
11
+ - Rebases the smart-memory branch onto `main@1.0.25` (keeps multi-key rotation & other recent fixes)
12
+
13
+ Notes:
14
+ - Retrieval now performs small, bounded metadata write-backs for top results (access_count / last_accessed_at / tier).
15
+
16
+ ---
17
+
3
18
 
4
19
  ## 1.0.22
5
20
 
package/index.ts CHANGED
@@ -19,6 +19,12 @@ import { registerAllMemoryTools } from "./src/tools.js";
19
19
  import { shouldSkipRetrieval } from "./src/adaptive-retrieval.js";
20
20
  import { createMemoryCLI } from "./cli.js";
21
21
 
22
+ // Import smart extraction & lifecycle components
23
+ import { SmartExtractor } from "./src/smart-extractor.js";
24
+ import { createLlmClient } from "./src/llm-client.js";
25
+ import { createDecayEngine, DEFAULT_DECAY_CONFIG } from "./src/decay-engine.js";
26
+ import { createTierManager, DEFAULT_TIER_CONFIG } from "./src/tier-manager.js";
27
+
22
28
  // ============================================================================
23
29
  // Configuration & Types
24
30
  // ============================================================================
@@ -26,7 +32,7 @@ import { createMemoryCLI } from "./cli.js";
26
32
  interface PluginConfig {
27
33
  embedding: {
28
34
  provider: "openai-compatible";
29
- apiKey: string;
35
+ apiKey: string | string[];
30
36
  model?: string;
31
37
  baseURL?: string;
32
38
  dimensions?: number;
@@ -57,6 +63,15 @@ interface PluginConfig {
57
63
  hardMinScore?: number;
58
64
  timeDecayHalfLifeDays?: number;
59
65
  };
66
+ // Smart extraction config (Phase 1: from epro-memory)
67
+ smartExtraction?: boolean;
68
+ llm?: {
69
+ apiKey?: string;
70
+ model?: string;
71
+ baseURL?: string;
72
+ };
73
+ extractMinMessages?: number;
74
+ extractMaxChars?: number;
60
75
  scopes?: {
61
76
  default?: string;
62
77
  definitions?: Record<string, { description: string }>;
@@ -344,17 +359,62 @@ const memoryLanceDBProPlugin = {
344
359
  taskPassage: config.embedding.taskPassage,
345
360
  normalized: config.embedding.normalized,
346
361
  });
347
- const retriever = createRetriever(store, embedder, {
348
- ...DEFAULT_RETRIEVAL_CONFIG,
349
- ...config.retrieval,
350
- });
362
+ // Initialize decay engine + tier manager (lifecycle scoring)
363
+ const decayEngine = createDecayEngine(DEFAULT_DECAY_CONFIG);
364
+ const tierManager = createTierManager(DEFAULT_TIER_CONFIG);
365
+
366
+ const retriever = createRetriever(
367
+ store,
368
+ embedder,
369
+ {
370
+ ...DEFAULT_RETRIEVAL_CONFIG,
371
+ ...config.retrieval,
372
+ },
373
+ { decayEngine, tierManager },
374
+ );
351
375
  const scopeManager = createScopeManager(config.scopes);
352
376
  const migrator = createMigrator(store);
353
377
 
378
+ // Initialize smart extraction (Phase 1: from epro-memory)
379
+ let smartExtractor: SmartExtractor | null = null;
380
+ if (config.smartExtraction !== false) {
381
+ try {
382
+ const embeddingKey = Array.isArray(config.embedding.apiKey)
383
+ ? config.embedding.apiKey[0]
384
+ : config.embedding.apiKey;
385
+ const llmApiKey = config.llm?.apiKey
386
+ ? resolveEnvVars(config.llm.apiKey)
387
+ : resolveEnvVars(embeddingKey);
388
+ const llmBaseURL = config.llm?.baseURL
389
+ ? resolveEnvVars(config.llm.baseURL)
390
+ : config.embedding.baseURL;
391
+ const llmModel = config.llm?.model || "gpt-4o-mini";
392
+
393
+ const llmClient = createLlmClient({
394
+ apiKey: llmApiKey,
395
+ model: llmModel,
396
+ baseURL: llmBaseURL,
397
+ timeoutMs: 30000,
398
+ });
399
+
400
+ smartExtractor = new SmartExtractor(store, embedder, llmClient, {
401
+ user: "User",
402
+ extractMinMessages: config.extractMinMessages ?? 4,
403
+ extractMaxChars: config.extractMaxChars ?? 8000,
404
+ defaultScope: config.scopes?.default ?? "global",
405
+ log: (msg: string) => api.logger.info(msg),
406
+ });
407
+
408
+ api.logger.info("memory-lancedb-pro: smart extraction enabled (LLM model: " + llmModel + ")");
409
+ } catch (err) {
410
+ api.logger.warn(`memory-lancedb-pro: smart extraction init failed, falling back to regex: ${String(err)}`);
411
+ }
412
+ }
413
+
354
414
  const pluginVersion = getPluginVersion();
355
415
 
356
416
  api.logger.info(
357
- `memory-lancedb-pro@${pluginVersion}: plugin registered (db: ${resolvedDbPath}, model: ${config.embedding.model || "text-embedding-3-small"})`
417
+ `memory-lancedb-pro@${pluginVersion}: plugin registered (db: ${resolvedDbPath}, model: ${config.embedding.model || "text-embedding-3-small"}, smartExtraction: ${smartExtractor ? 'ON' : 'OFF'})`
358
418
  );
359
419
 
360
420
  // ========================================================================
@@ -417,8 +477,17 @@ const memoryLanceDBProPlugin = {
417
477
  return;
418
478
  }
419
479
 
480
+ // Format with L0 abstracts grouped by category when available
420
481
  const memoryContext = results
421
- .map((r) => `- [${r.entry.category}:${r.entry.scope}] ${sanitizeForContext(r.entry.text)} (${(r.score * 100).toFixed(0)}%${r.sources?.bm25 ? ', vector+BM25' : ''}${r.sources?.reranked ? '+reranked' : ''})`)
482
+ .map((r) => {
483
+ let metaObj: Record<string, unknown> = {};
484
+ try { metaObj = JSON.parse(r.entry.metadata || "{}"); } catch {}
485
+ const displayCategory = (metaObj.memory_category as string) || r.entry.category;
486
+ const displayTier = (metaObj.tier as string) || "";
487
+ const tierPrefix = displayTier ? `[${displayTier.charAt(0).toUpperCase()}]` : "";
488
+ const abstract = (metaObj.l0_abstract as string) || r.entry.text;
489
+ return `- ${tierPrefix}[${displayCategory}:${r.entry.scope}] ${sanitizeForContext(abstract)} (${(r.score * 100).toFixed(0)}%${r.sources?.bm25 ? ', vector+BM25' : ''}${r.sources?.reranked ? '+reranked' : ''})`;
490
+ })
422
491
  .join("\n");
423
492
 
424
493
  api.logger.info?.(
@@ -488,7 +557,29 @@ const memoryLanceDBProPlugin = {
488
557
  }
489
558
  }
490
559
 
491
- // Filter for capturable content
560
+ // ----------------------------------------------------------------
561
+ // Smart Extraction (Phase 1: LLM-powered 6-category extraction)
562
+ // ----------------------------------------------------------------
563
+ if (smartExtractor) {
564
+ const minMessages = config.extractMinMessages ?? 4;
565
+ if (texts.length >= minMessages) {
566
+ const conversationText = texts.join("\n");
567
+ const sessionKey = (event as any).sessionKey || "unknown";
568
+ const stats = await smartExtractor.extractAndPersist(
569
+ conversationText, sessionKey,
570
+ );
571
+ if (stats.created > 0 || stats.merged > 0) {
572
+ api.logger.info(
573
+ `memory-lancedb-pro: smart-extracted ${stats.created} created, ${stats.merged} merged, ${stats.skipped} skipped for agent ${agentId}`
574
+ );
575
+ }
576
+ return; // Smart extraction handled everything
577
+ }
578
+ }
579
+
580
+ // ----------------------------------------------------------------
581
+ // Fallback: regex-triggered capture (original logic)
582
+ // ----------------------------------------------------------------
492
583
  const toCapture = texts.filter((text) => text && shouldCapture(text));
493
584
  if (toCapture.length === 0) {
494
585
  return;
@@ -743,11 +834,22 @@ function parsePluginConfig(value: unknown): PluginConfig {
743
834
  }
744
835
 
745
836
  // Accept single key (string) or array of keys for round-robin rotation
746
- const apiKey: string | string[] = typeof embedding.apiKey === "string"
747
- ? embedding.apiKey
748
- : Array.isArray(embedding.apiKey) && embedding.apiKey.length > 0 && embedding.apiKey.every((k: unknown) => typeof k === "string")
749
- ? (embedding.apiKey as string[])
750
- : process.env.OPENAI_API_KEY || "";
837
+ let apiKey: string | string[];
838
+ if (typeof embedding.apiKey === "string") {
839
+ apiKey = embedding.apiKey;
840
+ } else if (Array.isArray(embedding.apiKey) && embedding.apiKey.length > 0) {
841
+ // Validate every element is a non-empty string
842
+ const invalid = embedding.apiKey.findIndex((k: unknown) => typeof k !== "string" || (k as string).trim().length === 0);
843
+ if (invalid !== -1) {
844
+ throw new Error(`embedding.apiKey[${invalid}] is invalid: expected non-empty string`);
845
+ }
846
+ apiKey = embedding.apiKey as string[];
847
+ } else if (embedding.apiKey !== undefined) {
848
+ // apiKey is present but wrong type — throw, don't silently fall back
849
+ throw new Error("embedding.apiKey must be a string or non-empty array of strings");
850
+ } else {
851
+ apiKey = process.env.OPENAI_API_KEY || "";
852
+ }
751
853
 
752
854
  if (!apiKey || (Array.isArray(apiKey) && apiKey.length === 0)) {
753
855
  throw new Error("embedding.apiKey is required (set directly or via OPENAI_API_KEY env var)");
@@ -773,6 +875,11 @@ function parsePluginConfig(value: unknown): PluginConfig {
773
875
  autoRecallMinLength: parsePositiveInt(cfg.autoRecallMinLength),
774
876
  captureAssistant: cfg.captureAssistant === true,
775
877
  retrieval: typeof cfg.retrieval === "object" && cfg.retrieval !== null ? cfg.retrieval as any : undefined,
878
+ // Smart extraction config (Phase 1)
879
+ smartExtraction: cfg.smartExtraction !== false, // Default ON
880
+ llm: typeof cfg.llm === "object" && cfg.llm !== null ? cfg.llm as any : undefined,
881
+ extractMinMessages: parsePositiveInt(cfg.extractMinMessages) ?? 4,
882
+ extractMaxChars: parsePositiveInt(cfg.extractMaxChars) ?? 8000,
776
883
  scopes: typeof cfg.scopes === "object" && cfg.scopes !== null ? cfg.scopes as any : undefined,
777
884
  enableManagementTools: cfg.enableManagementTools === true,
778
885
  sessionMemory: typeof cfg.sessionMemory === "object" && cfg.sessionMemory !== null
@@ -2,7 +2,7 @@
2
2
  "id": "memory-lancedb-pro",
3
3
  "name": "Memory (LanceDB Pro)",
4
4
  "description": "Enhanced LanceDB-backed long-term memory with hybrid retrieval, multi-scope isolation, long-context chunking, and management CLI",
5
- "version": "1.0.23",
5
+ "version": "1.1.0-beta.1",
6
6
  "kind": "memory",
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -18,8 +18,18 @@
18
18
  },
19
19
  "apiKey": {
20
20
  "oneOf": [
21
- { "type": "string" },
22
- { "type": "array", "items": { "type": "string" }, "minItems": 1 }
21
+ {
22
+ "type": "string",
23
+ "minLength": 1
24
+ },
25
+ {
26
+ "type": "array",
27
+ "items": {
28
+ "type": "string",
29
+ "minLength": 1
30
+ },
31
+ "minItems": 1
32
+ }
23
33
  ],
24
34
  "description": "Single API key or array of keys for round-robin rotation"
25
35
  },
@@ -239,6 +249,44 @@
239
249
  }
240
250
  }
241
251
  }
252
+ },
253
+ "smartExtraction": {
254
+ "type": "boolean",
255
+ "default": true,
256
+ "description": "Enable LLM-powered smart memory extraction (6-category system). Falls back to regex capture when disabled or init fails."
257
+ },
258
+ "llm": {
259
+ "type": "object",
260
+ "additionalProperties": false,
261
+ "properties": {
262
+ "apiKey": {
263
+ "type": "string",
264
+ "description": "API key for LLM extraction (defaults to embedding apiKey)"
265
+ },
266
+ "model": {
267
+ "type": "string",
268
+ "default": "gpt-4o-mini",
269
+ "description": "LLM model for memory extraction and dedup"
270
+ },
271
+ "baseURL": {
272
+ "type": "string",
273
+ "description": "Base URL for LLM API (defaults to embedding baseURL)"
274
+ }
275
+ }
276
+ },
277
+ "extractMinMessages": {
278
+ "type": "integer",
279
+ "minimum": 1,
280
+ "maximum": 50,
281
+ "default": 4,
282
+ "description": "Minimum conversation messages before smart extraction triggers"
283
+ },
284
+ "extractMaxChars": {
285
+ "type": "integer",
286
+ "minimum": 500,
287
+ "maximum": 100000,
288
+ "default": 8000,
289
+ "description": "Maximum characters of conversation text to process for extraction"
242
290
  }
243
291
  },
244
292
  "required": [
@@ -297,6 +345,36 @@
297
345
  "help": "Directory path for the LanceDB database files",
298
346
  "advanced": true
299
347
  },
348
+ "smartExtraction": {
349
+ "label": "Smart Extraction",
350
+ "help": "Enable LLM-powered 6-category memory extraction. Falls back to regex capture when off."
351
+ },
352
+ "llm.apiKey": {
353
+ "label": "LLM API Key",
354
+ "sensitive": true,
355
+ "help": "API key for smart extraction LLM (defaults to embedding apiKey)",
356
+ "advanced": true
357
+ },
358
+ "llm.model": {
359
+ "label": "LLM Model",
360
+ "help": "Model for memory extraction and dedup (default: gpt-4o-mini)",
361
+ "advanced": true
362
+ },
363
+ "llm.baseURL": {
364
+ "label": "LLM Base URL",
365
+ "help": "Base URL for LLM API (defaults to embedding baseURL)",
366
+ "advanced": true
367
+ },
368
+ "extractMinMessages": {
369
+ "label": "Min Messages for Extraction",
370
+ "help": "Minimum conversation messages before smart extraction triggers",
371
+ "advanced": true
372
+ },
373
+ "extractMaxChars": {
374
+ "label": "Max Chars for Extraction",
375
+ "help": "Maximum conversation characters to process for extraction",
376
+ "advanced": true
377
+ },
300
378
  "autoCapture": {
301
379
  "label": "Auto-Capture",
302
380
  "help": "Automatically capture important information from conversations"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-lancedb-pro",
3
- "version": "1.0.24",
3
+ "version": "1.1.0-beta.1",
4
4
  "description": "OpenClaw enhanced LanceDB memory plugin with hybrid retrieval (Vector + BM25), cross-encoder rerank, multi-scope isolation, long-context chunking, and management CLI",
5
5
  "type": "module",
6
6
  "main": "index.ts",