@scotthuang/engram 0.6.8 → 0.7.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.
package/README.md CHANGED
@@ -1,6 +1,83 @@
1
- # Engram
1
+ # Engram - 分层语义记忆系统
2
2
 
3
- 分层语义记忆系统 - OpenClaw Plugin
3
+ OpenClaw Plugin for hierarchical semantic memory.
4
+
5
+ ## 🚀 快速启动
6
+
7
+ ### 一键启动所有服务
8
+
9
+ ```bash
10
+ # 首次运行会自动创建虚拟环境并安装依赖
11
+ ./start.sh
12
+ ```
13
+
14
+ 启动后访问:
15
+ - 前端:http://localhost:3210
16
+ - 后端:http://localhost:8765
17
+
18
+ ### 停止服务
19
+
20
+ ```bash
21
+ ./stop.sh
22
+ ```
23
+
24
+ ### 查看日志
25
+
26
+ ```bash
27
+ # 实时查看后端日志
28
+ tail -f .logs/backend.log
29
+
30
+ # 实时查看前端日志
31
+ tail -f .logs/frontend.log
32
+ ```
33
+
34
+ ## 📁 项目结构
35
+
36
+ - `face/` - 人脸和声纹识别模块
37
+ - `service/` - 后端服务 (FastAPI + Python)
38
+ - `web/` - 前端界面 (React + Vite)
39
+ - `src/` - 核心记忆系统代码
40
+ - `scripts/` - 工具脚本
41
+
42
+ ## 🔧 手动启动(可选)
43
+
44
+ 如果需要单独启动前端或后端:
45
+
46
+ ```bash
47
+ # 仅启动后端
48
+ cd face/service
49
+ ./start.sh
50
+
51
+ # 仅启动前端
52
+ cd face/web
53
+ ./start.sh
54
+ ```
55
+
56
+ ## 📋 环境要求
57
+
58
+ - Node.js (推荐 LTS 版本)
59
+ - Python 3.12
60
+ - macOS / Linux
61
+
62
+ ## 📦 功能模块
63
+
64
+ ### 人脸识别
65
+ - 注册人脸
66
+ - 识别照片中的人脸
67
+ - Gallery 展示和测试
68
+
69
+ ### 声纹识别
70
+ - 注册声纹
71
+ - 识别语音中的说话人
72
+ - Gallery 语音测试
73
+
74
+ ### 记忆系统
75
+ - 短期记忆
76
+ - 长期记忆
77
+ - 语义检索
78
+ - 自动浓缩
79
+
80
+ ---
4
81
 
5
82
  ## 方案文档
6
83
 
@@ -23,7 +23,6 @@ describe("ProfileManager", () => {
23
23
  await fs.mkdir(profileDir, { recursive: true });
24
24
  const saved = { ...EMPTY_PROFILE, summary: "test summary", coreTags: ["tag1"] };
25
25
  await fs.writeFile(join(profileDir, "semantic_profile.json"), JSON.stringify(saved));
26
- // 创建新的 manager 实例测试从文件加载
27
26
  const manager2 = new ProfileManager(tempDir);
28
27
  const loaded = await manager2.load();
29
28
  expect(loaded.summary).toBe("test summary");
@@ -31,22 +30,37 @@ describe("ProfileManager", () => {
31
30
  });
32
31
  });
