ai-memory-claw 1.0.0

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,304 @@
1
+ /**
2
+ * 记忆系统核心模块
3
+ *
4
+ * 提供记忆的存储、搜索、管理功能
5
+ */
6
+
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { v4 as uuidv4 } from 'uuid';
10
+ import { type Memory, type MemoryInput, type MemoryStats, type SearchOptions, type SearchResult, generateMemoryId } from './types';
11
+ import { type MemoryConfig } from './config';
12
+ import { EmbeddingGenerator } from './embedding';
13
+
14
+ export class MemorySystem {
15
+ private config: MemoryConfig;
16
+ private dataDir: string;
17
+ private memories: Map<string, Memory> = new Map();
18
+ private categoryIndex: Map<string, Set<string>> = new Map();
19
+ private embeddingGenerator: EmbeddingGenerator;
20
+ private initialized: boolean = false;
21
+
22
+ constructor(dataDir: string, config: MemoryConfig) {
23
+ this.dataDir = dataDir;
24
+ this.config = config;
25
+ this.embeddingGenerator = new EmbeddingGenerator();
26
+ }
27
+
28
+ /**
29
+ * 初始化记忆系统
30
+ */
31
+ async initialize(): Promise<void> {
32
+ // 确保目录存在
33
+ if (!fs.existsSync(this.dataDir)) {
34
+ fs.mkdirSync(this.dataDir, { recursive: true });
35
+ }
36
+
37
+ // 初始化向量生成器
38
+ await this.embeddingGenerator.initialize();
39
+
40
+ // 加载已有记忆
41
+ await this.loadMemories();
42
+
43
+ this.initialized = true;
44
+ }
45
+
46
+ isInitialized(): boolean {
47
+ return this.initialized;
48
+ }
49
+
50
+ /**
51
+ * 搜索记忆
52
+ */
53
+ async search(query: string, options: SearchOptions): Promise<Memory[]> {
54
+ // 1. 生成查询向量
55
+ const queryVector = await this.embeddingGenerator.embed(query);
56
+
57
+ // 2. 计算相似度
58
+ const results: SearchResult[] = [];
59
+
60
+ for (const memory of this.memories.values()) {
61
+ if (memory.embedding.length === 0) continue;
62
+
63
+ const score = this.embeddingGenerator.cosineSimilarity(
64
+ queryVector,
65
+ memory.embedding
66
+ );
67
+
68
+ if (score >= options.threshold) {
69
+ results.push({ memory, score });
70
+ }
71
+ }
72
+
73
+ // 3. 排序
74
+ results.sort((a, b) => b.score - a.score);
75
+
76
+ // 4. 强化前N个记忆
77
+ for (const result of results.slice(0, options.limit)) {
78
+ await this.enhance(result.memory.id);
79
+ }
80
+
81
+ // 5. 返回结果
82
+ return results.slice(0, options.limit).map(r => r.memory);
83
+ }
84
+
85
+ /**
86
+ * 存储记忆
87
+ */
88
+ async store(input: MemoryInput): Promise<Memory> {
89
+ const id = generateMemoryId(input.category, input.subCategory);
90
+
91
+ // 生成向量
92
+ const text = `${input.content.task} ${input.content.process}`;
93
+ const embedding = await this.embeddingGenerator.embed(text);
94
+
95
+ const memory: Memory = {
96
+ id,
97
+ taskDescription: input.content.task,
98
+ category: input.category,
99
+ subCategory: input.subCategory,
100
+ cluster: `${input.subCategory}-cluster`,
101
+ content: input.content,
102
+ embedding,
103
+ createdAt: new Date(),
104
+ updatedAt: new Date(),
105
+ lastAccessedAt: new Date(),
106
+ version: 1,
107
+ diffs: [],
108
+ mergedFrom: [],
109
+ confidence: 0.8,
110
+ usageCount: 0,
111
+ importance: input.importance,
112
+ tags: input.tags || [],
113
+ encrypted: false,
114
+ autoCleanup: false
115
+ };
116
+
117
+ // 保存到内存
118
+ this.memories.set(id, memory);
119
+ this.addToCategoryIndex(memory);
120
+
121
+ // 保存到文件
122
+ await this.saveMemoryToFile(memory);
123
+
124
+ return memory;
125
+ }
126
+
127
+ /**
128
+ * 强化记忆
129
+ */
130
+ async enhance(memoryId: string): Promise<void> {
131
+ const memory = this.memories.get(memoryId);
132
+ if (!memory) return;
133
+
134
+ memory.usageCount++;
135
+ memory.lastAccessedAt = new Date();
136
+ memory.updatedAt = new Date();
137
+
138
+ // 提升重要性
139
+ if (memory.importance !== 'critical') {
140
+ const levels: ('low' | 'medium' | 'high' | 'critical')[] =
141
+ ['low', 'medium', 'high', 'critical'];
142
+ const idx = levels.indexOf(memory.importance);
143
+ if (idx < levels.length - 1 && memory.usageCount > 3) {
144
+ memory.importance = levels[idx + 1];
145
+ }
146
+ }
147
+
148
+ await this.saveMemoryToFile(memory);
149
+ }
150
+
151
+ /**
152
+ * 获取所有记忆
153
+ */
154
+ getAllMemories(): Memory[] {
155
+ return Array.from(this.memories.values());
156
+ }
157
+
158
+ /**
159
+ * 获取记忆统计
160
+ */
161
+ getStats(): MemoryStats {
162
+ const memories = this.getAllMemories();
163
+
164
+ const byCategory: Record<string, number> = {};
165
+ const byImportance: Record<string, number> = {};
166
+ let totalUsage = 0;
167
+
168
+ for (const m of memories) {
169
+ byCategory[m.category] = (byCategory[m.category] || 0) + 1;
170
+ byImportance[m.importance] = (byImportance[m.importance] || 0) + 1;
171
+ totalUsage += m.usageCount;
172
+ }
173
+
174
+ return {
175
+ total: memories.length,
176
+ byCategory,
177
+ byImportance,
178
+ averageUsage: memories.length > 0 ? totalUsage / memories.length : 0
179
+ };
180
+ }
181
+
182
+ /**
183
+ * 按类别获取记忆
184
+ */
185
+ getMemoriesByCategory(category: string): Memory[] {
186
+ const ids = this.categoryIndex.get(category);
187
+ if (!ids) return [];
188
+ return Array.from(ids).map(id => this.memories.get(id)).filter(Boolean) as Memory[];
189
+ }
190
+
191
+ /**
192
+ * 获取记忆
193
+ */
194
+ getMemory(id: string): Memory | undefined {
195
+ return this.memories.get(id);
196
+ }
197
+
198
+ /**
199
+ * 删除记忆
200
+ */
201
+ async delete(id: string): Promise<boolean> {
202
+ const memory = this.memories.get(id);
203
+ if (!memory) return false;
204
+
205
+ // 从内存中删除
206
+ this.memories.delete(id);
207
+ this.removeFromCategoryIndex(memory);
208
+
209
+ // 从文件中删除
210
+ const filePath = this.getMemoryFilePath(memory);
211
+ if (fs.existsSync(filePath)) {
212
+ fs.unlinkSync(filePath);
213
+ }
214
+
215
+ return true;
216
+ }
217
+
218
+ /**
219
+ * 加载记忆到内存
220
+ */
221
+ private async loadMemories(): Promise<void> {
222
+ if (!fs.existsSync(this.dataDir)) return;
223
+
224
+ const categories = fs.readdirSync(this.dataDir);
225
+
226
+ for (const category of categories) {
227
+ const categoryPath = path.join(this.dataDir, category);
228
+ if (!fs.statSync(categoryPath).isDirectory()) continue;
229
+
230
+ const subCategories = fs.readdirSync(categoryPath);
231
+
232
+ for (const subCategory of subCategories) {
233
+ const subCategoryPath = path.join(categoryPath, subCategory);
234
+ if (!fs.statSync(subCategoryPath).isDirectory()) continue;
235
+
236
+ const files = fs.readdirSync(subCategoryPath);
237
+
238
+ for (const file of files) {
239
+ if (!file.endsWith('.json') || file === 'index.json') continue;
240
+
241
+ try {
242
+ const content = fs.readFileSync(
243
+ path.join(subCategoryPath, file),
244
+ 'utf-8'
245
+ );
246
+ const memory = JSON.parse(content) as Memory;
247
+ memory.createdAt = new Date(memory.createdAt);
248
+ memory.updatedAt = new Date(memory.updatedAt);
249
+ memory.lastAccessedAt = new Date(memory.lastAccessedAt);
250
+
251
+ this.memories.set(memory.id, memory);
252
+ this.addToCategoryIndex(memory);
253
+ } catch (e) {
254
+ console.error(`加载记忆失败: ${file}`, e);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ /**
262
+ * 保存记忆到文件
263
+ */
264
+ private async saveMemoryToFile(memory: Memory): Promise<void> {
265
+ const dir = path.join(this.dataDir, memory.category, memory.subCategory);
266
+
267
+ if (!fs.existsSync(dir)) {
268
+ fs.mkdirSync(dir, { recursive: true });
269
+ }
270
+
271
+ const filePath = path.join(dir, `${memory.id}.json`);
272
+ await fs.promises.writeFile(filePath, JSON.stringify(memory, null, 2));
273
+ }
274
+
275
+ /**
276
+ * 获取记忆文件路径
277
+ */
278
+ private getMemoryFilePath(memory: Memory): string {
279
+ return path.join(this.dataDir, memory.category, memory.subCategory, `${memory.id}.json`);
280
+ }
281
+
282
+ /**
283
+ * 添加到分类索引
284
+ */
285
+ private addToCategoryIndex(memory: Memory): void {
286
+ if (!this.categoryIndex.has(memory.category)) {
287
+ this.categoryIndex.set(memory.category, new Set());
288
+ }
289
+ this.categoryIndex.get(memory.category)!.add(memory.id);
290
+ }
291
+
292
+ /**
293
+ * 从分类索引中移除
294
+ */
295
+ private removeFromCategoryIndex(memory: Memory): void {
296
+ const set = this.categoryIndex.get(memory.category);
297
+ if (set) {
298
+ set.delete(memory.id);
299
+ if (set.size === 0) {
300
+ this.categoryIndex.delete(memory.category);
301
+ }
302
+ }
303
+ }
304
+ }
package/src/test.ts ADDED
@@ -0,0 +1,116 @@
1
+ /**
2
+ * 简单测试脚本
3
+ * 用于验证核心功能
4
+ */
5
+
6
+ import { MemorySystem } from './memory-system';
7
+ import { defaultMemoryConfig } from './config';
8
+ import { TriggerAnalyzer } from './triggers';
9
+ import { CategoryAnalyzer } from './category';
10
+ import { AutoRecall } from './auto-recall';
11
+ import { AutoCapture } from './auto-capture';
12
+
13
+ async function runTests() {
14
+ console.log('🧪 开始测试...\n');
15
+
16
+ // 测试1: 关键词分析
17
+ console.log('📝 测试1: 关键词分析');
18
+ const trigger = new TriggerAnalyzer();
19
+
20
+ const testCases = [
21
+ { text: '记住我的密码是123456', expected: 'critical' },
22
+ { text: '我决定使用Docker', expected: 'high' },
23
+ { text: '帮我写个Python脚本', expected: 'medium' },
24
+ { text: '谢谢你的帮助', expected: 'low' },
25
+ ];
26
+
27
+ for (const tc of testCases) {
28
+ const result = trigger.analyze(tc.text);
29
+ const pass = result === tc.expected ? '✅' : '❌';
30
+ console.log(` ${pass} "${tc.text}" => ${result} (期望: ${tc.expected})`);
31
+ }
32
+
33
+ // 测试2: 分类分析
34
+ console.log('\n📝 测试2: 分类分析');
35
+ const category = new CategoryAnalyzer();
36
+
37
+ const categoryTests = [
38
+ { text: '帮我写个Python脚本', expected: '代码开发' },
39
+ { text: '配置Docker环境', expected: '系统运维' },
40
+ { text: '帮我写份报告', expected: '文档撰写' },
41
+ { text: '分析销售数据', expected: '数据分析' },
42
+ ];
43
+
44
+ for (const tc of categoryTests) {
45
+ const result = category.analyze(tc.text);
46
+ const pass = result.category === tc.expected ? '✅' : '❌';
47
+ console.log(` ${pass} "${tc.text}" => ${result.category} (期望: ${tc.expected})`);
48
+ }
49
+
50
+ // 测试3: 记忆系统
51
+ console.log('\n📝 测试3: 记忆系统');
52
+ const memorySystem = new MemorySystem('./test-data', defaultMemoryConfig);
53
+ await memorySystem.initialize();
54
+
55
+ // 存储测试
56
+ const memory1 = await memorySystem.store({
57
+ content: {
58
+ task: '帮我写个Python脚本',
59
+ process: '创建了script.py',
60
+ result: '完成',
61
+ insights: []
62
+ },
63
+ category: '代码开发',
64
+ subCategory: '脚本',
65
+ importance: 'medium'
66
+ });
67
+ console.log(` ✅ 存储记忆: ${memory1.id}`);
68
+
69
+ // 搜索测试
70
+ const searchResults = await memorySystem.search('Python脚本', {
71
+ limit: 3,
72
+ threshold: 0.1
73
+ });
74
+ console.log(` ✅ 搜索结果: 找到 ${searchResults.length} 条`);
75
+
76
+ // 统计测试
77
+ const stats = memorySystem.getStats();
78
+ console.log(` ✅ 统计: ${stats.total} 条记忆`);
79
+
80
+ // 测试4: 自动召回
81
+ console.log('\n📝 测试4: 自动召回');
82
+ const autoRecall = new AutoRecall(memorySystem, defaultMemoryConfig);
83
+ const recallResult = await autoRecall.execute({
84
+ prompt: '之前让我写的脚本在哪?'
85
+ });
86
+ if (recallResult) {
87
+ console.log(` ✅ 自动召回成功`);
88
+ console.log(` ${recallResult.prependContext.slice(0, 100)}...`);
89
+ } else {
90
+ console.log(` ⚠️ 无相关记忆返回`);
91
+ }
92
+
93
+ // 测试5: 自动捕获
94
+ console.log('\n📝 测试5: 自动捕获');
95
+ const autoCapture = new AutoCapture(memorySystem, defaultMemoryConfig);
96
+ await autoCapture.execute({
97
+ messages: [
98
+ { role: 'user', content: '帮我创建一个备份脚本' },
99
+ { role: 'assistant', content: '已创建backup.ps1' }
100
+ ]
101
+ });
102
+
103
+ const stats2 = memorySystem.getStats();
104
+ console.log(` ✅ 自动捕获后: ${stats2.total} 条记忆`);
105
+
106
+ console.log('\n🎉 测试完成!');
107
+
108
+ // 清理测试数据
109
+ const fs = await import('fs');
110
+ if (fs.existsSync('./test-data')) {
111
+ fs.rmSync('./test-data', { recursive: true });
112
+ console.log('🧹 已清理测试数据');
113
+ }
114
+ }
115
+
116
+ runTests().catch(console.error);
@@ -0,0 +1,126 @@
1
+ /**
2
+ * 关键词分析模块
3
+ *
4
+ * 分析文本内容,判断重要性等级,提取标签
5
+ */
6
+
7
+ import type { ImportanceLevel } from './types';
8
+
9
+ export class TriggerAnalyzer {
10
+ // 关键信息 - importance = critical
11
+ private criticalPatterns = [
12
+ // 中文
13
+ /记住|别忘了|提醒我|提醒/i,
14
+ /密码|账号|身份|银行卡|信用卡/i,
15
+ /\+\d{10,}/, // 电话
16
+ /[\w.-]+@[\w.-]+\.\w+/, // 邮箱
17
+ // 英文
18
+ /remember|don't forget|remind me/i,
19
+ /password|account|identity|card/i
20
+ ];
21
+
22
+ // 重要决策 - importance = high
23
+ private highPatterns = [
24
+ // 中文
25
+ /决定|选择|采用|否决|定下来/i,
26
+ /配置|安装|部署|设置/i,
27
+ /偏好|喜欢|讨厌|想要/i,
28
+ // 英文
29
+ /decide|decided|choose|use|adopt/i,
30
+ /config|install|deploy|setup/i,
31
+ /prefer|like|hate|want/i
32
+ ];
33
+
34
+ // 一般工作 - importance = medium
35
+ private mediumPatterns = [
36
+ // 中文
37
+ /实现|修复|创建|帮助|完成|解决了/i,
38
+ /写|做|生成|处理|分析/i,
39
+ /实现|添加|新增|重构|优化/i,
40
+ // 英文
41
+ /implement|fix|create|help|complete|build/i,
42
+ /write|make|generate|process|analyze/i,
43
+ /add|new|refactor|optimize/i
44
+ ];
45
+
46
+ // 低价值 - importance = low
47
+ private lowPatterns = [
48
+ // 中文
49
+ /^你好|^谢谢|^再见|^好的/i,
50
+ /请问|没什么|随便/i,
51
+ // 英文
52
+ /^(hi|hello|thanks|bye|ok|okay)$/i,
53
+ /nothing|just|whatever/i
54
+ ];
55
+
56
+ /**
57
+ * 分析文本,返回重要性等级
58
+ */
59
+ analyze(content: string): ImportanceLevel {
60
+ const lower = content.toLowerCase();
61
+
62
+ if (this.criticalPatterns.some(p => p.test(lower))) {
63
+ return 'critical';
64
+ }
65
+ if (this.highPatterns.some(p => p.test(lower))) {
66
+ return 'high';
67
+ }
68
+ if (this.lowPatterns.some(p => p.test(lower))) {
69
+ return 'low';
70
+ }
71
+ if (this.mediumPatterns.some(p => p.test(lower))) {
72
+ return 'medium';
73
+ }
74
+
75
+ // 默认中等
76
+ return 'medium';
77
+ }
78
+
79
+ /**
80
+ * 提取标签
81
+ */
82
+ extractTags(content: string): string[] {
83
+ const tags: string[] = [];
84
+ const lower = content.toLowerCase();
85
+
86
+ // 标签映射
87
+ const tagPatterns: Record<string, RegExp[]> = {
88
+ // 技术相关
89
+ '代码': [/代码|编程|函数|脚本/i, /code|program|script/i],
90
+ '配置': [/配置|设置|安装/i, /config|setup|install/i],
91
+ '数据': [/数据|分析|统计/i, /data|analysis|stat/i],
92
+ '文档': [/文档|报告|文章/i, /doc|report|article/i],
93
+ '决策': [/决定|选择|采用/i, /decide|choose|adopt/i],
94
+ '问题': [/错误|bug|问题|故障/i, /error|bug|issue|problem/i],
95
+ '完成': [/完成|解决了|实现了/i, /done|completed|implemented/i],
96
+ '创建': [/创建|新建/i, /create|new/i],
97
+ // 偏好相关
98
+ '偏好': [/喜欢|偏好|讨厌|想要/i, /prefer|like|hate|want/i],
99
+ // 个人信息
100
+ '记住': [/记住|别忘了/i, /remember|don't forget/i],
101
+ '重要': [/重要|关键|永远|永不/i, /important|critical|always|never/i]
102
+ };
103
+
104
+ for (const [tag, patterns] of Object.entries(tagPatterns)) {
105
+ if (patterns.some(p => p.test(lower))) {
106
+ tags.push(tag);
107
+ }
108
+ }
109
+
110
+ return tags;
111
+ }
112
+
113
+ /**
114
+ * 检测是否包含关键信息
115
+ */
116
+ hasCriticalInfo(content: string): boolean {
117
+ return this.analyze(content) === 'critical';
118
+ }
119
+
120
+ /**
121
+ * 检测是否低价值内容
122
+ */
123
+ isLowValue(content: string): boolean {
124
+ return this.analyze(content) === 'low';
125
+ }
126
+ }