33
32
  describe("addTag", () => {
34
- it("adds a new tag to a new dimension", async () => {
33
+ it("adds a new tag with default layer (interest)", async () => {
35
34
  const profile = { ...EMPTY_PROFILE };
36
35
  const result = manager.addTag(profile, "口味偏好", "喜欢辣");
37
36
  expect(result.tags["口味偏好"]).toHaveLength(1);
38
37
  expect(result.tags["口味偏好"][0].value).toBe("喜欢辣");
39
38
  expect(result.tags["口味偏好"][0].confidence).toBe(0.7);
39
+ expect(result.tags["口味偏好"][0].layer).toBe("interest");
40
+ });
41
+ it("adds identity tag with high confidence", async () => {
42
+ const profile = { ...EMPTY_PROFILE };
43
+ manager.addTag(profile, "居住地", "广州天河", "identity");
44
+ expect(profile.tags["居住地"][0].confidence).toBe(0.95);
45
+ expect(profile.tags["居住地"][0].layer).toBe("identity");
40
46
  });
41
47
  it("increases confidence for existing tag", async () => {
42
48
  const profile = {
43
49
  ...EMPTY_PROFILE,
44
- tags: { 口味偏好: [{ value: "喜欢辣", confidence: 0.5, lastSeen: "2026-01-01" }] },
50
+ tags: { 口味偏好: [{ value: "喜欢辣", confidence: 0.5, lastSeen: "2026-01-01", layer: "pattern" }] },
45
51
  };
46
52
  const result = manager.addTag(profile, "口味偏好", "喜欢辣");
47
53
  expect(result.tags["口味偏好"]).toHaveLength(1);
48
54
  expect(result.tags["口味偏好"][0].confidence).toBeCloseTo(0.6);
49
55
  });
56
+ it("promotes tag layer when higher layer is specified", () => {
57
+ const profile = {
58
+ ...EMPTY_PROFILE,
59
+ tags: { 居住地: [{ value: "广州", confidence: 0.7, lastSeen: "2026-01-01", layer: "interest" }] },
60
+ };
61
+ manager.addTag(profile, "居住地", "广州", "identity");
62
+ expect(profile.tags["居住地"][0].layer).toBe("identity");
63
+ });
50
64
  it("adds multiple tags to same dimension", async () => {
51
65
  const profile = { ...EMPTY_PROFILE };
52
66
  manager.addTag(profile, "口味偏好", "喜欢辣");
@@ -55,37 +69,72 @@ describe("ProfileManager", () => {
55
69
  });
56
70
  });
57
71
  describe("decayTags", () => {
58
- it("reduces confidence of all tags", () => {
72
+ it("does not decay identity tags", () => {
73
+ const profile = {
74
+ ...EMPTY_PROFILE,
75
+ tags: {
76
+ 身份: [{ value: "Scott", confidence: 0.95, lastSeen: "2026-03-17", layer: "identity" }],
77
+ },
78
+ };
79
+ manager.decayTags(profile);
80
+ expect(profile.tags["身份"][0].confidence).toBeCloseTo(0.95);
81
+ });
82
+ it("slowly decays pattern tags", () => {
59
83
  const profile = {
60
84
  ...EMPTY_PROFILE,
61
85
  tags: {
62
- 口味偏好: [
63
- { value: "喜欢辣", confidence: 0.9, lastSeen: "2026-03-17" },
64
- ],
86
+ 习惯: [{ value: "晚睡", confidence: 0.9, lastSeen: "2026-03-17", layer: "pattern" }],
65
87
  },
66
88
  };
67
- const result = manager.decayTags(profile, 0.5);
68
- expect(result.tags["口味偏好"][0].confidence).toBeCloseTo(0.45);
89
+ manager.decayTags(profile);
90
+ expect(profile.tags["习惯"][0].confidence).toBeCloseTo(0.9 * 0.995);
69
91
  });
70
- it("removes tags below threshold", () => {
92
+ it("quickly decays interest tags", () => {
71
93
  const profile = {
72
94
  ...EMPTY_PROFILE,
73
95
  tags: {
74
- 过时: [{ value: "旧标签", confidence: 0.15, lastSeen: "2026-01-01" }],
96
+ 项目: [{ value: "声纹识别", confidence: 0.7, lastSeen: "2026-03-17", layer: "interest" }],
75
97
  },
76
98
  };
77
- const result = manager.decayTags(profile, 1.0);
78
- expect(result.tags["过时"]).toBeUndefined();
99
+ manager.decayTags(profile);
100
+ expect(profile.tags["项目"][0].confidence).toBeCloseTo(0.7 * 0.95);
79
101
  });
80
- it("removes empty dimensions after filtering", () => {
102
+ it("removes tags below their layer threshold", () => {
81
103
  const profile = {
82
104
  ...EMPTY_PROFILE,
83
105
  tags: {
84
- 空维度: [{ value: "很低", confidence: 0.1, lastSeen: "2026-01-01" }],
106
+ 过时: [{ value: "旧兴趣", confidence: 0.15, lastSeen: "2026-01-01", layer: "interest" }],
85
107
  },
86
108
  };
87
- const result = manager.decayTags(profile, 1.0);
88
- expect("空维度" in result.tags).toBe(false);
109
+ manager.decayTags(profile);
110
+ expect(profile.tags["过时"]).toBeUndefined();
111
+ });
112
+ it("treats tags without layer as interest (backward compat)", () => {
113
+ const profile = {
114
+ ...EMPTY_PROFILE,
115
+ tags: {
116
+ 旧数据: [{ value: "旧标签", confidence: 0.9, lastSeen: "2026-03-17" }],
117
+ },
118
+ };
119
+ manager.decayTags(profile);
120
+ // 旧数据没有 layer → 视为 interest → factor=0.95
121
+ expect(profile.tags["旧数据"][0].confidence).toBeCloseTo(0.9 * 0.95);
122
+ });
123
+ });
124
+ describe("generateCoreTags", () => {
125
+ it("prioritizes identity over pattern over interest", () => {
126
+ const profile = {
127
+ ...EMPTY_PROFILE,
128
+ tags: {
129
+ 兴趣: [{ value: "声纹项目", confidence: 0.9, layer: "interest" }],
130
+ 身份: [{ value: "广州天河", confidence: 0.8, layer: "identity" }],
131
+ 习惯: [{ value: "晚睡", confidence: 0.85, layer: "pattern" }],
132
+ },
133
+ };
134
+ const tags = manager.generateCoreTags(profile);
135
+ expect(tags[0]).toBe("广州天河"); // identity 优先
136
+ expect(tags[1]).toBe("晚睡"); // pattern 次之
137
+ expect(tags[2]).toBe("声纹项目"); // interest 最后
89
138
  });
90
139
  });
91
140
  describe("getRecallContext", () => {
@@ -100,11 +149,6 @@ describe("ProfileManager", () => {
100
149
  expect(ctx).toContain("辣味中餐");
101
150
  expect(ctx).toContain("天河");
102
151
  });
103
- it("works with only core tags", () => {
104
- const profile = { ...EMPTY_PROFILE, summary: "", coreTags: ["标签1"] };
105
- const ctx = manager.getRecallContext(profile);
106
- expect(ctx).toContain("标签1");
107
- });
108
152
  });
109
153
  describe("save", () => {
110
154
  it("saves profile to file", async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"profile.test.js","sourceRoot":"","sources":["../../../src/__tests__/profile.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"profile.test.js","sourceRoot":"","sources":["../../../src/__tests__/profile.test.ts"],"names":[],"mappings":"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"}
package/dist/src/index.js CHANGED
@@ -423,36 +423,47 @@ export default function register(api) {
423
423
  api.registerTool({
424
424
  name: "memory_system_profile",
425
425
  label: "User Profile",
426
- description: "查看或更新用户语义画像。",
426
+ description: "查看或更新用户语义画像(三层:identity 核心身份 / pattern 行为模式 / interest 动态兴趣)。",
427
427
  parameters: {
428
428
  type: "object",
429
429
  properties: {
430
430
  action: { type: "string", enum: ["get", "update"], description: "操作类型" },
431
431
  dimension: { type: "string", description: "标签维度(update 时使用)" },
432
432
  value: { type: "string", description: "标签值(update 时使用)" },
433
+ layer: { type: "string", enum: ["identity", "pattern", "interest"], description: "标签层级(update 时使用,默认 interest)" },
433
434
  },
434
435
  required: ["action"],
435
436
  },
436
437
  async execute(_toolCallId, params) {
437
- const { action, dimension, value } = params;
438
+ const { action, dimension, value, layer } = params;
438
439
  const profile = await profileManager.load();
439
440
  if (action === "get") {
440
441
  const context = profileManager.getRecallContext(profile);
441
- const fullTags = Object.entries(profile.tags)
442
- .map(([dim, tags]) => `- **${dim}**: ${tags.map(t => `${t.value}(${(t.confidence * 100).toFixed(0)}%)`).join(", ")}`)
443
- .join("\n");
442
+ // 按层分组展示
443
+ const layerLabels = { identity: "🏠 核心身份", pattern: "📊 行为模式", interest: "🎯 动态兴趣" };
444
+ const layerGroups = { identity: [], pattern: [], interest: [] };
445
+ for (const [dim, tags] of Object.entries(profile.tags)) {
446
+ for (const t of tags) {
447
+ const l = t.layer || "interest";
448
+ layerGroups[l].push(`${t.value}(${(t.confidence * 100).toFixed(0)}%) [${dim}]`);
449
+ }
450
+ }
451
+ const fullTags = Object.entries(layerGroups)
452
+ .filter(([, tags]) => tags.length > 0)
453
+ .map(([l, tags]) => `### ${layerLabels[l]}\n${tags.map(t => `- ${t}`).join("\n")}`)
454
+ .join("\n\n");
444
455
  return {
445
456
  content: [{
446
457
  type: "text",
447
- text: `${context}\n\n## 完整画像\n${fullTags || "(暂无标签)"}`,
458
+ text: `${context}\n\n${fullTags || "(暂无标签)"}`,
448
459
  }],
449
460
  };
450
461
  }
451
462
  if (action === "update" && dimension && value) {
452
- profileManager.addTag(profile, dimension, value);
463
+ profileManager.addTag(profile, dimension, value, layer || "interest");
453
464
  await profileManager.save(profile);
454
465
  return {
455
- content: [{ type: "text", text: `Added tag: [${dimension}] ${value}` }],
466
+ content: [{ type: "text", text: `Added tag: [${dimension}] ${value} (layer=${layer || "interest"})` }],
456
467
  };
457
468
  }
458
469
  return { content: [{ type: "text", text: "Invalid action or missing params." }] };
@@ -1357,6 +1368,63 @@ export default function register(api) {
1357
1368
  // Rebuild BM25 index after adding new entry
1358
1369
  await recallEngine.rebuildBM25();
1359
1370
  logger.info(`[engram] [async] BM25 index rebuilt after new entry added`);
1371
+ // ---- 实时 interest 更新:从对话中快速抽取动态兴趣标签 ----
1372
+ if (config.condense.apiKey && config.condense.baseUrl) {
1373
+ try {
1374
+ const interestSystemPrompt = `从以下对话中提取用户当前关注的话题/项目/兴趣,输出 JSON 数组。
1375
+ 每条格式:{"dimension": "分类", "value": "标签"}
1376
+ 只提取动态兴趣(当前在做的事、近期关注的话题),不要提取身份信息或长期习惯。
1377
+ 最多 3 条,宁缺毋滥。如果没有有价值的兴趣标签,输出空数组 []。
1378
+ 只输出 JSON。`;
1379
+ // 截取前 1500 字符避免 token 浪费
1380
+ const snippet = contentToSave.slice(0, 1500);
1381
+ const interestApiKey = config.condense.apiKey || "";
1382
+ const interestBaseUrl = config.condense.baseUrl || "";
1383
+ const interestModel = config.condense.model || config.settleModel || "MiniMax-M2.7-highspeed";
1384
+ // 直接用底层 LLM 调用
1385
+ const controller = new AbortController();
1386
+ const timeoutId = setTimeout(() => controller.abort(), 15_000);
1387
+ const response = await fetch(`${interestBaseUrl}/v1/messages`, {
1388
+ method: "POST",
1389
+ headers: {
1390
+ "Content-Type": "application/json",
1391
+ "x-api-key": interestApiKey,
1392
+ "anthropic-version": "2023-06-01",
1393
+ },
1394
+ body: JSON.stringify({
1395
+ model: interestModel,
1396
+ system: interestSystemPrompt,
1397
+ messages: [{ role: "user", content: snippet }],
1398
+ max_tokens: 512,
1399
+ temperature: 0.3,
1400
+ }),
1401
+ signal: controller.signal,
1402
+ });
1403
+ clearTimeout(timeoutId);
1404
+ if (response.ok) {
1405
+ const data = await response.json();
1406
+ const textBlock = data.content?.find((b) => b.type === "text");
1407
+ const interestResult = textBlock?.text?.trim() || "";
1408
+ if (interestResult) {
1409
+ const cleaned = interestResult.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?\s*```\s*$/, "");
1410
+ const interests = JSON.parse(cleaned);
1411
+ if (Array.isArray(interests) && interests.length > 0) {
1412
+ const profile = await profileManager.reload();
1413
+ for (const tag of interests) {
1414
+ if (tag.dimension && tag.value) {
1415
+ profileManager.addTag(profile, tag.dimension, tag.value, "interest");
1416
+ }
1417
+ }
1418
+ await profileManager.save(profile);
1419
+ logger.info(`[engram] [async] Updated ${interests.length} interest tags from conversation`);
1420
+ }
1421
+ }
1422
+ }
1423
+ }
1424
+ catch (interestErr) {
1425
+ logger.error(`[engram] [async] Interest update failed (non-critical): ${interestErr}`);
1426
+ }
1427
+ }
1360
1428
  }
1361
1429
  catch (asyncErr) {
1362
1430
  logger.error(`[engram] [async] Background processing failed: ${asyncErr}`);